public class AppOpsManager {

  public static final int MODE_ALLOWED = 0;


  public static final int MODE_IGNORED = 1;


  public static final int MODE_ERRORED = 2;


  public static final int MODE_DEFAULT = 3;


  public static int strOpToOp(String op) {
    return 0;
  }

  public static String permissionToOp(String s) {
    return null;
  }

  public static int permissionToOpCode(String s) {
    return 0;
  }

  public static int strDebugOpToOp(String op) {
    throw new IllegalArgumentException("Unknown operation string: " + op);
  }

  public static class PackageOps implements Parcelable {

    private final String mPackageName;
    private final int mUid;
    private final List<OpEntry> mEntries;

    public PackageOps(String packageName, int uid, List<OpEntry> entries) {
      mPackageName = packageName;
      mUid = uid;
      mEntries = entries;
    }

    public String getPackageName() {
      return mPackageName;
    }

    public int getUid() {
      return mUid;
    }

    public List<OpEntry> getOps() {
      return mEntries;
    }

    @Override
    public int describeContents() {
      return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
      dest.writeString(mPackageName);
      dest.writeInt(mUid);
      dest.writeInt(mEntries.size());
      for (int i = 0; i < mEntries.size(); i++) {
        mEntries.get(i).writeToParcel(dest, flags);
      }
    }

    PackageOps(Parcel source) {
      mPackageName = source.readString();
      mUid = source.readInt();
      mEntries = new ArrayList<OpEntry>();
      final int N = source.readInt();
      for (int i = 0; i < N; i++) {
        mEntries.add(OpEntry.CREATOR.createFromParcel(source));
      }
    }

    public static final Creator<PackageOps> CREATOR = new Creator<PackageOps>() {
      @Override
      public PackageOps createFromParcel(Parcel source) {
        return new PackageOps(source);
      }

      @Override
      public PackageOps[] newArray(int size) {
        return new PackageOps[size];
      }
    };
  }


  public static class OpEntry implements Parcelable {

    private final int mOp;
    private final int mMode;
    private final long mTime;
    private final long mRejectTime;
    private final int mDuration;
    private final int mProxyUid;
    private final String mProxyPackageName;

    public OpEntry(int op, int mode, long time, long rejectTime, int duration,
        int proxyUid, String proxyPackage) {
      mOp = op;
      mMode = mode;
      mTime = time;
      mRejectTime = rejectTime;
      mDuration = duration;
      mProxyUid = proxyUid;
      mProxyPackageName = proxyPackage;
    }

    public int getOp() {
      return mOp;
    }

    public int getMode() {
      return mMode;
    }

    public long getTime() {
      return mTime;
    }

    public long getRejectTime() {
      return mRejectTime;
    }

    public boolean isRunning() {
      return mDuration == -1;
    }

    public int getDuration() {
      return mDuration == -1 ? (int) (System.currentTimeMillis() - mTime) : mDuration;
    }

    public int getProxyUid() {
      return mProxyUid;
    }

    public String getProxyPackageName() {
      return mProxyPackageName;
    }

    @Override
    public int describeContents() {
      return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
      dest.writeInt(mOp);
      dest.writeInt(mMode);
      dest.writeLong(mTime);
      dest.writeLong(mRejectTime);
      dest.writeInt(mDuration);
      dest.writeInt(mProxyUid);
      dest.writeString(mProxyPackageName);
    }

    OpEntry(Parcel source) {
      mOp = source.readInt();
      mMode = source.readInt();
      mTime = source.readLong();
      mRejectTime = source.readLong();
      mDuration = source.readInt();
      mProxyUid = source.readInt();
      mProxyPackageName = source.readString();
    }

    public static final Creator<OpEntry> CREATOR = new Creator<OpEntry>() {
      @Override
      public OpEntry createFromParcel(Parcel source) {
        return new OpEntry(source);
      }

      @Override
      public OpEntry[] newArray(int size) {
        return new OpEntry[size];
      }
    };
  }
} public class UserInfo {
  public int id;
  public int serialNumber;
  public String name;
  public String iconPath;
  public int flags;


  public boolean isPrimary() {
    return false;
  }

  public boolean isAdmin() {
    return false;
  }

  public boolean isManagedProfile() {
    return false;
  }


  public UserHandle getUserHandle() {
    return null;
  }
} public final class FixCompat {
  /**  No operation specified. */
  public static final int OP_NONE = -1;
  /**  Access to coarse location information. */
  public static final int OP_COARSE_LOCATION = 0;
  /**  Access to fine location information. */
  public static final int OP_FINE_LOCATION = 1;
  /**  Causing GPS to run. */
  public static final int OP_GPS = 2;
  /**  */
  public static final int OP_VIBRATE = 3;
  /**  */
  public static final int OP_READ_CONTACTS = 4;
  /**  */
  public static final int OP_WRITE_CONTACTS = 5;
  /**  */
  public static final int OP_READ_CALL_LOG = 6;
  /**  */
  public static final int OP_WRITE_CALL_LOG = 7;
  /**  */
  public static final int OP_READ_CALENDAR = 8;
  /**  */
  public static final int OP_WRITE_CALENDAR = 9;
  /**  */
  public static final int OP_WIFI_SCAN = 10;
  /**  */
  public static final int OP_POST_NOTIFICATION = 11;
  /**  */
  public static final int OP_NEIGHBORING_CELLS = 12;
  /**  */
  public static final int OP_CALL_PHONE = 13;
  /**  */
  public static final int OP_READ_SMS = 14;
  /**  */
  public static final int OP_WRITE_SMS = 15;
  /**  */
  public static final int OP_RECEIVE_SMS = 16;
  /**  */
  public static final int OP_RECEIVE_EMERGECY_SMS = 17;
  /**  */
  public static final int OP_RECEIVE_MMS = 18;
  /**  */
  public static final int OP_RECEIVE_WAP_PUSH = 19;
  /**  */
  public static final int OP_SEND_SMS = 20;
  /**  */
  public static final int OP_READ_ICC_SMS = 21;
  /**  */
  public static final int OP_WRITE_ICC_SMS = 22;
  /**  */
  public static final int OP_WRITE_SETTINGS = 23;
  /**  Required to draw on top of other apps. */
  public static final int OP_SYSTEM_ALERT_WINDOW = 24;
  /**  */
  public static final int OP_ACCESS_NOTIFICATIONS = 25;
  /**  */
  public static final int OP_CAMERA = 26;
  /**  */
  public static final int OP_RECORD_AUDIO = 27;
  /**  */
  public static final int OP_PLAY_AUDIO = 28;
  /**  */
  public static final int OP_READ_CLIPBOARD = 29;
  /**  */
  public static final int OP_WRITE_CLIPBOARD = 30;
  /**  */
  public static final int OP_TAKE_MEDIA_BUTTONS = 31;
  /**  */
  public static final int OP_TAKE_AUDIO_FOCUS = 32;
  /**  */
  public static final int OP_AUDIO_MASTER_VOLUME = 33;
  /**  */
  public static final int OP_AUDIO_VOICE_VOLUME = 34;
  /**  */
  public static final int OP_AUDIO_RING_VOLUME = 35;
  /**  */
  public static final int OP_AUDIO_MEDIA_VOLUME = 36;
  /**  */
  public static final int OP_AUDIO_ALARM_VOLUME = 37;
  /**  */
  public static final int OP_AUDIO_NOTIFICATION_VOLUME = 38;
  /**  */
  public static final int OP_AUDIO_BLUETOOTH_VOLUME = 39;
  /**  */
  public static final int OP_WAKE_LOCK = 40;
  /**  Continually monitoring location data. */
  public static final int OP_MONITOR_LOCATION = 41;
  /**  Continually monitoring location data with a relatively high power request. */
  public static final int OP_MONITOR_HIGH_POWER_LOCATION = 42;
  /**  Retrieve current usage stats via {@link UsageStatsManager}. */
  public static final int OP_GET_USAGE_STATS = 43;
  /**  */
  public static final int OP_MUTE_MICROPHONE = 44;
  /**  */
  public static final int OP_TOAST_WINDOW = 45;
  /**  Capture the device's display contents and/or audio */
  public static final int OP_PROJECT_MEDIA = 46;
  /**  Activate a VPN connection without user intervention. */
  public static final int OP_ACTIVATE_VPN = 47;
  /**  Access the WallpaperManagerAPI to write wallpapers. */
  public static final int OP_WRITE_WALLPAPER = 48;
  /**  Received the assist structure from an app. */
  public static final int OP_ASSIST_STRUCTURE = 49;
  /**  Received a screenshot from assist. */
  public static final int OP_ASSIST_SCREENSHOT = 50;
  /**  Read the phone state. */
  public static final int OP_READ_PHONE_STATE = 51;
  /**  Add voicemail messages to the voicemail content provider. */
  public static final int OP_ADD_VOICEMAIL = 52;
  /**  Access APIs for SIP calling over VOIP or WiFi. */
  public static final int OP_USE_SIP = 53;
  /**  Intercept outgoing calls. */
  public static final int OP_PROCESS_OUTGOING_CALLS = 54;
  /**  User the fingerprint API. */
  public static final int OP_USE_FINGERPRINT = 55;
  /**  Access to body sensors such as heart rate, etc. */
  public static final int OP_BODY_SENSORS = 56;
  /**  Read previously received cell broadcast messages. */
  public static final int OP_READ_CELL_BROADCASTS = 57;
  /**  Inject mock location into the system. */
  public static final int OP_MOCK_LOCATION = 58;
  /**  Read external storage. */
  public static final int OP_READ_EXTERNAL_STORAGE = 59;
  /**  Write external storage. */
  public static final int OP_WRITE_EXTERNAL_STORAGE = 60;
  /**  Turned on the screen. */
  public static final int OP_TURN_SCREEN_ON = 61;
  /**  Get device accounts. */
  public static final int OP_GET_ACCOUNTS = 62;
  /**  Control whether an application is allowed to run in the background. */
  public static final int OP_RUN_IN_BACKGROUND = 63;
  /**  */
  public static final int OP_AUDIO_ACCESSIBILITY_VOLUME = 64;
  /**  Read the phone number. */
  public static final int OP_READ_PHONE_NUMBERS = 65;
  /**  Request package installs through package installer */
  public static final int OP_REQUEST_INSTALL_PACKAGES = 66;
  /**  Enter picture-in-picture. */
  public static final int OP_PICTURE_IN_PICTURE = 67;
  /**  Instant app start foreground service. */
  public static final int OP_INSTANT_APP_START_FOREGROUND = 68;
  /**  Answer incoming phone calls */
  public static final int OP_ANSWER_PHONE_CALLS = 69;
  /**  Run jobs when in background */
  public static final int OP_RUN_ANY_IN_BACKGROUND = 70;
  /**  Change Wi-Fi connectivity state */
  public static final int OP_CHANGE_WIFI_STATE = 71;
  /**  Request package deletion through package installer */
  public static final int OP_REQUEST_DELETE_PACKAGES = 72;
  /**  Bind an accessibility service. */
  public static final int OP_BIND_ACCESSIBILITY_SERVICE = 73;
  /**  Continue handover of a call from another app */
  public static final int OP_ACCEPT_HANDOVER = 74;
  /**  Create and Manage IPsec Tunnels */
  public static final int OP_MANAGE_IPSEC_TUNNELS = 75;
  /**  Any app start foreground service. */
  public static final int OP_START_FOREGROUND = 76;
  /**  */
  public static final int OP_BLUETOOTH_SCAN = 77;
  /**  */
  public static final int _NUM_OP = 78;

  private static final int _NUM_UID_STATE = 6;

  private static int[] _sOpToSwitch = new int[] {
      OP_COARSE_LOCATION,                 // COARSE_LOCATION
      OP_COARSE_LOCATION,                 // FINE_LOCATION
      OP_COARSE_LOCATION,                 // GPS
      OP_VIBRATE,                         // VIBRATE
      OP_READ_CONTACTS,                   // READ_CONTACTS
      OP_WRITE_CONTACTS,                  // WRITE_CONTACTS
      OP_READ_CALL_LOG,                   // READ_CALL_LOG
      OP_WRITE_CALL_LOG,                  // WRITE_CALL_LOG
      OP_READ_CALENDAR,                   // READ_CALENDAR
      OP_WRITE_CALENDAR,                  // WRITE_CALENDAR
      OP_COARSE_LOCATION,                 // WIFI_SCAN
      OP_POST_NOTIFICATION,               // POST_NOTIFICATION
      OP_COARSE_LOCATION,                 // NEIGHBORING_CELLS
      OP_CALL_PHONE,                      // CALL_PHONE
      OP_READ_SMS,                        // READ_SMS
      OP_WRITE_SMS,                       // WRITE_SMS
      OP_RECEIVE_SMS,                     // RECEIVE_SMS
      OP_RECEIVE_SMS,                     // RECEIVE_EMERGECY_SMS
      OP_RECEIVE_MMS,                     // RECEIVE_MMS
      OP_RECEIVE_WAP_PUSH,                // RECEIVE_WAP_PUSH
      OP_SEND_SMS,                        // SEND_SMS
      OP_READ_SMS,                        // READ_ICC_SMS
      OP_WRITE_SMS,                       // WRITE_ICC_SMS
      OP_WRITE_SETTINGS,                  // WRITE_SETTINGS
      OP_SYSTEM_ALERT_WINDOW,             // SYSTEM_ALERT_WINDOW
      OP_ACCESS_NOTIFICATIONS,            // ACCESS_NOTIFICATIONS
      OP_CAMERA,                          // CAMERA
      OP_RECORD_AUDIO,                    // RECORD_AUDIO
      OP_PLAY_AUDIO,                      // PLAY_AUDIO
      OP_READ_CLIPBOARD,                  // READ_CLIPBOARD
      OP_WRITE_CLIPBOARD,                 // WRITE_CLIPBOARD
      OP_TAKE_MEDIA_BUTTONS,              // TAKE_MEDIA_BUTTONS
      OP_TAKE_AUDIO_FOCUS,                // TAKE_AUDIO_FOCUS
      OP_AUDIO_MASTER_VOLUME,             // AUDIO_MASTER_VOLUME
      OP_AUDIO_VOICE_VOLUME,              // AUDIO_VOICE_VOLUME
      OP_AUDIO_RING_VOLUME,               // AUDIO_RING_VOLUME
      OP_AUDIO_MEDIA_VOLUME,              // AUDIO_MEDIA_VOLUME
      OP_AUDIO_ALARM_VOLUME,              // AUDIO_ALARM_VOLUME
      OP_AUDIO_NOTIFICATION_VOLUME,       // AUDIO_NOTIFICATION_VOLUME
      OP_AUDIO_BLUETOOTH_VOLUME,          // AUDIO_BLUETOOTH_VOLUME
      OP_WAKE_LOCK,                       // WAKE_LOCK
      OP_COARSE_LOCATION,                 // MONITOR_LOCATION
      OP_COARSE_LOCATION,                 // MONITOR_HIGH_POWER_LOCATION
      OP_GET_USAGE_STATS,                 // GET_USAGE_STATS
      OP_MUTE_MICROPHONE,                 // MUTE_MICROPHONE
      OP_TOAST_WINDOW,                    // TOAST_WINDOW
      OP_PROJECT_MEDIA,                   // PROJECT_MEDIA
      OP_ACTIVATE_VPN,                    // ACTIVATE_VPN
      OP_WRITE_WALLPAPER,                 // WRITE_WALLPAPER
      OP_ASSIST_STRUCTURE,                // ASSIST_STRUCTURE
      OP_ASSIST_SCREENSHOT,               // ASSIST_SCREENSHOT
      OP_READ_PHONE_STATE,                // READ_PHONE_STATE
      OP_ADD_VOICEMAIL,                   // ADD_VOICEMAIL
      OP_USE_SIP,                         // USE_SIP
      OP_PROCESS_OUTGOING_CALLS,          // PROCESS_OUTGOING_CALLS
      OP_USE_FINGERPRINT,                 // USE_FINGERPRINT
      OP_BODY_SENSORS,                    // BODY_SENSORS
      OP_READ_CELL_BROADCASTS,            // READ_CELL_BROADCASTS
      OP_MOCK_LOCATION,                   // MOCK_LOCATION
      OP_READ_EXTERNAL_STORAGE,           // READ_EXTERNAL_STORAGE
      OP_WRITE_EXTERNAL_STORAGE,          // WRITE_EXTERNAL_STORAGE
      OP_TURN_SCREEN_ON,                  // TURN_SCREEN_ON
      OP_GET_ACCOUNTS,                    // GET_ACCOUNTS
      OP_RUN_IN_BACKGROUND,               // RUN_IN_BACKGROUND
      OP_AUDIO_ACCESSIBILITY_VOLUME,      // AUDIO_ACCESSIBILITY_VOLUME
      OP_READ_PHONE_NUMBERS,              // READ_PHONE_NUMBERS
      OP_REQUEST_INSTALL_PACKAGES,        // REQUEST_INSTALL_PACKAGES
      OP_PICTURE_IN_PICTURE,              // ENTER_PICTURE_IN_PICTURE_ON_HIDE
      OP_INSTANT_APP_START_FOREGROUND,    // INSTANT_APP_START_FOREGROUND
      OP_ANSWER_PHONE_CALLS,              // ANSWER_PHONE_CALLS
      OP_RUN_ANY_IN_BACKGROUND,           // OP_RUN_ANY_IN_BACKGROUND
      OP_CHANGE_WIFI_STATE,               // OP_CHANGE_WIFI_STATE
      OP_REQUEST_DELETE_PACKAGES,         // OP_REQUEST_DELETE_PACKAGES
      OP_BIND_ACCESSIBILITY_SERVICE,      // OP_BIND_ACCESSIBILITY_SERVICE
      OP_ACCEPT_HANDOVER,                 // ACCEPT_HANDOVER
      OP_MANAGE_IPSEC_TUNNELS,            // MANAGE_IPSEC_HANDOVERS
      OP_START_FOREGROUND,                // START_FOREGROUND
      OP_COARSE_LOCATION,                 // BLUETOOTH_SCAN
  };


  private static String[] _sOpNames = new String[] {
      "COARSE_LOCATION",
      "FINE_LOCATION",
      "GPS",
      "VIBRATE",
      "READ_CONTACTS",
      "WRITE_CONTACTS",
      "READ_CALL_LOG",
      "WRITE_CALL_LOG",
      "READ_CALENDAR",
      "WRITE_CALENDAR",
      "WIFI_SCAN",
      "POST_NOTIFICATION",
      "NEIGHBORING_CELLS",
      "CALL_PHONE",
      "READ_SMS",
      "WRITE_SMS",
      "RECEIVE_SMS",
      "RECEIVE_EMERGECY_SMS",
      "RECEIVE_MMS",
      "RECEIVE_WAP_PUSH",
      "SEND_SMS",
      "READ_ICC_SMS",
      "WRITE_ICC_SMS",
      "WRITE_SETTINGS",
      "SYSTEM_ALERT_WINDOW",
      "ACCESS_NOTIFICATIONS",
      "CAMERA",
      "RECORD_AUDIO",
      "PLAY_AUDIO",
      "READ_CLIPBOARD",
      "WRITE_CLIPBOARD",
      "TAKE_MEDIA_BUTTONS",
      "TAKE_AUDIO_FOCUS",
      "AUDIO_MASTER_VOLUME",
      "AUDIO_VOICE_VOLUME",
      "AUDIO_RING_VOLUME",
      "AUDIO_MEDIA_VOLUME",
      "AUDIO_ALARM_VOLUME",
      "AUDIO_NOTIFICATION_VOLUME",
      "AUDIO_BLUETOOTH_VOLUME",
      "WAKE_LOCK",
      "MONITOR_LOCATION",
      "MONITOR_HIGH_POWER_LOCATION",
      "GET_USAGE_STATS",
      "MUTE_MICROPHONE",
      "TOAST_WINDOW",
      "PROJECT_MEDIA",
      "ACTIVATE_VPN",
      "WRITE_WALLPAPER",
      "ASSIST_STRUCTURE",
      "ASSIST_SCREENSHOT",
      "OP_READ_PHONE_STATE",
      "ADD_VOICEMAIL",
      "USE_SIP",
      "PROCESS_OUTGOING_CALLS",
      "USE_FINGERPRINT",
      "BODY_SENSORS",
      "READ_CELL_BROADCASTS",
      "MOCK_LOCATION",
      "READ_EXTERNAL_STORAGE",
      "WRITE_EXTERNAL_STORAGE",
      "TURN_ON_SCREEN",
      "GET_ACCOUNTS",
      "RUN_IN_BACKGROUND",
      "AUDIO_ACCESSIBILITY_VOLUME",
      "READ_PHONE_NUMBERS",
      "REQUEST_INSTALL_PACKAGES",
      "PICTURE_IN_PICTURE",
      "INSTANT_APP_START_FOREGROUND",
      "ANSWER_PHONE_CALLS",
      "RUN_ANY_IN_BACKGROUND",
      "CHANGE_WIFI_STATE",
      "REQUEST_DELETE_PACKAGES",
      "BIND_ACCESSIBILITY_SERVICE",
      "ACCEPT_HANDOVER",
      "MANAGE_IPSEC_TUNNELS",
      "START_FOREGROUND",
      "BLUETOOTH_SCAN",
  };

  /**
   * This optionally maps a permission to an operation.  If there
   * is no permission associated with an operation, it is null.
   */
  private static String[] _sOpPerms = new String[] {
      android.Manifest.permission.ACCESS_COARSE_LOCATION,
      android.Manifest.permission.ACCESS_FINE_LOCATION,
      null,
      android.Manifest.permission.VIBRATE,
      android.Manifest.permission.READ_CONTACTS,
      android.Manifest.permission.WRITE_CONTACTS,
      android.Manifest.permission.READ_CALL_LOG,
      android.Manifest.permission.WRITE_CALL_LOG,
      android.Manifest.permission.READ_CALENDAR,
      android.Manifest.permission.WRITE_CALENDAR,
      android.Manifest.permission.ACCESS_WIFI_STATE,
      null, // no permission required for notifications
      null, // neighboring cells shares the coarse location perm
      android.Manifest.permission.CALL_PHONE,
      android.Manifest.permission.READ_SMS,
      null, // no permission required for writing sms
      android.Manifest.permission.RECEIVE_SMS,
      "android.permission.RECEIVE_EMERGENCY_BROADCAST",
      android.Manifest.permission.RECEIVE_MMS,
      android.Manifest.permission.RECEIVE_WAP_PUSH,
      android.Manifest.permission.SEND_SMS,
      android.Manifest.permission.READ_SMS,
      null, // no permission required for writing icc sms
      android.Manifest.permission.WRITE_SETTINGS,
      android.Manifest.permission.SYSTEM_ALERT_WINDOW,
      "android.permission.ACCESS_NOTIFICATIONS",
      android.Manifest.permission.CAMERA,
      android.Manifest.permission.RECORD_AUDIO,
      null, // no permission for playing audio
      null, // no permission for reading clipboard
      null, // no permission for writing clipboard
      null, // no permission for taking media buttons
      null, // no permission for taking audio focus
      null, // no permission for changing master volume
      null, // no permission for changing voice volume
      null, // no permission for changing ring volume
      null, // no permission for changing media volume
      null, // no permission for changing alarm volume
      null, // no permission for changing notification volume
      null, // no permission for changing bluetooth volume
      android.Manifest.permission.WAKE_LOCK,
      null, // no permission for generic location monitoring
      null, // no permission for high power location monitoring
      android.Manifest.permission.PACKAGE_USAGE_STATS,
      null, // no permission for muting/unmuting microphone
      null, // no permission for displaying toasts
      null, // no permission for projecting media
      null, // no permission for activating vpn
      null, // no permission for supporting wallpaper
      null, // no permission for receiving assist structure
      null, // no permission for receiving assist screenshot
      Manifest.permission.READ_PHONE_STATE,
      Manifest.permission.ADD_VOICEMAIL,
      Manifest.permission.USE_SIP,
      Manifest.permission.PROCESS_OUTGOING_CALLS,
      Manifest.permission.USE_FINGERPRINT,
      Manifest.permission.BODY_SENSORS,
      "android.permission.READ_CELL_BROADCASTS",
      null,
      Manifest.permission.READ_EXTERNAL_STORAGE,
      Manifest.permission.WRITE_EXTERNAL_STORAGE,
      null, // no permission for turning the screen on
      Manifest.permission.GET_ACCOUNTS,
      null, // no permission for running in background
      null, // no permission for changing accessibility volume
      Manifest.permission.READ_PHONE_NUMBERS,
      Manifest.permission.REQUEST_INSTALL_PACKAGES,
      null, // no permission for entering picture-in-picture on hide
      Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
      Manifest.permission.ANSWER_PHONE_CALLS,
      null, // no permission for OP_RUN_ANY_IN_BACKGROUND
      Manifest.permission.CHANGE_WIFI_STATE,
      Manifest.permission.REQUEST_DELETE_PACKAGES,
      Manifest.permission.BIND_ACCESSIBILITY_SERVICE,
      Manifest.permission.ACCEPT_HANDOVER,
      null, // no permission for OP_MANAGE_IPSEC_TUNNELS
      Manifest.permission.FOREGROUND_SERVICE,
      null, // no permission for OP_BLUETOOTH_SCAN
  };

  private static int[] ref_sOpToSwitch = null;
  private static String[] ref_sOpNames = null;
  private static String[] ref_sOpPerms = null;


  public static int[] sOpToSwitch(){
    if (Build.VERSION.SDK_INT >= 28){
      return _sOpToSwitch;
    }else {
      if (ref_sOpToSwitch == null){
        ref_sOpToSwitch = (int[]) ReflectUtils.getFieldValue(AppOpsManager.class, "sOpToSwitch");
      }
      return ref_sOpToSwitch;
    }
  }

  public static String[] sOpNames(){
    if (Build.VERSION.SDK_INT >= 28){
      return _sOpNames;
    }else {
      if (ref_sOpNames == null){
        ref_sOpNames = (String[]) ReflectUtils.getFieldValue(AppOpsManager.class, "sOpNames");
      }
      return ref_sOpNames;
    }
  }

  public static String[] sOpPerms(){
    if (Build.VERSION.SDK_INT >= 28){
      return _sOpPerms;
    }else {
      if (ref_sOpPerms == null){
        ref_sOpPerms = (String[]) ReflectUtils.getFieldValue(AppOpsManager.class, "sOpPerms");
      }
      return ref_sOpPerms;
    }
  }


} public class OpEntry implements Parcelable {

  private final int mOp;
  private final int mMode;
  private final long[] mTimes;
  private final long[] mRejectTimes;
  private final int mDuration;
  private final int mProxyUid;
  private final boolean mRunning;
  private final String mProxyPackageName;

  /**
   * {@see https://github.com/LineageOS/android_frameworks_base/blob/lineage-16.0/core/java/android/app/AppOpsManager.java}
   */
  private final int mAllowedCount;
  private final int mIgnoredCount;

  // Metrics about an op when its uid is persistent.
  public static final int UID_STATE_PERSISTENT = 0;
  // Metrics about an op when its uid is at the top.
  public static final int UID_STATE_TOP = 1;
  // Metrics about an op when its uid is running a foreground service.
  public static final int UID_STATE_FOREGROUND_SERVICE = 2;
  // Last UID state in which we don't restrict what an op can do.
  public static final int UID_STATE_LAST_NON_RESTRICTED = UID_STATE_FOREGROUND_SERVICE;
  // Metrics about an op when its uid is in the foreground for any other reasons.
  public static final int UID_STATE_FOREGROUND = 3;
  // Metrics about an op when its uid is in the background for any reason.
  public static final int UID_STATE_BACKGROUND = 4;
  // Metrics about an op when its uid is cached.
  public static final int UID_STATE_CACHED = 5;
  // Number of uid states we track.
  public static final int _NUM_UID_STATE = 6;

  public OpEntry(int op, int mode, long time, long rejectTime, int duration,
      int proxyUid, String proxyPackage,int allowedCount,int ignoredCount) {
    mOp = op;
    mMode = mode;
    mTimes = new long[_NUM_UID_STATE];
    mRejectTimes = new long[_NUM_UID_STATE];
    mTimes[0] = time;
    mRejectTimes[0] = rejectTime;
    mDuration = duration;
    mRunning = duration == -1;
    mProxyUid = proxyUid;
    mProxyPackageName = proxyPackage;
    mAllowedCount = allowedCount;
    mIgnoredCount = ignoredCount;
  }

  public OpEntry(int op, int mode, long[] times, long[] rejectTimes, int duration,
                 boolean running, int proxyUid, String proxyPackage,
                 int allowedCount, int ignoredCount) {
    mOp = op;
    mMode = mode;
    mTimes = new long[_NUM_UID_STATE];
    mRejectTimes = new long[_NUM_UID_STATE];
    System.arraycopy(times, 0, mTimes, 0, _NUM_UID_STATE);
    System.arraycopy(rejectTimes, 0, mRejectTimes, 0, _NUM_UID_STATE);
    mDuration = duration;
    mRunning = running;
    mProxyUid = proxyUid;
    mProxyPackageName = proxyPackage;
    mAllowedCount = allowedCount;
    mIgnoredCount = ignoredCount;
  }

  public OpEntry(int op, int mode, long[] times, long[] rejectTimes, int duration,
                 int proxyUid, String proxyPackage, int allowedCount, int ignoredCount) {
    this(op, mode, times, rejectTimes, duration, duration == -1, proxyUid, proxyPackage,
            allowedCount, ignoredCount);
  }

  public OpEntry(int op, int mode, long time, long rejectTime, int duration,
                 int proxyUid, String proxyPackage) {
    this(op, mode, time, rejectTime, duration, proxyUid, proxyPackage,
            0, 0);
  }


  public int getOp() {
    return mOp;
  }

  public int getMode() {
    return mMode;
  }

  public long getTime() {
    return maxTime(mTimes, 0, _NUM_UID_STATE);
  }

  public long getRejectTime() {
    return maxTime(mRejectTimes, 0, _NUM_UID_STATE);
  }

  public boolean isRunning() {
    return mDuration == -1;
  }

  public int getDuration() {
    return mDuration;
  }

  public int getProxyUid() {
    return mProxyUid;
  }

  public String getProxyPackageName() {
    return mProxyPackageName;
  }

  public int getAllowedCount() {
    return mAllowedCount;
  }

  public int getIgnoredCount() {
    return mIgnoredCount;
  }

  @Override
  public String toString() {
    return "OpEntry{" +
        "mOp=" + mOp +
        ", mMode=" + mMode +
        ", mTime=" + Arrays.toString(mTimes) +
        ", mRejectTime=" + Arrays.toString(mRejectTimes) +
        ", mDuration=" + mDuration +
        ", mProxyUid=" + mProxyUid +
        ", mProxyPackageName='" + mProxyPackageName + '\'' +
        '}';
  }

  @Override
  public int describeContents() {
    return 0;
  }

  @Override
  public void writeToParcel(Parcel dest, int flags) {
    dest.writeInt(this.mOp);
    dest.writeInt(this.mMode);
    dest.writeLongArray(this.mTimes);
    dest.writeLongArray(this.mRejectTimes);
    dest.writeInt(this.mDuration);
    dest.writeByte((byte) (this.mRunning ? 1 : 0));
    dest.writeInt(this.mProxyUid);
    dest.writeString(this.mProxyPackageName);
    dest.writeInt(this.mAllowedCount);
    dest.writeInt(this.mIgnoredCount);
  }

  protected OpEntry(Parcel in) {
    this.mOp = in.readInt();
    this.mMode = in.readInt();
    this.mTimes = in.createLongArray();
    this.mRejectTimes = in.createLongArray();
    this.mDuration = in.readInt();
    this.mRunning = in.readByte() != 0;
    this.mProxyUid = in.readInt();
    this.mProxyPackageName = in.readString();
    this.mAllowedCount = in.readInt();
    this.mIgnoredCount = in.readInt();
  }

  public static long maxTime(long[] times, int start, int end) {
    long time = 0;
    for (int i = start; i < end; i++) {
      if (times[i] > time) {
        time = times[i];
      }
    }
    return time;
  }

  public static final Creator<OpEntry> CREATOR = new Creator<OpEntry>() {
    @Override
    public OpEntry createFromParcel(Parcel source) {
      return new OpEntry(source);
    }

    @Override
    public OpEntry[] newArray(int size) {
      return new OpEntry[size];
    }
  };
} public class OpsResult implements Parcelable {

  private Throwable exception;
  private List<PackageOps> list;

  public OpsResult(List<PackageOps> list, Throwable exception) {
    this.exception = exception;
    this.list = list;
  }


  public Throwable getException() {
    return exception;
  }

  public List<PackageOps> getList() {
    return list;
  }

  @Override
  public int describeContents() {
    return 0;
  }

  @Override
  public void writeToParcel(Parcel dest, int flags) {
    dest.writeSerializable(this.exception);
    dest.writeTypedList(this.list);
  }

  protected OpsResult(Parcel in) {
    this.exception = (Exception) in.readSerializable();
    this.list = in.createTypedArrayList(PackageOps.CREATOR);
  }

  public static final Parcelable.Creator<OpsResult> CREATOR = new Parcelable.Creator<OpsResult>() {
    @Override
    public OpsResult createFromParcel(Parcel source) {
      return new OpsResult(source);
    }

    @Override
    public OpsResult[] newArray(int size) {
      return new OpsResult[size];
    }
  };


  @Override
  public String toString() {
    return "OpsResult{" +
        "exception=" + exception +
        ", list=" + list +
        '}';
  }
} public final class OtherOp {

  public static final int OP_ACCESS_PHONE_DATA = 51001;

  public static final int OP_ACCESS_WIFI_NETWORK = 52002;


  public static final String OP_NAME_ACCESS_PHONE_DATA = "ACCESS_PHONE_DATA";
  public static final String OP_NAME_ACCESS_WIFI_NETWORK = "ACCESS_WIFI_NETWORK";

  private static Boolean sSupportCount = null;

  private static Integer s_OP_WIFI_SCAN = null;

  private static final SparseArray<String> mData = new SparseArray<>();
  private static final SparseArray<String> mPerms = new SparseArray<>();

  static {
    mData.put(OP_ACCESS_PHONE_DATA, OP_NAME_ACCESS_PHONE_DATA);
    mData.put(OP_ACCESS_WIFI_NETWORK, OP_NAME_ACCESS_WIFI_NETWORK);

    mPerms.put(OP_ACCESS_PHONE_DATA, Manifest.permission.INTERNET);
    mPerms.put(OP_ACCESS_WIFI_NETWORK, Manifest.permission.INTERNET);
  }

  public static boolean isOtherOp(int op) {
    return op == OP_ACCESS_PHONE_DATA || op == OP_ACCESS_WIFI_NETWORK;
  }

  public static boolean isOtherOp(String opName) {
    return OP_NAME_ACCESS_PHONE_DATA.equals(opName) || OP_NAME_ACCESS_WIFI_NETWORK.equals(opName);
  }


  public static String getOpName(int op) {
    return mData.get(op);
  }

  public static String getOpPermName(int op) {
    return mPerms.get(op);
  }

  public static boolean isSupportCount(){
    if(sSupportCount == null){
      try {
        Class<?> aClass = Class.forName("android.app.AppOpsManager$OpEntry", false,
            ClassLoader.getSystemClassLoader());
        sSupportCount = ReflectUtils.hasField(aClass,"mAllowedCount");
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      }
    }
    return sSupportCount;
  }

  public static int getWifiScanOp() {
    if (s_OP_WIFI_SCAN == null) {
      s_OP_WIFI_SCAN = (Integer) ReflectUtils.getFieldValue(AppOpsManager.class, "OP_WIFI_SCAN");
    }
    return s_OP_WIFI_SCAN != null ? s_OP_WIFI_SCAN : -1;
  }

} public class PackageOps implements Parcelable {

  private final String mPackageName;
  private final int mUid;
  private final List<OpEntry> mEntries;
  private SparseArray<OpEntry> mSparseEntries = null;

  public PackageOps(String packageName, int uid, List<OpEntry> entries) {
    mPackageName = packageName;
    mUid = uid;
    mEntries = entries;
  }

  public String getPackageName() {
    return mPackageName;
  }

  public int getUid() {
    return mUid;
  }

  public List<OpEntry> getOps() {
    return mEntries;
  }

  public boolean hasOp(int op) {
    if (mSparseEntries == null) {
      mSparseEntries = new SparseArray<>();
      if (mEntries != null) {
        for (OpEntry entry : mEntries) {
          mSparseEntries.put(entry.getOp(), entry);
        }
      }
    }
    return mSparseEntries.indexOfKey(op) >= 0;
  }

  @Override
  public String toString() {
    return "PackageOps{" +
        "mPackageName='" + mPackageName + '\'' +
        ", mUid=" + mUid +
        ", mEntries=" + mEntries +
        '}';
  }

  @Override
  public int describeContents() {
    return 0;
  }

  @Override
  public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(this.mPackageName);
    dest.writeInt(this.mUid);
    dest.writeList(this.mEntries);
  }

  protected PackageOps(Parcel in) {
    this.mPackageName = in.readString();
    this.mUid = in.readInt();
    this.mEntries = new ArrayList<OpEntry>();
    in.readList(this.mEntries, OpEntry.class.getClassLoader());
  }

  public static final Parcelable.Creator<PackageOps> CREATOR = new Parcelable.Creator<PackageOps>() {
    @Override
    public PackageOps createFromParcel(Parcel source) {
      return new PackageOps(source);
    }

    @Override
    public PackageOps[] newArray(int size) {
      return new PackageOps[size];
    }
  };
} public class AppInfo implements Parcelable {

  public String appName;
  public String packageName;
  public long time;
  public long installTime;
  public long updateTime;
  public String pinyin;
  public ApplicationInfo applicationInfo;

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }

    AppInfo appInfo = (AppInfo) o;

    return packageName != null ? packageName.equals(appInfo.packageName)
        : appInfo.packageName == null;

  }

  @Override
  public int describeContents() {
    return 0;
  }

  @Override
  public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(this.appName);
    dest.writeString(this.packageName);
  }

  public AppInfo() {
  }

  protected AppInfo(Parcel in) {
    this.appName = in.readString();
    this.packageName = in.readString();
  }

  public static final Parcelable.Creator<AppInfo> CREATOR = new Parcelable.Creator<AppInfo>() {
    @Override
    public AppInfo createFromParcel(Parcel source) {
      return new AppInfo(source);
    }

    @Override
    public AppInfo[] newArray(int size) {
      return new AppInfo[size];
    }
  };


  @Override
  public String toString() {
    return "AppInfo{" +
        "appName='" + appName + '\'' +
        ", packageName='" + packageName + '\'' +
        '}';
  }
} public class AppPermissions {

  public AppInfo appInfo;
  public List<OpEntryInfo> opEntries;

  public boolean hasPermissions() {
    return opEntries != null && !opEntries.isEmpty();
  }

  @Override
  public String toString() {
    return "AppPermissions{" +
        "appInfo=" + appInfo +
        ", opEntries=" + opEntries +
        '}';
  }
} public class OpEntryInfo {

  private static Integer sMaxLength = null;

  public OpEntry opEntry;
  public String opName;
  public String opPermsName;
  public String opPermsLab;
  public String opPermsDesc;
  public int mode;
  public int icon;
  public String groupName;

  public OpEntryInfo(OpEntry opEntry) {
    if (opEntry != null) {
      this.opEntry = opEntry;
      this.mode = opEntry.getMode();
      String[] sOpNames = FixCompat.sOpNames();
      if (sMaxLength == null && sOpNames != null) {
        sMaxLength = sOpNames.length;
      }

      if (opEntry.getOp() < sMaxLength) {
        String[] sOpPerms = FixCompat.sOpPerms();

        if (sOpNames != null) {
          this.opName = sOpNames[opEntry.getOp()];
        }
        if (sOpPerms != null) {
          this.opPermsName = sOpPerms[opEntry.getOp()];
        }



      }
    }
  }

  public boolean isAllowed() {
    return this.mode == AppOpsManager.MODE_ALLOWED;
  }

  public void changeStatus() {
    if (isAllowed()) {
      this.mode = AppOpsManager.MODE_IGNORED;
    } else {
      this.mode = AppOpsManager.MODE_ALLOWED;
    }
  }

  @Override
  public String toString() {
    return "OpEntryInfo{" +
        ", opName='" + opName + '\'' +
        ", opPermsName='" + opPermsName + '\'' +
        ", opPermsLab='" + opPermsLab + '\'' +
        ", mode=" + mode +
        '}';
  }
} public class PermissionChildItem {

  public AppInfo appInfo;
  public OpEntryInfo opEntryInfo;
} public class PermissionGroup {

  public String group;
  public String opName;
  public String opPermsName;
  public String opPermsLab;
  public String opPermsDesc;
  public int grants;
  public int count;
  public int icon;
  public List<PermissionChildItem> apps;

  @Override
  public String toString() {
    return "PermissionGroup{" +
        "opName='" + opName + '\'' +
        ", opPermsName='" + opPermsName + '\'' +
        ", opPermsLab='" + opPermsLab + '\'' +
        ", opPermsDesc='" + opPermsDesc + '\'' +
        ", grants=" + grants +
        ", count=" + count +
        ", apps=" + apps +
        '}';
  }
} public class PreAppInfo {

  private String packageName;
  private String ignoredOps;
  private List<Integer> ops;

  public PreAppInfo(String packageName, String ignoredOps) {
    this.packageName = packageName;
    this.ignoredOps = ignoredOps;
  }

  public PreAppInfo(String packageName) {
    this.packageName = packageName;
  }

  public void setIgnoredOps(String ignoredOps) {
    this.ignoredOps = ignoredOps;
  }

  public String getPackageName() {
    return packageName;
  }

  public String getIgnoredOps() {
    return ignoredOps;
  }

  public List<Integer> getOps() {
    if (ops == null) {
      ops = new ArrayList<>();
      if (!TextUtils.isEmpty(ignoredOps)) {
        String[] split = ignoredOps.split(",");
        for (String s : split) {
          try {
            ops.add(Integer.valueOf(s));
          } catch (NumberFormatException e) {
            e.printStackTrace();
          }
        }
      }
    }
    return ops;
  }


  @Override
  public String toString() {
    return "PreAppInfo{" +
        "packageName='" + packageName + '\'' +
        ", ignoredOps='" + ignoredOps + '\'' +
        '}';
  }
} public class AppPermissionActivity extends BaseActivity implements IPermView {

  private static final String TAG = "AppPermissionActivity";

  public static final String EXTRA_APP = "extra.app";
  public static final String EXTRA_APP_PKGNAME = "pkgName";
  public static final String EXTRA_APP_NAME = "appName";


  private ProgressBar mProgressBar;
  private TextView tvError;
  private PermPresenter mPresenter;
  private AppPermissionAdapter adapter;

  private String pkgName;

  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_opsx);

    Toolbar toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    getSupportActionBar().setDisplayHomeAsUpEnabled(true);


    AppInfo appInfo = handleIntent(getIntent());
    if(appInfo == null){
      finish();
      return;
    }

    if(TextUtils.isEmpty(appInfo.appName)){
      loadAppinfo(appInfo.packageName);
    }else {
      setTitle(appInfo.appName);
    }


    tvError = (TextView) findViewById(R.id.tv_error);
    mProgressBar = (ProgressBar) findViewById(R.id.progressBar);

    RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
    recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
    recyclerView.addItemDecoration(new CommonDivderDecorator(getApplicationContext()));

    adapter = new AppPermissionAdapter();
    recyclerView.setAdapter(adapter);

    adapter.setListener(new AppPermissionAdapter.OnSwitchItemClickListener() {
      @Override
      public void onSwitch(OpEntryInfo info, boolean v) {

        mPresenter.switchMode(info, v);
      }
    });

    pkgName = appInfo.packageName;
    mPresenter = new PermPresenter(this, appInfo, getApplicationContext());
    mPresenter.setUp();
  }


  private AppInfo handleIntent(Intent intent){
    AppInfo appInfo = intent.getParcelableExtra(EXTRA_APP);
    if(appInfo == null){
      //find from extra
      String pkgName = intent.getStringExtra(EXTRA_APP_PKGNAME);
      if(TextUtils.isEmpty(pkgName) && intent.getData() != null){
        pkgName = intent.getData().getQueryParameter("id");
      }
      if(!TextUtils.isEmpty(pkgName)){
        appInfo = new AppInfo();
        appInfo.packageName = pkgName;
      }

    }
    return appInfo;
  }

  private void loadAppinfo(String pkgName){
    Helper.getAppInfo(getApplicationContext(),pkgName)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new SingleObserver<AppInfo>() {
          @Override
          public void onSubscribe(@NonNull Disposable d) {

          }

          @Override
          public void onSuccess(@NonNull AppInfo appInfo) {
            setTitle(appInfo.appName);
          }

          @Override
          public void onError(@NonNull Throwable e) {

          }
        });
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();
    if (mPresenter != null) {
      mPresenter.destory();
    }
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
      case android.R.id.home:
        finish();
        return true;
      case R.id.action_reset:
        mPresenter.reset();
        return true;
      case R.id.action_hide_perm:
        showHidePerms();
        return true;
      case R.id.action_open_all:
        changeAll(AppOpsManager.MODE_ALLOWED);
        break;
      case R.id.action_close_all:
        changeAll(AppOpsManager.MODE_IGNORED);
        break;
      case R.id.action_app_info:
        startAppinfo();
        break;
    }
    return super.onOptionsItemSelected(item);
  }

  @Override
  public boolean onCreateOptionsMenu(final Menu menu) {
    if (!mPresenter.isLoadSuccess()) {
      return false;
    }

    getMenuInflater().inflate(R.menu.app_menu, menu);

    MenuItem menuShowAllPerm = menu.findItem(R.id.action_hide_perm);
    MenuItem menuShowOpDesc = menu.findItem(R.id.action_show_op_perm);
    MenuItem menuShowOpName = menu.findItem(R.id.action_show_op_name);
    MenuItem menuShowPremTime = menu.findItem(R.id.action_show_perm_time);

    final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);

    final Map<MenuItem, String> menus = new HashMap<>();
    menus.put(menuShowAllPerm, "key_show_no_prems");
    menus.put(menuShowOpDesc, "key_show_op_desc");
    menus.put(menuShowOpName, "key_show_op_name");
    menus.put(menuShowPremTime, "key_show_perm_time");

    MenuItem.OnMenuItemClickListener itemClickListener = new MenuItem.OnMenuItemClickListener() {
      @Override
      public boolean onMenuItemClick(MenuItem item) {
        String s = menus.get(item);
        if (s != null) {
          item.setChecked(!item.isChecked());
          sp.edit().putBoolean(s, item.isChecked()).apply();
          ActivityCompat.invalidateOptionsMenu(AppPermissionActivity.this);
          mPresenter.load();
        }
        return true;
      }
    };

    Set<Map.Entry<MenuItem, String>> entries = menus.entrySet();
    for (Map.Entry<MenuItem, String> entry : entries) {
      entry.getKey().setChecked(sp.getBoolean(entry.getValue(), false));
      entry.getKey().setOnMenuItemClickListener(itemClickListener);
    }

    return true;
  }


  private void showHidePerms() {

  }

  private void changeAll(int newMode) {
    final List<OpEntryInfo> datas = adapter.getDatas();
    if (datas != null) {
      for (OpEntryInfo data : datas) {
        data.mode = newMode;
        mPresenter.setMode(data);
        adapter.updateItem(data);
      }
    }
  }


  @Override
  public void showProgress(boolean show) {
    tvError.setVisibility(View.GONE);
    mProgressBar.setVisibility(show ? View.VISIBLE : View.GONE);

    ActivityCompat.invalidateOptionsMenu(AppPermissionActivity.this);
  }

  @Override
  public void showError(CharSequence text) {
    mProgressBar.setVisibility(View.GONE);
    tvError.setVisibility(View.VISIBLE);
    tvError.setText(text);

    ActivityCompat.invalidateOptionsMenu(AppPermissionActivity.this);
  }

  @Override
  public void showPerms(List<OpEntryInfo> opEntryInfos) {
    final SharedPreferences sp = PreferenceManager
        .getDefaultSharedPreferences(getApplicationContext());
    adapter.setShowConfig(sp.getBoolean("key_show_op_desc", false),
        sp.getBoolean("key_show_op_name", false),
        sp.getBoolean("key_show_perm_time", false));
    adapter.setDatas(opEntryInfos);
    adapter.notifyDataSetChanged();

    ActivityCompat.invalidateOptionsMenu(AppPermissionActivity.this);
  }

  @Override
  public void updateItem(OpEntryInfo info) {
    info.mode = info.opEntry.getMode();
    adapter.updateItem(info);

    //Toast.makeText(getApplicationContext(),e.getMessage(),Toast.LENGTH_LONG).show();
  }


  private void startAppinfo(){
    Intent intent=new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
    intent.setData(Uri.fromParts("package",pkgName,null));
    startActivity(intent);
  }
}
import android.Manifest;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.content.pm.UserInfo;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Build;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.SparseArray;
import android.util.SparseIntArray;
import androidx.annotation.RequiresApi;
import androidx.core.text.BidiFormatter;
import androidx.core.util.Pair;
import com.zzzmode.appopsx.BuildConfig;
import com.zzzmode.appopsx.R;
import com.zzzmode.appopsx.common.FixCompat;
import com.zzzmode.appopsx.common.OpEntry;
import com.zzzmode.appopsx.common.OpsResult;
import com.zzzmode.appopsx.common.OtherOp;
import com.zzzmode.appopsx.common.PackageOps;
import com.zzzmode.appopsx.ui.model.AppInfo;
import com.zzzmode.appopsx.ui.model.AppPermissions;
import com.zzzmode.appopsx.ui.model.OpEntryInfo;
import com.zzzmode.appopsx.ui.model.PermissionChildItem;
import com.zzzmode.appopsx.ui.model.PermissionGroup;
import com.zzzmode.appopsx.ui.model.PreAppInfo;
import com.zzzmode.appopsx.ui.permission.AppPermissionActivity;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.ObservableSource;
import io.reactivex.Single;
import io.reactivex.SingleEmitter;
import io.reactivex.SingleOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.BiConsumer;
import io.reactivex.functions.Function;
import io.reactivex.functions.Predicate;
import io.reactivex.internal.operators.single.SingleJust;
import io.reactivex.observers.ResourceSingleObserver;
import io.reactivex.schedulers.Schedulers;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.Callable;
      public AppInfo apply(String s) throws Exception {
        PackageManager packageManager = context.getPackageManager();
        PackageInfo packageInfo = packageManager.getPackageInfo(s, 0);

        AppInfo info = new AppInfo();
        info.packageName = packageInfo.packageName;
        info.appName = BidiFormatter.getInstance()
            .unicodeWrap(packageInfo.applicationInfo.loadLabel(packageManager)).toString();
        info.time = Math.max(packageInfo.lastUpdateTime, packageInfo.firstInstallTime);
        info.installTime = packageInfo.firstInstallTime;
        info.updateTime = packageInfo.lastUpdateTime;
        info.applicationInfo = packageInfo.applicationInfo;

        LocalImageLoader.initAdd(context, info);
        return info;
      }
    });

  }

  public static Observable<List<AppInfo>> getInstalledApps(final Context context,
      final boolean loadSysapp) {

    return Observable.create(new ObservableOnSubscribe<List<AppInfo>>() {
      @Override
      public void subscribe(final ObservableEmitter<List<AppInfo>> e) throws Exception {
        PackageManager packageManager = context.getPackageManager();
        int uid = Users.getInstance().getCurrentUid();
        List<PackageInfo> installedPackages = null;
        if(uid == 0){
          installedPackages = packageManager.getInstalledPackages(0);
        }else {
          installedPackages = AppOpsx.getInstance(context).getApiSupporter().getInstalledPackages(0,uid);
        }


        List<AppInfo> zhAppInfos = new ArrayList<AppInfo>();
        List<AppInfo> enAppInfos = new ArrayList<AppInfo>();
        for (PackageInfo installedPackage : installedPackages) {
          if (loadSysapp
              || (installedPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
            AppInfo info = new AppInfo();
            info.packageName = installedPackage.packageName;
            info.appName = BidiFormatter.getInstance()
                .unicodeWrap(installedPackage.applicationInfo.loadLabel(packageManager)).toString();
            info.time = Math
                .max(installedPackage.lastUpdateTime, installedPackage.firstInstallTime);
            info.installTime = installedPackage.firstInstallTime;
            info.updateTime = installedPackage.lastUpdateTime;
            info.applicationInfo = installedPackage.applicationInfo;

            LocalImageLoader.initAdd(context, info);

            //some of the app name is empty.
            if(TextUtils.isEmpty(info.appName)){
              info.appName = info.packageName;
            }
            final char c = info.appName.charAt(0);
            if (c >= 48 && c <= 122) {
              enAppInfos.add(info);
            } else {
              zhAppInfos.add(info);
            }

          }
        }

        Collections.sort(enAppInfos, new Comparator<AppInfo>() {
          @Override
          public int compare(AppInfo o1, AppInfo o2) {
            return o1.appName.compareToIgnoreCase(o2.appName);
          }
        });

        Collections.sort(zhAppInfos, new Comparator<AppInfo>() {
          @Override
          public int compare(AppInfo o1, AppInfo o2) {
            return o2.appName.compareTo(o1.appName);
          }
        });
        List<AppInfo> ret = new ArrayList<AppInfo>();

        int type = PreferenceManager.getDefaultSharedPreferences(context)
            .getInt("pref_app_sort_type", 0);
        if (type == 1) {
          //按名称排序[字母在后]

          ret.addAll(zhAppInfos);
          ret.addAll(enAppInfos);
        } else {
          //按名称排序[字母在前] 默认
          ret.addAll(enAppInfos);
          ret.addAll(zhAppInfos);
        }

        e.onNext(ret);
        e.onComplete();
      }
    });
  }


  public static Observable<PreAppInfo> getAppsPermission(final Context context,
      AppInfo[] appInfos) {
    return Observable.fromArray(appInfos).map(new Function<AppInfo, PreAppInfo>() {
      @Override
      public PreAppInfo apply(@NonNull AppInfo s) throws Exception {
        OpsResult opsForPackage = AppOpsx.getInstance(context).getOpsForPackage(s.packageName);
        if (opsForPackage != null) {
          if (opsForPackage.getException() != null) {
            throw new Exception(opsForPackage.getException());
          }
        } else {
          throw new NullPointerException("getOpsForPackage:" + s + " return null !");
        }
        PreAppInfo appInfo = new PreAppInfo(s.packageName);
        List<PackageOps> opses = opsForPackage.getList();
        if (opses != null) {
          StringBuilder sb = new StringBuilder();
          for (PackageOps opse : opses) {
            List<OpEntry> ops = opse.getOps();