package com.xdandroid.sample.misc;

import android.app.*;
import android.content.pm.*;
import android.os.*;
import android.text.*;

import java.lang.reflect.*;
import java.util.*;

/**
 * uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS"
 * android:theme="@android:style/Theme.NoDisplay"
 */
public class RevokeActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        new Thread(() -> {
            try {
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return;
                PackageManager pm = getPackageManager();
                Class<AppOpsManager> aomClass = AppOpsManager.class;
                AppOpsManager aom = getSystemService(aomClass);
                Method setUidModeMethod = aomClass.getMethod("setUidMode", String.class, int.class, int.class);
                Method setModeMethod = aomClass.getMethod("setMode", int.class, int.class, String.class, int.class);
                pm.getInstalledPackages(PackageManager.GET_PERMISSIONS)
                  .stream()
                  .filter(i -> (i.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0)
                  .filter(i -> (i.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0)
                  .forEach(i -> {
                      int uid = i.applicationInfo.uid;
                      int targetSdkVersion = i.applicationInfo.targetSdkVersion;
                      String n = i.applicationInfo.packageName;
                      if (targetSdkVersion < Build.VERSION_CODES.M && i.requestedPermissions != null) {
                          Arrays.stream(i.requestedPermissions)
                                .map(p -> {
                                    try { return pm.getPermissionInfo(p, 0); } catch (Exception e) { return null; }
                                })
                                .filter(Objects::nonNull)
                                .filter(pi -> pi.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS)
                                .map(pi -> pi.name)
                                .filter(pn -> pn.startsWith("android"))
                                .filter(pn -> !"android.permission.READ_EXTERNAL_STORAGE".equals(pn))
                                .filter(pn -> !"android.permission.WRITE_EXTERNAL_STORAGE".equals(pn))
                                .map(AppOpsManager::permissionToOp)
                                .filter(op -> !TextUtils.isEmpty(op))
                                .forEach(op -> {
                                    try { setUidModeMethod.invoke(aom, op, uid, AppOpsManager.MODE_IGNORED); } catch (Exception e) { e.printStackTrace(); }
                                });
                      }
                      if (targetSdkVersion < Build.VERSION_CODES.M) {
                          try { setModeMethod.invoke(aom, 24, uid, n, AppOpsManager.MODE_IGNORED); } catch (Exception e) { e.printStackTrace(); }
                          try { setModeMethod.invoke(aom, 23, uid, n, AppOpsManager.MODE_IGNORED); } catch (Exception e) { e.printStackTrace(); }
                      }
                      if (targetSdkVersion < Build.VERSION_CODES.O) {
                          try { setModeMethod.invoke(aom, 63, uid, n, AppOpsManager.MODE_IGNORED); } catch (Exception e) { e.printStackTrace(); }
                      }
                  });
            } catch (Exception e) { e.printStackTrace(); }
        }).start();
        finish();
    }
}

@@ -1421,27 +1421,15 @@
     
-int targetSdkVersio
+String 
 n = 
@@ -1446,32 +1446,27 @@
 ionInfo.
-targetSdkVersion
+packageName
 ;%0A      
@@ -1485,49 +1485,127 @@
     
-S
 tr
-ing n = i.applicationInfo.packageName;
+y %7B setModeMethod.invoke(aom, 63, uid, n, AppOpsManager.MODE_IGNORED); %7D catch (Exception e) %7B e.printStackTrace(); %7D
 %0A   
@@ -1619,32 +1619,50 @@
             if (
+i.applicationInfo.
 targetSdkVersion
@@ -2857,102 +2857,8 @@
 %7D);%0A
-                      %7D%0A                      if (targetSdkVersion %3C Build.VERSION_CODES.M) %7B%0A
     
@@ -3173,248 +3173,8 @@
   %7D%0A
-                      if (targetSdkVersion %3C Build.VERSION_CODES.O) %7B%0A                          try %7B setModeMethod.invoke(aom, 63, uid, n, AppOpsManager.MODE_IGNORED); %7D catch (Exception e) %7B e.printStackTrace(); %7D%0A                      %7D%0A
     

优化 Revoke 的性能.