I have a Huawei P8 with Android 5.0 that I\'m using for testing an app. The app needs to be running in the background, as it tracks BLE regions.
I\'ve discovered that Huawei has built in a \"feature\" called Protected Apps, that can be accessed from the phone settings (Battery Manager > Protected Apps). This allows elected apps to keep running after the screen is turned off.
Sensibly for Huawei, but unfortunately for me, it looks like it\'s opt-in, i.e. apps are out by default, and you have to manually put them in.
This isn\'t a showstopper, as I can advise users in an FAQ or printed documentation about the fix, but I recently installed Tinder (for research purposes!), and noticed that it was put in the protected list automatically.
Does anyone know how I can do this for my app? Is it a setting in the manifest? Is it something Huawei has enabled for Tinder because it\'s a popular app?
if(\"huawei\".equalsIgnoreCase(android.os.Build.MANUFACTURER) && !sp.getBoolean(\"protected\",false)) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.huawei_headline).setMessage(R.string.huawei_text)
.setPositiveButton(R.string.go_to_protected, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent intent = new Intent();
intent.setComponent(new ComponentName(\"com.huawei.systemmanager\", \"com.huawei.systemmanager.optimize.process.ProtectActivity\"));
startActivity(intent);
sp.edit().putBoolean(\"protected\",true).commit();
}
}).create().show();
}
There isn\'t a setting in the manifest, and Huawei has enabled Tinder because it\'s a popular app. There isn\'t a way to know if apps are protected.
Anyway I used ifHuaweiAlert()
in onCreate()
to show an AlertDialog
:
private void ifHuaweiAlert() {
final SharedPreferences settings = getSharedPreferences(\"ProtectedApps\", MODE_PRIVATE);
final String saveIfSkip = \"skipProtectedAppsMessage\";
boolean skipMessage = settings.getBoolean(saveIfSkip, false);
if (!skipMessage) {
final SharedPreferences.Editor editor = settings.edit();
Intent intent = new Intent();
intent.setClassName(\"com.huawei.systemmanager\", \"com.huawei.systemmanager.optimize.process.ProtectActivity\");
if (isCallable(intent)) {
final AppCompatCheckBox dontShowAgain = new AppCompatCheckBox(this);
dontShowAgain.setText(\"Do not show again\");
dontShowAgain.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
editor.putBoolean(saveIfSkip, isChecked);
editor.apply();
}
});
new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(\"Huawei Protected Apps\")
.setMessage(String.format(\"%s requires to be enabled in \'Protected Apps\' to function properly.%n\", getString(R.string.app_name)))
.setView(dontShowAgain)
.setPositiveButton(\"Protected Apps\", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
huaweiProtectedApps();
}
})
.setNegativeButton(android.R.string.cancel, null)
.show();
} else {
editor.putBoolean(saveIfSkip, true);
editor.apply();
}
}
}
private boolean isCallable(Intent intent) {
List<ResolveInfo> list = getPackageManager().queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
return list.size() > 0;
}
private void huaweiProtectedApps() {
try {
String cmd = \"am start -n com.huawei.systemmanager/.optimize.process.ProtectActivity\";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
cmd += \" --user \" + getUserSerial();
}
Runtime.getRuntime().exec(cmd);
} catch (IOException ignored) {
}
}
private String getUserSerial() {
//noinspection ResourceType
Object userManager = getSystemService(\"user\");
if (null == userManager) return \"\";
try {
Method myUserHandleMethod = android.os.Process.class.getMethod(\"myUserHandle\", (Class<?>[]) null);
Object myUserHandle = myUserHandleMethod.invoke(android.os.Process.class, (Object[]) null);
Method getSerialNumberForUser = userManager.getClass().getMethod(\"getSerialNumberForUser\", myUserHandle.getClass());
Long userSerial = (Long) getSerialNumberForUser.invoke(userManager, myUserHandle);
if (userSerial != null) {
return String.valueOf(userSerial);
} else {
return \"\";
}
} catch (NoSuchMethodException | IllegalArgumentException | InvocationTargetException | IllegalAccessException ignored) {
}
return \"\";
}
+1 for Pierre for his great solution which works for multiple device Manufacturers (Huawei, asus, oppo ...).
I wanted to use his code in my Android app which is in Java.
I inspired my code from Pierre and Aiuspaktyn answers.
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.support.v7.widget.AppCompatCheckBox;
import android.widget.CompoundButton;
import java.util.List;
public class Utils {
public static void startPowerSaverIntent(Context context) {
SharedPreferences settings = context.getSharedPreferences(\"ProtectedApps\", Context.MODE_PRIVATE);
boolean skipMessage = settings.getBoolean(\"skipProtectedAppCheck\", false);
if (!skipMessage) {
final SharedPreferences.Editor editor = settings.edit();
boolean foundCorrectIntent = false;
for (Intent intent : Constants.POWERMANAGER_INTENTS) {
if (isCallable(context, intent)) {
foundCorrectIntent = true;
final AppCompatCheckBox dontShowAgain = new AppCompatCheckBox(context);
dontShowAgain.setText(\"Do not show again\");
dontShowAgain.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
editor.putBoolean(\"skipProtectedAppCheck\", isChecked);
editor.apply();
}
});
new AlertDialog.Builder(context)
.setTitle(Build.MANUFACTURER + \" Protected Apps\")
.setMessage(String.format(\"%s requires to be enabled in \'Protected Apps\' to function properly.%n\", context.getString(R.string.app_name)))
.setView(dontShowAgain)
.setPositiveButton(\"Go to settings\", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
context.startActivity(intent);
}
})
.setNegativeButton(android.R.string.cancel, null)
.show();
break;
}
}
if (!foundCorrectIntent) {
editor.putBoolean(\"skipProtectedAppCheck\", true);
editor.apply();
}
}
}
private static boolean isCallable(Context context, Intent intent) {
List<ResolveInfo> list = context.getPackageManager().queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
return list.size() > 0;
}
}
}
import android.content.ComponentName;
import android.content.Intent;
import java.util.Arrays;
import java.util.List;
public class Constants {
public static List<Intent> POWERMANAGER_INTENTS = Arrays.asList(
new Intent().setComponent(new ComponentName(\"com.miui.securitycenter\", \"com.miui.permcenter.autostart.AutoStartManagementActivity\")),
new Intent().setComponent(new ComponentName(\"com.letv.android.letvsafe\", \"com.letv.android.letvsafe.AutobootManageActivity\")),
new Intent().setComponent(new ComponentName(\"com.huawei.systemmanager\", \"com.huawei.systemmanager.optimize.process.ProtectActivity\")),
new Intent().setComponent(new ComponentName(\"com.coloros.safecenter\", \"com.coloros.safecenter.permission.startup.StartupAppListActivity\")),
new Intent().setComponent(new ComponentName(\"com.coloros.safecenter\", \"com.coloros.safecenter.startupapp.StartupAppListActivity\")),
new Intent().setComponent(new ComponentName(\"com.oppo.safe\", \"com.oppo.safe.permission.startup.StartupAppListActivity\")),
new Intent().setComponent(new ComponentName(\"com.iqoo.secure\", \"com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity\")),
new Intent().setComponent(new ComponentName(\"com.iqoo.secure\", \"com.iqoo.secure.ui.phoneoptimize.BgStartUpManager\")),
new Intent().setComponent(new ComponentName(\"com.vivo.permissionmanager\", \"com.vivo.permissionmanager.activity.BgStartUpManagerActivity\")),
new Intent().setComponent(new ComponentName(\"com.asus.mobilemanager\", \"com.asus.mobilemanager.entry.FunctionActivity\")).setData(android.net.Uri.parse(\"mobilemanager://function/entry/AutoStart\"))
);
}
}
I hope this helps someone.
+1 Aiuspaktyn for the java solution
Xamarin Solution
Usage:
MainActivity =>
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
MyUtils.IfHuaweiAlert(this);
}
public static void IfHuaweiAlert(Context context)
{
ISharedPreferences settings = context.GetSharedPreferences(\"ProtectedApps\", FileCreationMode.Private);
string saveIfSkip = \"skipProtectedAppsMessage\";
bool skipMessage = settings.GetBoolean(saveIfSkip, false);
if (!skipMessage)
{
ISharedPreferencesEditor editor = settings.Edit();
Intent intent = new Intent();
intent.SetClassName(\"com.huawei.systemmanager\", \"com.huawei.systemmanager.optimize.process.ProtectActivity\");
if (context.PackageManager.QueryIntentActivities(intent, PackageInfoFlags.MatchDefaultOnly).Count > 0)
{
var dontShowAgain = new Android.Support.V7.Widget.AppCompatCheckBox(context);
dontShowAgain.Text = \"Do not show again\";
dontShowAgain.CheckedChange += (object sender, CompoundButton.CheckedChangeEventArgs e) =>
{
editor.PutBoolean(saveIfSkip, e.IsChecked);
editor.Apply();
};
new AlertDialog.Builder(context)
.SetIcon(Android.Resource.Drawable.IcDialogAlert)
.SetTitle(\"Huawei Protected Apps\")
.SetMessage(string.Format(\"{0} requires to be enabled in \'Protected Apps\' to function properly.\\n\", context.GetString(Resource.String.app_name)))
.SetView(dontShowAgain)
.SetPositiveButton(\"Protected Apps\", (o, d) =>
{
try
{
string cmd = \"am start -n com.huawei.systemmanager/.optimize.process.ProtectActivity\";
if (Build.VERSION.SdkInt >= BuildVersionCodes.JellyBeanMr1)
{
try
{
UserManager um = (UserManager)context.GetSystemService(Context.UserService);
cmd += \" --user \" + um.GetSerialNumberForUser(Process.MyUserHandle());
}
catch { }
}
Java.Lang.Runtime.GetRuntime().Exec(cmd);
}
catch (Exception ignored)
{
}
})
.SetNegativeButton(Android.Resource.String.Cancel, (o, d) => { })
.Show();
}
else
{
editor.PutBoolean(saveIfSkip, true);
editor.Apply();
}
}
}
I still want to figure it out for the following (from here):
private static List<Intent> POWERMANAGER_INTENTS = new List<Intent>()
{
new Intent().SetComponent(new ComponentName(\"com.miui.securitycenter\", \"com.miui.permcenter.autostart.AutoStartManagementActivity\")),
new Intent().SetComponent(new ComponentName(\"com.letv.android.letvsafe\", \"com.letv.android.letvsafe.AutobootManageActivity\")),
new Intent().SetComponent(new ComponentName(\"com.huawei.systemmanager\", \"com.huawei.systemmanager.optimize.process.ProtectActivity\")),
new Intent().SetComponent(new ComponentName(\"com.coloros.safecenter\", \"com.coloros.safecenter.permission.startup.StartupAppListActivity\")),
new Intent().SetComponent(new ComponentName(\"com.coloros.safecenter\", \"com.coloros.safecenter.startupapp.StartupAppListActivity\")),
new Intent().SetComponent(new ComponentName(\"com.oppo.safe\", \"com.oppo.safe.permission.startup.StartupAppListActivity\")),
new Intent().SetComponent(new ComponentName(\"com.iqoo.secure\", \"com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity\")),
new Intent().SetComponent(new ComponentName(\"com.iqoo.secure\", \"com.iqoo.secure.ui.phoneoptimize.BgStartUpManager\")),
new Intent().SetComponent(new ComponentName(\"com.vivo.permissionmanager\", \"com.vivo.permissionmanager.activity.BgStartUpManagerActivity\")),
new Intent().SetComponent(new ComponentName(\"com.asus.mobilemanager\", \"com.asus.mobilemanager.entry.FunctionActivity\")).SetData(Android.Net.Uri.Parse(\"mobilemanager://function/entry/AutoStart\"))
};
/*
Should this method also run the command for the listed devices?
I do not have devices to test it with.
*/
public static void StartPowerSaverIntent(Context context)
{
foreach (Intent intent in POWERMANAGER_INTENTS)
{
if (context.PackageManager.ResolveActivity(intent, PackageInfoFlags.MatchDefaultOnly) != null)
{
context.StartActivity(intent);
break;
}
}
}
It would be nice to just run the following command, and everything is covered:
MyUtils.StartPowerSaverIntent(this);
EDIT:
This should do:
public class MyUtils
{
private static List<Intent> POWERMANAGER_INTENTS = new List<Intent>()
{
new Intent().SetComponent(new ComponentName(\"com.miui.securitycenter\", \"com.miui.permcenter.autostart.AutoStartManagementActivity\")),
new Intent().SetComponent(new ComponentName(\"com.letv.android.letvsafe\", \"com.letv.android.letvsafe.AutobootManageActivity\")),
new Intent().SetComponent(new ComponentName(\"com.huawei.systemmanager\", \"com.huawei.systemmanager.optimize.process.ProtectActivity\")),
new Intent().SetComponent(new ComponentName(\"com.coloros.safecenter\", \"com.coloros.safecenter.permission.startup.StartupAppListActivity\")),
new Intent().SetComponent(new ComponentName(\"com.coloros.safecenter\", \"com.coloros.safecenter.startupapp.StartupAppListActivity\")),
new Intent().SetComponent(new ComponentName(\"com.oppo.safe\", \"com.oppo.safe.permission.startup.StartupAppListActivity\")),
new Intent().SetComponent(new ComponentName(\"com.iqoo.secure\", \"com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity\")),
new Intent().SetComponent(new ComponentName(\"com.iqoo.secure\", \"com.iqoo.secure.ui.phoneoptimize.BgStartUpManager\")),
new Intent().SetComponent(new ComponentName(\"com.vivo.permissionmanager\", \"com.vivo.permissionmanager.activity.BgStartUpManagerActivity\")),
new Intent().SetComponent(new ComponentName(\"com.asus.mobilemanager\", \"com.asus.mobilemanager.entry.FunctionActivity\")).SetData(Android.Net.Uri.Parse(\"mobilemanager://function/entry/AutoStart\"))
};
public static void StartPowerSaverIntent(Context context)
{
ISharedPreferences settings = context.GetSharedPreferences(\"ProtectedApps\", FileCreationMode.Private);
bool skipMessage = settings.GetBoolean(\"skipAppListMessage\", false);
if (!skipMessage)
{
ISharedPreferencesEditor editor = settings.Edit();
foreach (Intent intent in POWERMANAGER_INTENTS)
{
if (context.PackageManager.ResolveActivity(intent, PackageInfoFlags.MatchDefaultOnly) != null)
{
var dontShowAgain = new Android.Support.V7.Widget.AppCompatCheckBox(context);
dontShowAgain.Text = \"Do not show again\";
dontShowAgain.CheckedChange += (object sender, CompoundButton.CheckedChangeEventArgs e) =>
{
editor.PutBoolean(\"skipAppListMessage\", e.IsChecked);
editor.Apply();
};
new AlertDialog.Builder(context)
.SetIcon(Android.Resource.Drawable.IcDialogAlert)
.SetTitle(string.Format(\"Add {0} to list\", context.GetString(Resource.String.app_name)))
.SetMessage(string.Format(\"{0} requires to be enabled/added in the list to function properly.\\n\", context.GetString(Resource.String.app_name)))
.SetView(dontShowAgain)
.SetPositiveButton(\"Go to settings\", (o, d) => context.StartActivity(intent))
.SetNegativeButton(Android.Resource.String.Cancel, (o, d) => { })
.Show();
break;
}
}
}
}
}
i have collected some intent from various post to check all producer:
How to start Power Manager of all android manufactures to enable push notification?
I\'m using @Aiuspaktyn solution which is missing the part of how to detect when stop show the dialog after the user set the app as protected. I\'m use a Service to check if the app was terminated or not, checking if it exists.
PowerMaster -> AutoStart ->Find your app in blocked section and allow