Skip to content

Commit

Permalink
Merge pull request #40 from MrApplejuice/debug-menu-item
Browse files Browse the repository at this point in the history
Add debug allowing to debug server <-> client communication in production builds
  • Loading branch information
MrApplejuice authored Jul 29, 2023
2 parents f65a905 + d56db0e commit 293e8cd
Show file tree
Hide file tree
Showing 9 changed files with 177 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import androidx.viewpager2.widget.ViewPager2;
import eu.pkgsoftware.babybuddywidgets.databinding.BabyManagerBinding;
import eu.pkgsoftware.babybuddywidgets.databinding.LoggedInFragmentBinding;
import eu.pkgsoftware.babybuddywidgets.debugging.GlobalDebugObject;
import eu.pkgsoftware.babybuddywidgets.networking.BabyBuddyClient;
import eu.pkgsoftware.babybuddywidgets.networking.ChildrenStateTracker;

Expand Down Expand Up @@ -154,6 +155,7 @@ public void onPageSelected(int position) {
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.loggedin_menu, menu);
menu.findItem(R.id.exportDebugLogsMenuItem).setVisible(GlobalDebugObject.getENABLED());
}

private void logout() {
Expand All @@ -172,6 +174,9 @@ public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.aboutPageMenuItem) {
Navigation.findNavController(getView()).navigate(R.id.global_aboutFragment);
}
if (item.getItemId() == R.id.exportDebugLogsMenuItem) {
Navigation.findNavController(getView()).navigate(R.id.action_global_debugLogDisplay);
}
return false;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package eu.pkgsoftware.babybuddywidgets.debugging

import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import eu.pkgsoftware.babybuddywidgets.BaseFragment
import eu.pkgsoftware.babybuddywidgets.R
import eu.pkgsoftware.babybuddywidgets.databinding.FragmentDebugLogDisplayBinding

class DebugLogDisplay : BaseFragment() {
lateinit var fragment: FragmentDebugLogDisplayBinding

override fun onResume() {
super.onResume()

val stringBuilder = StringBuilder(16000)
for (line in GlobalDebugObject.getLog()) {
stringBuilder.append(line.trim())
stringBuilder.append("\n<EOL>\n")
}
fragment.debugTextArea.setText(stringBuilder)

mainActivity.setTitle(getString(R.string.export_debug_logs_title))
}

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
fragment = FragmentDebugLogDisplayBinding.inflate(inflater)

fragment.copyToClipboardButton.setOnClickListener {
val clipboard = requireActivity().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
clipboard.setPrimaryClip(ClipData.newPlainText(
"BabyBuddy Debug Data", fragment.debugTextArea.text
))

Toast.makeText(context, "Copied to clipboard", Toast.LENGTH_SHORT).show()
}

return fragment.root
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package eu.pkgsoftware.babybuddywidgets.debugging

import android.util.Log

class GlobalDebugObject {
companion object {
@JvmStatic
val ENABLED = true
@JvmStatic
val DO_PRINT = true
@JvmStatic
val LOG_FILE_MESSAGE_LIMIT = 10000

val LOCK = Object()

private val log = mutableListOf<String>()

@JvmStatic
fun log(msg: String) {
if (!ENABLED) return
synchronized(LOCK) {
while (log.size > LOG_FILE_MESSAGE_LIMIT) {
log.removeAt(0)
}
if (DO_PRINT) {
Log.println(Log.DEBUG, "GlobalDebugObject.log", msg)
}
log.add(msg)
}
}

@JvmStatic
fun getLog(): List<String> {
if (!ENABLED) return listOf()
val result = synchronized(LOCK) {
log.toList()
}
return result
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,16 @@
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.TimeZone;
import java.util.Timer;

import androidx.annotation.NonNull;
import eu.pkgsoftware.babybuddywidgets.Constants;
import eu.pkgsoftware.babybuddywidgets.CredStore;
import eu.pkgsoftware.babybuddywidgets.debugging.GlobalDebugObject;

public class BabyBuddyClient extends StreamReader {
public final boolean DEBUG = false;

public static final String DATE_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ssX";
public static final String DATE_QUERY_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ss";

Expand Down Expand Up @@ -495,12 +495,18 @@ public interface RequestCallback<R> {

private void updateServerDateTime(HttpURLConnection con) {
String dateString = con.getHeaderField("Date");
if (dateString == null) {
GlobalDebugObject.log("updateServerDateTime(): Date header not found");
return; // Chicken out, no dateString found, let's hope everything works!
}
try {
Date serverTime = SERVER_DATE_FORMAT.parse(dateString);
Date now = new Date(System.currentTimeMillis());

serverDateOffset = serverTime.getTime() - now.getTime() - 100; // 100 ms offset
GlobalDebugObject.log("updateServerDateTime(): Adjusted serverDateOffset to " + serverDateOffset);
} catch (ParseException e) {
GlobalDebugObject.log("updateServerDateTime(): Date header parse error; " + e);
}
}

Expand Down Expand Up @@ -541,20 +547,21 @@ public BabyBuddyClient(Looper mainLoop, CredStore credStore) {
this.syncMessage = new Handler(mainLoop);
}

private final Random requestIdGenerator = new Random();
private synchronized int newRequestId() {
return Math.abs(requestIdGenerator.nextInt()) % 10000;
}

private void dispatchQuery(String method, String path, String payload, RequestCallback<String> callback) {
final int REQUEST_ID = newRequestId();
final String QUERY_STR = "Query " + REQUEST_ID;

Thread thread = new Thread() {
@Override
public void run() {
try {
HttpURLConnection query = doQuery(path);
if (DEBUG) {
System.out.println(
"BabyBuddyClient.DEBUG "
+ method
+ " path: " + path
+ " payload: " + payload
);
}
GlobalDebugObject.log(QUERY_STR + ": " + method + " to " + path + "; payload = " + payload);

query.setRequestMethod(method);
if (payload != null) {
Expand All @@ -570,27 +577,26 @@ public void run() {
updateServerDateTime(query);

int responseCode = query.getResponseCode();
if (DEBUG) {
System.out.println(" -> response code: " + responseCode);
}
if ((responseCode < 200) || (responseCode >= 300)) {
String message = query.getResponseMessage();
throw new RequestCodeFailure(
responseCode,
message,
loadHttpData(query.getErrorStream())
String messageText = loadHttpData(query.getErrorStream());
GlobalDebugObject.log(
QUERY_STR + " response error: " + responseCode + "; messageText = " + messageText
);
throw new RequestCodeFailure(responseCode, message, messageText);
}


String result = loadHttpData(query);
final String result = loadHttpData(query);
GlobalDebugObject.log(QUERY_STR + " succeeded: response = " + result);
syncMessage.post(new Runnable() {
@Override
public void run() {
callback.response(result);
}
});
} catch (Exception e) {
GlobalDebugObject.log(QUERY_STR + ": Exception occurred; " + e);
syncMessage.post(() -> callback.error(e));
}
}
Expand Down
44 changes: 44 additions & 0 deletions app/src/main/res/layout/fragment_debug_log_display.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".debugging.DebugLogDisplay">

<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toTopOf="@+id/copyToClipboardButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

<EditText
android:id="@+id/debugTextArea"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:enabled="false"
android:fontFamily="monospace"
android:gravity="start|top"
android:inputType="textMultiLine"
android:textAlignment="viewStart"
android:textColor="#000000"
android:textIsSelectable="true"
android:textSize="12sp" />
</ScrollView>

<Button
android:id="@+id/copyToClipboardButton"
android:layout_width="match_parent"
android:layout_height="54dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:text="@string/export_debug_logs_menu_item_copy_to_clipboard"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
3 changes: 3 additions & 0 deletions app/src/main/res/menu/loggedin_menu.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@
<item
android:id="@+id/aboutPageMenuItem"
android:title="@string/about_page_title" />
<item
android:id="@+id/exportDebugLogsMenuItem"
android:title="@string/export_debug_logs_menu_item" />
</menu>
5 changes: 5 additions & 0 deletions app/src/main/res/navigation/nav_graph.xml
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,9 @@
app:argType="boolean"
android:defaultValue="false" />
</fragment>
<fragment
android:id="@+id/debugLogDisplay"
android:name="eu.pkgsoftware.babybuddywidgets.debugging.DebugLogDisplay"
android:label="fragment_debug_log_display"
tools:layout="@layout/fragment_debug_log_display" /><action android:id="@+id/action_global_debugLogDisplay" app:destination="@id/debugLogDisplay"/>
</navigation>
7 changes: 5 additions & 2 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,6 @@
</string>
<string name="history_delete_question_delete_button">Delete</string>
<string name="history_delete_question_cancel_button">Cancel</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>

<!-- QR Code Login -->
<string name="login_qrcode_camera_access_needed_dialog_title">Camera access needed</string>
Expand Down Expand Up @@ -136,4 +134,9 @@
Only the timers that are supported by the app are shown now. Timer controls and manual timer
associations of timers with activities were removed.
</string>

<!-- Debugging -->
<string name="export_debug_logs_title">Export Debug Logs</string>
<string name="export_debug_logs_menu_item">Export Debug Logs</string>
<string name="export_debug_logs_menu_item_copy_to_clipboard">Copy to clipboard</string>
</resources>
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.0.2'
classpath 'com.android.tools.build:gradle:8.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

// NOTE: Do not place your application dependencies here; they belong
Expand Down

0 comments on commit 293e8cd

Please sign in to comment.