How to check MIUI autostart permission programmatically?
For now it's not possible.
As it's completely depend on their operating system API's and customisation. Even developers have requested for this on XIOMI's official forums but there is no response from there side.
Till now even i am finding an answer to this question but nothing helped me.
For the time being it will be only possible for rooted phones. i.e. making customisation in their firmware by becoming super user. But this is not at all advisable as it may damage user's phone.
EDIT 1
You can redirect user to autostart permission's settings page for enabling your app using following code
String manufacturer = "xiaomi";if (manufacturer.equalsIgnoreCase(android.os.Build.MANUFACTURER)) { //this will open auto start screen where user can enable permission for your app Intent intent1 = new Intent(); intent1.setComponent(new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity")); startActivity(intent1);}
EDIT 2I have recently used Mi A1 from XIOMI which have stock android (not miui) so this phone does not have autostart permission
settings from miui. So take care while navigating user to the settings in such devices because it will not work here.
100% working for oppo, vivo, xiomi, letv huawei, and honor
just call this function
private void addAutoStartup() { try { Intent intent = new Intent(); String manufacturer = android.os.Build.MANUFACTURER; if ("xiaomi".equalsIgnoreCase(manufacturer)) { intent.setComponent(new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity")); } else if ("oppo".equalsIgnoreCase(manufacturer)) { intent.setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity")); } else if ("vivo".equalsIgnoreCase(manufacturer)) { intent.setComponent(new ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity")); } else if ("Letv".equalsIgnoreCase(manufacturer)) { intent.setComponent(new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity")); } else if ("Honor".equalsIgnoreCase(manufacturer)) { intent.setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity")); } List<ResolveInfo> list = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); if (list.size() > 0) { startActivity(intent); } } catch (Exception e) { Log.e("exc" , String.valueOf(e)); }}
This is not a perfect solution by any means and it requires some testing, but I've been able to detect the autostart permission on my Xiaomi device with it.
The autostart permission allows apps to be started by receiving an implicit broadcast intent. This method consists of scheduling an implicit broadcast with AlarmManager, killing the app and checking if the broadcast caused it to respawn. A second explicit intent is also scheduled just to make sure that the app is started eventually.
public class AutostartDetector extends BroadcastReceiver {// I've omitted all the constant declaration to keep this snippet concise// they should match the values used in the Manifestpublic static void testAutoStart(Context context) { long now = System.currentTimeMillis(); // this ID is for matching the implicit and explicit intents // it might be unnecessary String testId = Long.toHexString(now); Intent implicitIntent = new Intent(ACTION_IMPLICIT_BROADCAST); // the category is set just to make sure that no other receivers handle the broadcast implicitIntent.addCategory(CATEGORY_AUTOSTART); implicitIntent.putExtra(EXTRA_TEST_ID, testId); PendingIntent implicitPendingIntent = PendingIntent.getBroadcast(context, REQUEST_CODE_IMPLICIT_BROADCAST, implicitIntent, PendingIntent.FLAG_UPDATE_CURRENT); Intent explicitIntent = new Intent(ACTION_EXPLICIT_BROADCAST); explicitIntent.addCategory(CATEGORY_AUTOSTART); explicitIntent.setComponent(new ComponentName(context, AutostartDetector.class)); explicitIntent.putExtra(EXTRA_TEST_ID, testId); PendingIntent explicitPendingIntent = PendingIntent.getBroadcast(context, REQUEST_CODE_EXPLICIT_BROADCAST, explicitIntent, PendingIntent.FLAG_UPDATE_CURRENT); AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); // calling commit() makes sure that the data is written before we kill the app // again, this might be unnecessary getSharedPreferences(context).edit().putInt(testId, TestStatus.STARTED).commit(); // the explicit intent is set with an additional delay to let the implicit one be received first; might require some fine tuning alarmManager.set(AlarmManager.RTC_WAKEUP, now + BASE_DELAY, implicitPendingIntent); alarmManager.set(AlarmManager.RTC_WAKEUP, now + BASE_DELAY + EXPLICIT_INTENT_DELAY, explicitPendingIntent); // kill the app - actually kind of tricky, see below SelfKiller.killSelf(context);}@Overridepublic void onReceive(Context context, Intent intent) { SharedPreferences sharedPreferences = getSharedPreferences(context); String testId = intent.getStringExtra(EXTRA_TEST_ID); if (testId == null) { Log.w(TAG, "Null test ID"); return; } if (!sharedPreferences.contains(testId)) { Log.w(TAG, "Unknown test ID: " + testId); return; } String action = intent.getAction(); if (ACTION_IMPLICIT_BROADCAST.equals(action)) { // we could assume right here that the autostart permission has been granted, // but we should receive the explicit intent anyway, so let's use it // as a test sanity check Log.v(TAG, "Received implicit broadcast"); sharedPreferences.edit().putInt(testId, TestStatus.IMPLICIT_INTENT_RECEIVED).apply(); } else if (ACTION_EXPLICIT_BROADCAST.equals(action)) { Log.v(TAG, "Received explicit broadcast"); int testStatus = sharedPreferences.getInt(testId, -1); switch (testStatus) { case TestStatus.STARTED: // the implicit broadcast has NOT been received - autostart permission denied Log.d(TAG, "Autostart disabled"); sharedPreferences.edit().putBoolean(PREF_AUTOSTART_ENABLED, false).apply(); notifyListener(false); break; case TestStatus.IMPLICIT_INTENT_RECEIVED: // the implicit broadcast has been received - autostart permission granted Log.d(TAG, "Autostart enabled"); sharedPreferences.edit().putBoolean(PREF_AUTOSTART_ENABLED, true).apply(); notifyListener(true); break; default: Log.w(TAG, "Invalid test status: " + testId + ' ' + testStatus); break; } }}private interface TestStatus { int STARTED = 1; int IMPLICIT_INTENT_RECEIVED = 2;}
Receiver declaration in the manifest:
<receiver android:name=".autostart.AutostartDetector"> <intent-filter> <category android:name="com.example.autostart.CATEGORY_AUTOSTART"/> <action android:name="com.example.autostart.ACTION_IMPLICIT_BROADCAST"/> <action android:name="com.example.autostart.ACTION_EXPLICIT_BROADCAST"/> </intent-filter></receiver>
Killing the app reliably is another problem. I've been using this helper method:
public static void killSelf(Context context) { ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); activityManager.killBackgroundProcesses(context.getPackageName()); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { // this is all we can do before ICS. luckily Xiaomi phones have newer system versions :) System.exit(1); return; } // set up a callback so System.exit() is called as soon as all // the activities are finished context.registerComponentCallbacks(new ComponentCallbacks2() { @Override public void onTrimMemory(int i) { if (i == TRIM_MEMORY_UI_HIDDEN) { Log.v(TAG, "UI Hidden"); System.exit(1); } } /* ... */ }); // see below ActivityTracker.getInstance().finishAllActivities();}
ActivityTracker is another utility that keeps track of activity lifecycles. Make sure to register it in the Application subclass.
@RequiresApi(api = Build.VERSION_CODES.ICE_CREAM_SANDWICH)public final class ActivityTracker implements Application.ActivityLifecycleCallbacks { private final ArraySet<Activity> mCreatedActivities = new ArraySet<>(); public static ActivityTracker getInstance() { return Holder.INSTANCE; } public static void init(Application application) { application.registerActivityLifecycleCallbacks(getInstance()); } public static void release(Application application) { ActivityTracker activityTracker = getInstance(); application.unregisterActivityLifecycleCallbacks(activityTracker); activityTracker.mCreatedActivities.clear(); } public void finishAllActivities() { // iterate over active activities and finish them all for (Activity activity : mCreatedActivities) { Log.v(TAG, "Finishing " + activity); activity.finish(); } } public Set<Activity> getCreatedActivities() { return Collections.unmodifiableSet(mCreatedActivities); } @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { mCreatedActivities.add(activity); } @Override public void onActivityDestroyed(Activity activity) { mCreatedActivities.remove(activity); } private static final class Holder { private static final ActivityTracker INSTANCE = new ActivityTracker(); } /* ... */}
You might also want to stop all the services just to be sure.