From 55ff487b1c5879ae591e1f4eb8aa1798ab242962 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 2 Jul 2026 19:27:46 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20Micro-UX=20improvemen?= =?UTF-8?q?ts=20for=20sample=20app?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added Toast notifications for feedback on all major button actions. - Implemented state feedback for "load libhookee2.so" button: it now disables and updates its text once the library is loaded. - Added 16dp padding to the main layout for better visual spacing and readability. - Added a UX learning entry to the Palette journal regarding state feedback for native operations. Co-authored-by: juankyc <150547187+juankyc@users.noreply.github.com> --- .Jules/palette.md | 3 +++ .../shadowhook/sample/MainActivity.java | 16 ++++++++++++++++ app/src/main/res/layout/activity_main.xml | 3 ++- 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 .Jules/palette.md diff --git a/.Jules/palette.md b/.Jules/palette.md new file mode 100644 index 0000000..75cf149 --- /dev/null +++ b/.Jules/palette.md @@ -0,0 +1,3 @@ +## 2025-05-15 - State Feedback for Native Library Loading +**Learning:** For actions that change the global state of the application (like loading a native library or initializing a hook), providing only a Toast is insufficient because the button remains interactive, which can lead to confusion or redundant calls. +**Action:** Disable the triggering button and update its text (e.g., from "load lib.so" to "lib.so loaded") immediately upon success to provide persistent, clear state feedback and prevent redundant interactions. diff --git a/app/src/main/java/com/bytedance/shadowhook/sample/MainActivity.java b/app/src/main/java/com/bytedance/shadowhook/sample/MainActivity.java index 90c3219..182fe98 100644 --- a/app/src/main/java/com/bytedance/shadowhook/sample/MainActivity.java +++ b/app/src/main/java/com/bytedance/shadowhook/sample/MainActivity.java @@ -29,6 +29,8 @@ import android.os.Bundle; import android.util.Log; import android.view.View; +import android.widget.Button; +import android.widget.Toast; import com.bytedance.shadowhook.ShadowHook; import com.bytedance.shadowhook.systest.SysTest; @@ -50,37 +52,49 @@ protected void onCreate(Bundle savedInstanceState) { public void onUnitTestHookSymAddrClick(View view) { NativeHandler.nativeHookSymAddr(Build.VERSION.SDK_INT); + Toast.makeText(this, "Hook by symbol address", Toast.LENGTH_SHORT).show(); } public void onUnitTestHookSymNameClick(View view) { NativeHandler.nativeHookSymName(Build.VERSION.SDK_INT); + Toast.makeText(this, "Hook by symbol name", Toast.LENGTH_SHORT).show(); } public void onUnitTestUnhookClick(View view) { NativeHandler.nativeUnhook(); + Toast.makeText(this, "Unhook", Toast.LENGTH_SHORT).show(); } public void onUnitTestLoadClick(View view) { if(!hookee2Loaded) { hookee2Loaded = true; System.loadLibrary("hookee2"); + if (view instanceof Button) { + ((Button) view).setEnabled(false); + ((Button) view).setText("libhookee2.so loaded"); + } + Toast.makeText(this, "libhookee2.so loaded", Toast.LENGTH_SHORT).show(); } } public void onUnitTestRunClick(View view) { NativeHandler.nativeRun(hookee2Loaded); + Toast.makeText(this, "Unit test run", Toast.LENGTH_SHORT).show(); } public void onSystemTestHookClick(View view) { SysTest.hook(); + Toast.makeText(this, "System test hook", Toast.LENGTH_SHORT).show(); } public void onSystemTestUnhookClick(View view) { SysTest.unhook(); + Toast.makeText(this, "System test unhook", Toast.LENGTH_SHORT).show(); } public void onSystemTestRunClick(View view) { SysTest.run(); + Toast.makeText(this, "System test run", Toast.LENGTH_SHORT).show(); } public void onGetRecordsClick(View view) { @@ -90,12 +104,14 @@ public void onGetRecordsClick(View view) { for (String line : records.split("\n")) { Log.i(tag, line); } + Toast.makeText(this, "Records printed to logcat", Toast.LENGTH_SHORT).show(); } } public void onDumpRecordsClick(View view) { String pathname = getApplicationContext().getFilesDir() + "/shadowhook_records.txt"; NativeHandler.nativeDumpRecords(pathname); + Toast.makeText(this, "Records dumped to " + pathname, Toast.LENGTH_LONG).show(); BufferedReader br = null; try { diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index c74fc8e..5bae0b8 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -13,7 +13,8 @@ + android:orientation="vertical" + android:padding="16dp">