How to check MIUI autostart permission programmatically?
Asked Answered
R

11

59

I need to check programmatically if the auto start permission for my app in MIUI phone is on or off. Facebook and whatsapp have this permission already enabled by default , how can I do so?

Roundfaced answered 7/9, 2016 at 9:31 Comment(2)
It has happened 5 years since you asked this question. Is there any better approach now?Unflinching
@Unflinching It has been 9 moths since you asked the question, did you find a solution?Vassalage
S
57

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 2 I 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.

Seleucid answered 7/9, 2016 at 9:47 Comment(9)
But some apps like facebook messenger, whatsapp etc have autostart option by default. Any idea how is ith getting done ?Booty
@Booty These apps are white listed by miui os and so they get autostart permission automaticallySeleucid
yes @indramurari . As a workaround we can ask the users to redirect to the security app as mentioned here. #40814626Booty
As of now, this seems to be the only workaround. I hate it when custom ROMs meddle in such a way!Ie
@Seleucid how to check autostart permission already enable or notShumway
@AkashSingh I don't think it's possibleSeleucid
@Seleucid Is it possible now to check if the permission is enabled?Eric
@Royz, did you find a solution?Vassalage
Not anymore, check this library: github.com/XomaDev/MIUI-autostartJanes
M
51

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));
    }
}
Mehalek answered 8/3, 2018 at 7:34 Comment(9)
This does not answer if a user has set the permission or not.Cantankerous
It does answer my question. :)Prady
Unfortunately, it does not work on oppo A77. Permission Denial: starting Intent { cmp=com.coloros.safecenter/.startupapp.StartupAppListActivity }. I have also put this "oppo.permission.OPPO_COMPONENT_SAFE" in the manifest.Probe
it is right to start auto start permission but how to check auto start permission is already enable or not.Anemia
@Mehalek how did you get these class names?Wingback
Wait, this issue exists on devices of other companies too?Russon
It is redirecting every time when I open my app, even I've already gave the auto startup permission. How to deal with that? @MehalekPlato
I doubt there is a way to retrieve that setting. However, what you could do is save the information that the user was redirected to the setting screen in the shared preferences (but make sure you have explained to the user what is actually happening and why before redirecting him). Add the conditional statement that will be checking this flag to prevent further redirects. @NevilGhelaniMishamishaan
For tecno and infinix phones use componennt name and class: ComponentName("com.transsion.phonemaster", "com.cyin.himgr.autostart.AutoStartActivity")Connacht
D
5

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 Manifest

public 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);
}

@Override
public 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.

Deputy answered 24/7, 2017 at 16:32 Comment(2)
i am not getting any broadcast you have any other way or example?Avian
Would you mind making this a standalone library and publishing? I tried using this, but I get both intents even though Autostart is off. Also it is not clear to me how the activity is supposed to be recreated in this method.Lilithe
J
3

You could use this library to check the autostart permission state on MIUI 10, 11 and 12 and so on

https://github.com/XomaDev/MIUI-autostart

if (Utils.isOnMiui()) {
  val enabled: Boolean = Autostart.isAutoStartEnabled(context)
}
Janes answered 5/12, 2021 at 7:8 Comment(0)
W
2

In addition to Nikhil's answer:

First of all, some apps like Facebook, Whatsapp are whitelisted from Xiomi by default that means auto start permission will automatically be on for these apps.

I also didn't find any way to check for auto start permission if it's enabled or not and enable it programmatically. Though as above answer suggests we can redirect user to auto start permission activity but when we have to redirect user we still don't know and also this will not work in all of the Xiomi devices.

So I used an alternative for my sync adapter to work. I stored a boolean variable named "isSyncAdapterRunning" in shared preferences and set the value of it every time sync adapter runs. This way I'll be able to know if my sync adapter is working or not.

//in my sync adapter
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
    Log.e("TAG", "SyncStarted");
    performSync(true);        
}

public static void performSync(boolean fromSyncAdapterClass){
    //write your code for sync operation
    if(fromSyncAdapterClass){
          setValueOfIsSyncAdapterRunningVariable();
    }
}

I made other background service to perform same task if sync adapter is not working.

//In my other background service
public class BackgroundSyncService extends IntentService {

public BackgroundSyncService() {
    super("BackgroundSyncService");
}

@Override
protected void onHandleIntent(Intent intent) {
    SyncAdapter.performSync(false);        
}
}

Now start sync adapter:

// start your sync adapter here

//And after that just start that service with a condition
if(!getValueOfIsSyncAdapterRunningVariable()){
      startService(new Intent(context, BackgroundSyncService.class));
}

So basically I'm running another service to perform same task in background if my sync adapter is not working and the best thing is only one of them will run at a time. Above code will fail if user turn on auto start permission and turn off again because value of boolean variable is already set. For that you can set value of boolean variable to default once in every 24Hrs.

Hope this helps.

Wayland answered 14/12, 2017 at 12:53 Comment(0)
H
2

For now it's not possible. As it's completely depend on their operating system API's and customization. But i implemented a fix using SharedPreference. It doesn't solved the problem but it prevents app from opening setting screen everytime app is opened. Example :

 if (AppPref.getAutoStart(context).isEmpty() && AppPref.getAutoStart(context).equals("")) {
        enableAutoStart();
    }

private void enableAutoStart() {
    if (Build.BRAND.equalsIgnoreCase("xiaomi")) {

        new AlertDialog.Builder(context)
                .setTitle("Enable AutoStart")
                .setMessage("Please allow this app to always run in the background,else our services can't be accessed.")
                .setNegativeButton("Deny", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        AppPref.setAutoStart(context, "");
                        dialog.dismiss();
                    }
                })
                .setPositiveButton("ALLOW", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        try {
                            AppPref.setAutoStart(context, "1");
                            Intent intent = new Intent();
                            intent.setComponent(new ComponentName("com.miui.securitycenter",
                                    "com.miui.permcenter.autostart.AutoStartManagementActivity"));
                            startActivity(intent);
                        } catch (Exception e) {
                            Toast.makeText(context, "Can't perform action", Toast.LENGTH_SHORT).show();
                        }
                        dialog.dismiss();
                    }
                })
                .create()
                .show();
    }
}
Hoke answered 11/2, 2021 at 10:18 Comment(0)
M
2

You cannot check whether autorun permission is enabled or not because autorun feature is provided by customised os only not by android os like mi, vivo, oppo, letv etc

This is a workaround tested on MI, Honor and vivo phones.

To check whether os is customised like miui, honor ui copy and paste this method in activity, fragment or util class

public static void getAutoStartPermission(final Activity context) {
        final String build_info = Build.BRAND.toLowerCase();
        switch (build_info) {
            case "xiaomi":
                Utilities.Companion.showAutorunDialog(context);
                break;
            case "letv":
                Utilities.Companion.showAutorunDialog(context);
                break;
            case "oppo":
                Utilities.Companion.showAutorunDialog(context);
                break;
            case "vivo":
                Utilities.Companion.showAutorunDialog(context);
                break;
            case "Honor":
                Utilities.Companion.showAutorunDialog(context);
                break;
            default:
                break;

        }

    }

Where

fun showAutorunDialog(context: Context) {
            val builder = AlertDialog.Builder(context)
            //set title for alert dialog
            builder.setTitle("Alert")
            //set message for alert dialog
            builder.setMessage("Enable Autostart permission for this app if its disabled in app settings in order to run application in background.")
            builder.setCancelable(true)
            //performing positive action
            builder.setPositiveButton("Enable") { _, _ ->
                addAutoStartup(context)
            }

            // Create the AlertDialog
              var  vpnDialog = builder.create()
                // Set other dialog properties
                vpnDialog!!.setCancelable(false)
                vpnDialog!!.show()

        }
        private fun addAutoStartup(context:Context) {
            try {
                val intent = Intent()
                val manufacturer = Build.MANUFACTURER
                if ("xiaomi".equals(manufacturer, ignoreCase = true)) {
                    intent.component = ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity")
                } else if ("oppo".equals(manufacturer, ignoreCase = true)) {
                    intent.component = ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity")
                } else if ("vivo".equals(manufacturer, ignoreCase = true)) {
                    intent.component = ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity")
                } else if ("Letv".equals(manufacturer, ignoreCase = true)) {
                    intent.component = ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity")
                } else if ("Honor".equals(manufacturer, ignoreCase = true)) {
                    intent.component = ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity")
                }
                val list: List<ResolveInfo> = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
                if (list.size > 0) {
                    context.startActivity(intent)
                }
            } catch (e: java.lang.Exception) {
                Log.e("exc", e.toString())
            }
        }
Marvelofperu answered 4/6, 2021 at 14:12 Comment(0)
P
2

This code worked for me. Simple and easy . Credit

  private State getAutoStartState(Activity activity) throws Exception {
    Class<?> clazz;
    try {
        clazz = Class.forName(CLAZZ);
    } catch (ClassNotFoundException ignored) {
        // we don't know if its enabled, class
        // is not found, no info
        return State.NO_INFO;
    }
    final Method method = getMethod(clazz);
    if (method == null) {
        // exception raised while search the method,
        // or it doesn't exist
        return State.NO_INFO;
    }
    // the method is a public method, It's still
    // better to do this
    method.setAccessible(true);

    // the target object is null, because the
    // method is static
    final Object result = method.invoke(null, getActivity(),
            getActivity().getPackageName());

    // the result should be an Int
    if (!(result instanceof Integer))
        throw new Exception();

    final int _int = (int) result;

    if (_int == ENABLED)
        return State.ENABLED;
    else if (_int == DISABLED)
        return State.DISABLED;
    return State.UNKNOWN;
}

private Method getMethod(Class<?> clazz) {
    try {
        return clazz.getDeclaredMethod("getApplicationAutoStart",
                Context.class, String.class);
    } catch (Exception ignored) {
        // this should not happen, probably
        // MIUI version is updated, lets give a last try
        return null;
    }
}
public void checkMIUIAutoStart(Activity activity) throws Exception {
    if (getAutoStartState(activity) == State.DISABLED) {

        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);
        }

    }else {
        Toast.makeText(activity, "Auto-start is enabled.", Toast.LENGTH_SHORT).show();
    }
}
Pliant answered 29/11, 2021 at 9:40 Comment(1)
I'm the author of this code, and it requires some updates on newer devices, use this library instead: github.com/XomaDev/MIUI-autostartJanes
C
0

To check if permission enabled, I just starting a foreground service and check if is running.

Service:

class ExtraPermissionStateService: Service() {

    companion object {
        private var instance: ExtraPermissionStateService? = null

        fun isAppCanRunOnBackground(context: Context): Boolean {
            val serviceIntent = Intent(context, ExtraPermissionStateService::class.java)
            context.startService(serviceIntent)
            return instance != null
        }
    }

    override fun onBind(p0: Intent?): IBinder? {
        return null
    }

    override fun onCreate() {
        super.onCreate()
        instance = this
    }

    override fun onDestroy() {
        super.onDestroy()
        instance = null
    }
}

call it:

ExtraPermissionStateService.isAppCanRunOnBackground(context)

And don't forget on the manifest:

<service android:name=".helpers.utils.ExtraPermissionStateService"/>

Condition answered 22/6, 2021 at 14:28 Comment(1)
This does not answer the questions, as Auto Start is not a permission, rather a feature provided by customized OEMs/OS, and your code does not have any statement to check for permissions.Mcmahan
J
0

I have tried the below solution and it worked for me. If the "Auto Start" is enabled it will return "true", if not it will return "false".

public class CustomPermissionCheck {

private static final String TAG = "CustomPermissionCheck";

private Context context;
private static final int APP_AUTO_START_PERMISSION_CODE = 10008;

public CustomPermissionCheck(Context context) {
    this.context = context;
}

public boolean isAutoStartEnabled() {

    try {
        AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        Method method = AppOpsManager.class.getMethod("checkOpNoThrow", int.class, int.class, String.class);
        int result = (int) method.invoke(appOpsManager, APP_AUTO_START_PERMISSION_CODE, android.os.Process.myUid(), context.getPackageName());
        boolean isEnabled = result == AppOpsManager.MODE_ALLOWED;
        return isEnabled;
    } catch (Exception e) {
        e.printStackTrace();
    }

    return false;
}
}
Jumbala answered 30/6, 2022 at 8:28 Comment(1)
not working in mi4iComte
U
-10

You have to do allow and deny for system permissions.

below is the code:

private boolean checkPermission(){
    int result = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION);
    if (result == PackageManager.PERMISSION_GRANTED){

        return true;

    } else {

        return false;

    }
}

 @Override
 public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case PERMISSION_REQUEST_CODE:
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                Snackbar.make(view,"Permission Granted, Now you can access location data.",Snackbar.LENGTH_LONG).show();

            } else {

                Snackbar.make(view,"Permission Denied, You cannot access location data.",Snackbar.LENGTH_LONG).show();

            }
            break;
    }
}
Unmixed answered 7/9, 2016 at 9:49 Comment(1)
autostart permission is for notification purpose i think the above answer of for the LOCATIONRetrogradation

© 2022 - 2024 — McMap. All rights reserved.