web-dev-qa-db-fra.com

Comment vérifier l'autorisation de démarrage automatique de MIUI par programme?

Je dois vérifier par programme si l'autorisation de démarrage automatique de mon application sur le téléphone MIUI est activée ou désactivée. Facebook et WhatsApp ont déjà cette autorisation activée par défaut, comment puis-je le faire?

29
Ekta Aggarwal

Pour l'instant ce n'est pas possible.

Comme cela dépend complètement de leurs API de système d'exploitation et de leur personnalisation. Même les développeurs l'ont demandé sur les forums officiels de XIOMI mais il n'y a aucune réponse de ce côté.

Jusqu'à présent, même moi, je trouve une réponse à cette question, mais rien ne m'a aidé.

Pour le moment, cela ne sera possible que pour les téléphones rootés. c'est-à-dire faire la personnalisation dans leur firmware en devenant super utilisateur. Mais ce n'est pas du tout conseillé car cela peut endommager le téléphone de l'utilisateur.

MODIFIER 1

Vous pouvez rediriger l'utilisateur vers la page des paramètres de l'autorisation de démarrage automatique pour activer votre application à l'aide du code suivant

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 J'ai récemment utilisé Mi A1 de XIOMI qui ont des actions Android (pas miui) donc ce téléphone n'a pas autostart permission paramètres de miui. Faites donc attention lors de la navigation de l'utilisateur vers les paramètres de ces appareils, car cela ne fonctionnera pas ici.

31
Nikhil

100% travaillant pour oppo, vivo, xiaomi, letv huawei et honor

il suffit d'appeler cette fonction

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

Ce n'est en aucun cas une solution parfaite et cela nécessite quelques tests, mais j'ai pu détecter l'autorisation de démarrage automatique sur mon appareil Xiaomi avec.

L'autorisation de démarrage automatique permet de démarrer des applications en recevant une intention de diffusion implicite. Cette méthode consiste à planifier une diffusion implicite avec AlarmManager, à tuer l'application et à vérifier si la diffusion a provoqué sa réapparition. Une deuxième intention explicite est également prévue juste pour s'assurer que l'application est éventuellement lancée.

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

Déclaration du destinataire dans le manifeste:

<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>

Tuer l'application de manière fiable est un autre problème. J'utilise cette méthode d'assistance:

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 est un autre utilitaire qui assure le suivi des cycles de vie des activités. Assurez-vous de l'enregistrer dans la sous-classe Application.

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

    /* ... */
}

Vous pouvez également vouloir arrêter tous les services juste pour être sûr.

4
SpaceBison

En plus de réponse de Nikhil :

Tout d'abord, certaines applications comme Facebook, Whatsapp sont inscrites sur la liste blanche de Xiomi par défaut, ce qui signifie que l'autorisation de démarrage automatique sera automatiquement activée pour ces applications.

Je n'ai également trouvé aucun moyen de vérifier l'autorisation de démarrage automatique si elle est activée ou non et de l'activer par programme. Bien que la réponse ci-dessus suggère que nous pouvons rediriger l'utilisateur vers une activité d'autorisation de démarrage automatique, mais lorsque nous devons rediriger l'utilisateur, nous ne le savons toujours pas et cela ne fonctionnera pas dans tous les appareils Xiomi.

J'ai donc utilisé une alternative pour que mon adaptateur de synchronisation fonctionne. J'ai stocké une variable booléenne nommée "isSyncAdapterRunning" dans les préférences partagées et défini sa valeur à chaque exécution de l'adaptateur de synchronisation. De cette façon, je pourrai savoir si mon adaptateur de synchronisation fonctionne ou non.

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

J'ai créé un autre service d'arrière-plan pour effectuer la même tâche si l'adaptateur de synchronisation ne fonctionne pas.

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

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

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

Maintenant, démarrez l'adaptateur de synchronisation:

// start your sync adapter here

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

Donc, fondamentalement, j'exécute un autre service pour effectuer la même tâche en arrière-plan si mon adaptateur de synchronisation ne fonctionne pas et la meilleure chose est qu'un seul d'entre eux s'exécutera à la fois. Le code ci-dessus échouera si l'utilisateur active l'autorisation de démarrage automatique et la désactive à nouveau car la valeur de la variable booléenne est déjà définie. Pour cela, vous pouvez définir la valeur de la variable booléenne par défaut une fois toutes les 24 heures.

J'espère que cela t'aides.

1
Vipul Kumar