diff --git a/AIMSICD/TikTok-SIM-Privacy.md b/AIMSICD/TikTok-SIM-Privacy.md
new file mode 100644
index 000000000..82b5ad5eb
--- /dev/null
+++ b/AIMSICD/TikTok-SIM-Privacy.md
@@ -0,0 +1,45 @@
+## TikTok SIM/Telephony Privacy (Non‑root)
+
+This guide explains practical steps to prevent apps (e.g., TikTok) from learning SIM/phone identifiers on Android devices without root.
+
+### 1) Deny phone/SIM permissions
+- Settings → Apps → TikTok → Permissions → Phone → Deny. Also deny SMS/Call log if present.
+- Force stop TikTok, then Clear storage.
+
+### 2) Stronger enforcement with ADB (no root)
+```bash
+# Replace PKG with the exact package of TikTok (e.g., com.zhiliaoapp.musically or com.ss.android.ugc.trill)
+PKG=com.zhiliaoapp.musically
+
+# Revoke telephony-related dangerous permissions
+adb shell pm revoke $PKG android.permission.READ_PHONE_STATE
+adb shell pm revoke $PKG android.permission.READ_PHONE_NUMBERS
+adb shell pm revoke $PKG android.permission.READ_SMS
+adb shell pm revoke $PKG android.permission.READ_CALL_LOG
+
+# Clamp app-ops (Android 10+)
+adb shell cmd appops set $PKG READ_DEVICE_IDENTIFIERS ignore
+adb shell cmd appops set $PKG READ_PHONE_STATE ignore
+adb shell cmd appops set $PKG READ_PHONE_NUMBERS ignore
+adb shell cmd appops set $PKG READ_SMS ignore
+adb shell cmd appops set $PKG READ_CALL_LOG ignore
+
+# Reset the app
+adb shell am force-stop $PKG
+adb shell pm clear $PKG
+```
+
+### 3) Use a secondary Android user without telephony
+- Settings → System → Multiple users → Add user.
+- Do not enable “Phone calls & SMS for this user.”
+- Switch, install TikTok, use Wi‑Fi.
+
+### 4) Temporarily disable the SIM subscription
+- Settings → Network & Internet → SIMs → toggle OFF the problematic SIM.
+- Keep Wi‑Fi ON. Force stop + Clear storage for TikTok before testing.
+
+### Notes
+- Intercepting app traffic is not feasible non‑root due to TLS pinning.
+- Use the new “Privacy Advisor” (App → Menu → Privacy Advisor) to see which installed apps request telephony permissions and copy ready‑made ADB commands.
+
+
diff --git a/AIMSICD/src/main/AndroidManifest.xml b/AIMSICD/src/main/AndroidManifest.xml
index 983b980d2..91d27ad02 100644
--- a/AIMSICD/src/main/AndroidManifest.xml
+++ b/AIMSICD/src/main/AndroidManifest.xml
@@ -104,6 +104,16 @@
+
+
+
+
+
+
adapter;
+ private final List items = new ArrayList<>();
+
+ private static final Set TELEPHONY_PERMS = new HashSet<>(Arrays.asList(
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_PHONE_NUMBERS,
+ android.Manifest.permission.READ_SMS,
+ android.Manifest.permission.READ_CALL_LOG
+ ));
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_privacy_advisor);
+
+ listView = (ListView) findViewById(R.id.privacy_list);
+ progressBar = (ProgressBar) findViewById(R.id.privacy_progress);
+ emptyView = (TextView) findViewById(R.id.privacy_empty);
+
+ adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_2, android.R.id.text1, items) {
+ @Override
+ public View getView(int position, View convertView, android.view.ViewGroup parent) {
+ View v = super.getView(position, convertView, parent);
+ TextView t1 = (TextView) v.findViewById(android.R.id.text1);
+ TextView t2 = (TextView) v.findViewById(android.R.id.text2);
+ AppPerms ap = getItem(position);
+ if (ap != null) {
+ t1.setText(ap.label + " (" + ap.packageName + ")");
+ t2.setText(getString(R.string.privacy_perms_count, ap.relevantGrantedCount, ap.relevantRequestedCount));
+ }
+ return v;
+ }
+ };
+ listView.setAdapter(adapter);
+ listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> parent, View view, int position, long id) {
+ AppPerms ap = adapter.getItem(position);
+ if (ap != null) {
+ showDetailsDialog(ap);
+ }
+ }
+ });
+
+ loadData();
+ }
+
+ private void loadData() {
+ progressBar.setVisibility(View.VISIBLE);
+ emptyView.setVisibility(View.GONE);
+ listView.setVisibility(View.GONE);
+
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ final List result = scanInstalled();
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ items.clear();
+ items.addAll(result);
+ adapter.notifyDataSetChanged();
+
+ progressBar.setVisibility(View.GONE);
+ if (items.isEmpty()) {
+ emptyView.setVisibility(View.VISIBLE);
+ listView.setVisibility(View.GONE);
+ } else {
+ listView.setVisibility(View.VISIBLE);
+ emptyView.setVisibility(View.GONE);
+ }
+ }
+ });
+ }
+ }).start();
+ }
+
+ private List scanInstalled() {
+ PackageManager pm = getPackageManager();
+ List pkgs = pm.getInstalledPackages(PackageManager.GET_PERMISSIONS);
+ List result = new ArrayList<>();
+
+ for (PackageInfo pi : pkgs) {
+ if (pi.requestedPermissions == null || pi.requestedPermissions.length == 0) {
+ continue;
+ }
+ List requested = new ArrayList<>();
+ List granted = new ArrayList<>();
+
+ for (int i = 0; i < pi.requestedPermissions.length; i++) {
+ String perm = pi.requestedPermissions[i];
+ if (!TELEPHONY_PERMS.contains(perm)) continue;
+
+ requested.add(perm);
+ boolean isGranted = false;
+ if (pi.requestedPermissionsFlags != null && pi.requestedPermissionsFlags.length > i) {
+ isGranted = (pi.requestedPermissionsFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;
+ } else {
+ isGranted = pm.checkPermission(perm, pi.packageName) == PackageManager.PERMISSION_GRANTED;
+ }
+ if (isGranted) {
+ granted.add(perm);
+ }
+ }
+
+ if (!requested.isEmpty()) {
+ CharSequence label;
+ try {
+ label = pm.getApplicationLabel(pm.getApplicationInfo(pi.packageName, 0));
+ } catch (PackageManager.NameNotFoundException e) {
+ label = pi.packageName;
+ }
+ result.add(new AppPerms(pi.packageName, label.toString(), requested, granted));
+ }
+ }
+
+ Collections.sort(result, new Comparator() {
+ @Override
+ public int compare(AppPerms o1, AppPerms o2) {
+ // Sort by granted count desc, then label
+ int g = Integer.valueOf(o2.relevantGrantedCount).compareTo(o1.relevantGrantedCount);
+ if (g != 0) return g;
+ return o1.label.compareToIgnoreCase(o2.label);
+ }
+ });
+
+ return result;
+ }
+
+ private void showDetailsDialog(final AppPerms ap) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getString(R.string.privacy_dialog_pkg)).append(" ").append(ap.packageName).append("\n\n");
+ if (!ap.relevantRequested.isEmpty()) {
+ sb.append(getString(R.string.privacy_dialog_requested)).append("\n");
+ for (String rp : ap.relevantRequested) {
+ sb.append("• ").append(humanizePermission(rp));
+ if (ap.relevantGranted.contains(rp)) {
+ sb.append(" ").append(getString(R.string.privacy_dialog_granted));
+ } else {
+ sb.append(" ").append(getString(R.string.privacy_dialog_denied));
+ }
+ sb.append("\n");
+ }
+ }
+
+ final String adb = buildAdbCommands(ap.packageName, ap.relevantRequested);
+
+ new AlertDialog.Builder(this)
+ .setTitle(getString(R.string.privacy_dialog_title, ap.label))
+ .setMessage(sb.toString())
+ .setPositiveButton(R.string.privacy_copy_cmds, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ copyToClipboard(adb);
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null)
+ .show();
+ }
+
+ private String humanizePermission(String perm) {
+ if (android.Manifest.permission.READ_PHONE_STATE.equals(perm)) return getString(R.string.perm_read_phone_state);
+ if (android.Manifest.permission.READ_PHONE_NUMBERS.equals(perm)) return getString(R.string.perm_read_phone_numbers);
+ if (android.Manifest.permission.READ_SMS.equals(perm)) return getString(R.string.perm_read_sms);
+ if (android.Manifest.permission.READ_CALL_LOG.equals(perm)) return getString(R.string.perm_read_call_log);
+ return perm;
+ }
+
+ private void copyToClipboard(String text) {
+ ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
+ if (cm != null) {
+ cm.setPrimaryClip(ClipData.newPlainText("adb", text));
+ }
+ }
+
+ private String buildAdbCommands(String pkg, List perms) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("# Replace PKG if needed\n");
+ sb.append("PKG=").append(pkg).append("\n\n");
+ for (String p : perms) {
+ sb.append("adb shell pm revoke $PKG ").append(p).append("\n");
+ }
+ // App-ops clamps
+ sb.append("\n# App-ops clamps (Android 10+)\n");
+ sb.append("adb shell cmd appops set $PKG READ_DEVICE_IDENTIFIERS ignore\n");
+ sb.append("adb shell cmd appops set $PKG READ_PHONE_STATE ignore\n");
+ sb.append("adb shell cmd appops set $PKG READ_PHONE_NUMBERS ignore\n");
+ sb.append("adb shell cmd appops set $PKG READ_SMS ignore\n");
+ sb.append("adb shell cmd appops set $PKG READ_CALL_LOG ignore\n");
+ sb.append("\n# Reset app\n");
+ sb.append("adb shell am force-stop $PKG\n");
+ sb.append("adb shell pm clear $PKG\n");
+ return sb.toString();
+ }
+
+ @AllArgsConstructor
+ @ToString
+ private static class AppPerms {
+ @Getter
+ final String packageName;
+ @Getter
+ final String label;
+ @Getter
+ final List relevantRequested;
+ @Getter
+ final List relevantGranted;
+
+ final int relevantRequestedCount() { return relevantRequested == null ? 0 : relevantRequested.size(); }
+ final int relevantGrantedCount() { return relevantGranted == null ? 0 : relevantGranted.size(); }
+ }
+}
+
+
diff --git a/AIMSICD/src/main/res/layout/activity_privacy_advisor.xml b/AIMSICD/src/main/res/layout/activity_privacy_advisor.xml
new file mode 100644
index 000000000..1fad2bddf
--- /dev/null
+++ b/AIMSICD/src/main/res/layout/activity_privacy_advisor.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AIMSICD/src/main/res/menu/main_menu.xml b/AIMSICD/src/main/res/menu/main_menu.xml
index ee63df847..1770d88f7 100644
--- a/AIMSICD/src/main/res/menu/main_menu.xml
+++ b/AIMSICD/src/main/res/menu/main_menu.xml
@@ -31,4 +31,9 @@
android:icon="@drawable/ic_action_computer"
android:title="@string/debugging"
app:showAsAction="never" />
-
\ No newline at end of file
+
+
diff --git a/AIMSICD/src/main/res/values/strings.xml b/AIMSICD/src/main/res/values/strings.xml
index 5ecd90551..c7bbe5784 100644
--- a/AIMSICD/src/main/res/values/strings.xml
+++ b/AIMSICD/src/main/res/values/strings.xml
@@ -1,4 +1,18 @@
Antenna Map Viewer
-
\ No newline at end of file
+ Privacy Advisor
+ Apps requesting phone/SIM permissions (tap for details)
+ No installed apps request telephony-related permissions.
+ %1$d granted of %2$d requested
+ %1$s
+ Package:
+ Requested telephony permissions:
+ (granted)
+ (denied)
+ Copy ADB commands
+ Read phone state
+ Read phone numbers
+ Read SMS
+ Read call log
+