diff --git a/.Jules/palette.md b/.Jules/palette.md new file mode 100644 index 0000000..5996203 --- /dev/null +++ b/.Jules/palette.md @@ -0,0 +1,3 @@ +## 2025-05-14 - [Visual Feedback for Native Operations] +**Learning:** In debug/sample apps performing native operations (like hooking), silent execution leads to user uncertainty. Immediate visual feedback via Toasts and button state changes significantly improves the developer experience by confirming action success. +**Action:** For buttons triggering library loading or native states, disable the button and update its text (e.g., 'lib... loaded') immediately upon success to provide 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..4cc232a 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,41 +52,55 @@ protected void onCreate(Bundle savedInstanceState) { public void onUnitTestHookSymAddrClick(View view) { NativeHandler.nativeHookSymAddr(Build.VERSION.SDK_INT); + Toast.makeText(this, R.string.toast_hook_sym_addr, Toast.LENGTH_SHORT).show(); } public void onUnitTestHookSymNameClick(View view) { NativeHandler.nativeHookSymName(Build.VERSION.SDK_INT); + Toast.makeText(this, R.string.toast_hook_sym_name, Toast.LENGTH_SHORT).show(); } public void onUnitTestUnhookClick(View view) { NativeHandler.nativeUnhook(); + Toast.makeText(this, R.string.toast_unhooked, Toast.LENGTH_SHORT).show(); } public void onUnitTestLoadClick(View view) { if(!hookee2Loaded) { hookee2Loaded = true; System.loadLibrary("hookee2"); + if (view instanceof Button) { + Button button = (Button) view; + button.setEnabled(false); + button.setText(R.string.btn_lib_loaded); + } + Toast.makeText(this, R.string.toast_lib_loaded, Toast.LENGTH_SHORT).show(); } } public void onUnitTestRunClick(View view) { NativeHandler.nativeRun(hookee2Loaded); + Toast.makeText(this, R.string.toast_running_unit_test, Toast.LENGTH_SHORT).show(); } public void onSystemTestHookClick(View view) { SysTest.hook(); + Toast.makeText(this, R.string.toast_system_hook, Toast.LENGTH_SHORT).show(); } public void onSystemTestUnhookClick(View view) { SysTest.unhook(); + Toast.makeText(this, R.string.toast_system_unhook, Toast.LENGTH_SHORT).show(); } public void onSystemTestRunClick(View view) { SysTest.run(); + Toast.makeText(this, R.string.toast_running_system_test, Toast.LENGTH_SHORT).show(); } public void onGetRecordsClick(View view) { String records = ShadowHook.getRecords(); + Toast.makeText(this, R.string.toast_records_logcat, Toast.LENGTH_SHORT).show(); // String records = ShadowHook.getRecords(ShadowHook.RecordItem.CALLER_LIB_NAME, ShadowHook.RecordItem.OP, ShadowHook.RecordItem.LIB_NAME, ShadowHook.RecordItem.SYM_NAME, ShadowHook.RecordItem.ERRNO, ShadowHook.RecordItem.STUB); if (records != null) { for (String line : records.split("\n")) { @@ -96,6 +112,7 @@ public void onGetRecordsClick(View view) { public void onDumpRecordsClick(View view) { String pathname = getApplicationContext().getFilesDir() + "/shadowhook_records.txt"; NativeHandler.nativeDumpRecords(pathname); + Toast.makeText(this, R.string.toast_records_dumped, Toast.LENGTH_SHORT).show(); BufferedReader br = null; try { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e3b1ca3..e2d4f03 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,14 @@ shadowhook + Hook by symbol address... + Hook by symbol name... + Unhooked + libhookee2.so loaded + libhookee2.so loaded + Running unit test... + System hook... + System unhook... + Running system test... + Records sent to logcat + Records dumped to file and logcat \ No newline at end of file