Как запрограммировать разрешение автозапуска MIUI?
Мне нужно проверить программно, если включено или выключено разрешение автозапуска для моего приложения на телефоне MIUI. Facebook и whatsapp имеют это разрешение, которое уже включено по умолчанию, как я могу это сделать?
Ответы
Ответ 1
Пока это невозможно.
Поскольку это полностью зависит от их API операционной системы и настройки. Даже разработчики просили об этом на официальных форумах XIOMI, но ответа оттуда нет.
До сих пор даже я нахожу ответ на этот вопрос, но мне ничего не помогло.
Пока это будет возможно только для корневых телефонов. т.е. внесение настроек в их прошивку, став суперпользователем. Но это совсем не рекомендуется, так как это может повредить пользовательские телефоны.
ИЗМЕНИТЬ 1
Вы можете перенаправить пользователя на страницу настроек автозапуска, чтобы включить приложение, используя следующий код
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 Недавно я использовал Mi A1 от XIOMI, у которого есть Android android (не miui), поэтому у этого телефона нет настроек авторизации autostart permission
из miui. Поэтому будьте внимательны при навигации пользователя к настройкам на таких устройствах, потому что здесь это не сработает.
Ответ 2
100% работают на oppo, vivo, xiomi, letv huawei и честь
просто вызовите эту функцию
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));
}
}
Ответ 3
Это не идеальное решение любыми средствами, и для этого требуется некоторое тестирование, но я смог обнаружить с него разрешение автозапуска на своем устройстве Xiaomi.
Разрешение автозапуска позволяет запускать приложения, получая неявное назначение трансляции. Этот метод состоит из планирования неявного трансляции с помощью AlarmManager, убийства приложения и проверки того, вызвало ли это вещание его респаун. Второе явное намерение также запланировано только для того, чтобы убедиться, что приложение запущено в конце концов.
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 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 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>
Надежно убить приложение - еще одна проблема. Я использовал этот вспомогательный метод:
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 - еще одна утилита, которая отслеживает жизненные циклы активности. Обязательно зарегистрируйте его в подклассе 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();
}
/* ... */
}
Вы также можете остановить все службы, чтобы быть уверенными.
Ответ 4
В дополнение к Nikhil answer:
Прежде всего, некоторые приложения, такие как Facebook, Whatsapp по умолчанию отправляются из Xiomi, что означает, что автоматически запускается разрешение для этих приложений.
Я также не нашел способа проверить разрешение автозапуска, если оно включено или нет, и включить его программно. Хотя, как сказано выше, мы можем перенаправить пользователя на автоматическую авторизацию, но когда нам нужно перенаправить пользователя, мы все еще не знаем, и это не будет работать на всех устройствах Xiomi.
Итак, я использовал альтернативу для работы адаптера синхронизации. Я сохранил логическую переменную с именем "isSyncAdapterRunning" в общих настройках и задал ее значение при каждом запуске адаптера синхронизации. Таким образом, я смогу узнать, работает ли мой адаптер синхронизации.
//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();
}
}
Я сделал другой фоновый сервис для выполнения той же задачи, если адаптер синхронизации не работает.
//In my other background service
public class BackgroundSyncService extends IntentService {
public BackgroundSyncService() {
super("BackgroundSyncService");
}
@Override
protected void onHandleIntent(Intent intent) {
SyncAdapter.performSync(false);
}
}
Теперь запустите адаптер синхронизации:
// start your sync adapter here
//And after that just start that service with a condition
if(!getValueOfIsSyncAdapterRunningVariable()){
startService(new Intent(context, BackgroundSyncService.class));
}
Итак, в основном я запускаю другую службу для выполнения той же задачи в фоновом режиме, если мой адаптер синхронизации не работает, и самое лучшее, что только один из них будет запускаться за раз.
Вышеуказанный код не будет работать, если пользователь включит разрешение автозапуска и снова выключится, так как значение булевой переменной уже установлено. Для этого вы можете установить значение переменной boolean по умолчанию один раз в каждые 24 часа.
Надеюсь, что это поможет.
Ответ 5
Вы должны разрешить и запретить системные разрешения.
ниже приведен код:
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;
}
}