Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Protected Apps" setting on Huawei phones, and how to handle it

People also ask

What is the meaning of protected apps?

In short, to save battery power. To help users, on their Android 7-based smartphones (Android Nougat), Huawei had a feature called "Protected Apps" which allowed users and app developers to set certain apps as "protected" so that they can keep running in the background even when the screen is closed.

Where can I find protected apps on Android?

Scroll down and tap on Advanced settings. Tap on Battery Manager. Find Protected apps and select it. You can either Protect all apps or individually toggle each application to protect it from having background data restricted.


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) {
    try {
        if (intent == null || context == null) {
            return false;
        } else {
            List<ResolveInfo> list = context.getPackageManager().queryIntentActivities(intent,
                    PackageManager.MATCH_DEFAULT_ONLY);
            return list.size() > 0;
        }
    } catch (Exception ignored) {
        return false;
    }
}
}

}

import android.content.ComponentName;
import android.content.Intent;
import java.util.Arrays;
import java.util.List;

public class Constants {
//updated the POWERMANAGER_INTENTS 26/06/2019
static final 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.huawei.systemmanager", Build.VERSION.SDK_INT >= Build.VERSION_CODES.P? "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity": "com.huawei.systemmanager.appcontrol.activity.StartupAppControlActivity")),
        new Intent().setComponent(new ComponentName("com.coloros.oppoguardelf", "com.coloros.powermanager.fuelgaue.PowerUsageModelActivity")),
        new Intent().setComponent(new ComponentName("com.coloros.oppoguardelf", "com.coloros.powermanager.fuelgaue.PowerSaverModeActivity")),
        new Intent().setComponent(new ComponentName("com.coloros.oppoguardelf", "com.coloros.powermanager.fuelgaue.PowerConsumptionActivity")),
        new Intent().setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity")),
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? new Intent().setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.startupapp.StartupAppListActivity")).setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).setData(Uri.parse("package:"+ MyApplication.getContext().getPackageName())) : null,
        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")),
        new Intent().setComponent(new ComponentName("com.asus.mobilemanager", "com.asus.mobilemanager.autostart.AutoStartActivity")),
        new Intent().setComponent(new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity"))
                .setData(android.net.Uri.parse("mobilemanager://function/entry/AutoStart")),
        new Intent().setComponent(new ComponentName("com.meizu.safe", "com.meizu.safe.security.SHOW_APPSEC")).addCategory(Intent.CATEGORY_DEFAULT).putExtra("packageName", BuildConfig.APPLICATION_ID)
);
}

Add the following permissions in your Android.Manifest

<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<uses-permission android:name="oppo.permission.OPPO_COMPONENT_SAFE"/>
<uses-permission android:name="com.huawei.permission.external_app_settings.USE_COMPONENT"/>

  • I am still facing few issues with OPPO devices

I hope this helps someone.


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

Solution for all devices (Xamarin.Android)

Usage:

MainActivity =>
protected override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);

    MyUtils.StartPowerSaverIntent(this);
}

public class MyUtils
{
    private const string SKIP_INTENT_CHECK = "skipAppListMessage";

    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.appcontrol.activity.StartupAppControlActivity")),
        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.samsung.android.lool", "com.samsung.android.sm.ui.battery.BatteryActivity")),
        new Intent().SetComponent(new ComponentName("com.htc.pitroad", "com.htc.pitroad.landingpage.activity.LandingPageActivity")),
        new Intent().SetComponent(new ComponentName("com.asus.mobilemanager", "com.asus.mobilemanager.autostart.AutoStartActivity")),
        new Intent().SetComponent(new ComponentName("com.asus.mobilemanager", "com.asus.mobilemanager.entry.FunctionActivity")).SetData(Android.Net.Uri.Parse("mobilemanager://function/entry/AutoStart")),
        new Intent().SetComponent(new ComponentName("com.dewav.dwappmanager", "com.dewav.dwappmanager.memory.SmartClearupWhiteList"))
    };

    public static void StartPowerSaverIntent(Context context)
    {
        ISharedPreferences settings = context.GetSharedPreferences("ProtectedApps", FileCreationMode.Private);
        bool skipMessage = settings.GetBoolean(SKIP_INTENT_CHECK, false);
        if (!skipMessage)
        {
            bool HasIntent = false;
            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(SKIP_INTENT_CHECK, 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();

                    HasIntent = true;

                    break;
                }
            }

            if (!HasIntent)
            {
                editor.PutBoolean(SKIP_INTENT_CHECK, true);
                editor.Apply();
            }
        }
    }
}

Add the following permissions in your Android.Manifest

<uses-permission android:name="oppo.permission.OPPO_COMPONENT_SAFE"/>
<uses-permission android:name="com.huawei.permission.external_app_settings.USE_COMPONENT"/>

To help find the activity of the device not listed here, simply use the following method to help find the correct activity to open for the user

C#

public static void LogDeviceBrandActivities(Context context)
{
    var Brand = Android.OS.Build.Brand?.ToLower()?.Trim() ?? "";
    var Manufacturer = Android.OS.Build.Manufacturer?.ToLower()?.Trim() ?? "";

    var apps = context.PackageManager.GetInstalledPackages(PackageInfoFlags.Activities);

    foreach (PackageInfo pi in apps.OrderBy(n => n.PackageName))
    {
        if (pi.PackageName.ToLower().Contains(Brand) || pi.PackageName.ToLower().Contains(Manufacturer))
        {
            var print = false;
            var activityInfo = "";

            if (pi.Activities != null)
            {
                foreach (var activity in pi.Activities.OrderBy(n => n.Name))
                {
                    if (activity.Name.ToLower().Contains(Brand) || activity.Name.ToLower().Contains(Manufacturer))
                    {
                        activityInfo += "  Activity: " + activity.Name + (string.IsNullOrEmpty(activity.Permission) ? "" : " - Permission: " + activity.Permission) + "\n";
                        print = true;
                    }
                }
            }

            if (print)
            {
                Android.Util.Log.Error("brand.activities", "PackageName: " + pi.PackageName);
                Android.Util.Log.Warn("brand.activities", activityInfo);
            }
        }
    }
}

Java

public static void logDeviceBrandActivities(Context context) {
    String brand = Build.BRAND.toLowerCase();
    String manufacturer = Build.MANUFACTURER.toLowerCase();

    List<PackageInfo> apps = context.getPackageManager().getInstalledPackages(PackageManager.GET_ACTIVITIES);

    Collections.sort(apps, (a, b) -> a.packageName.compareTo(b.packageName));
    for (PackageInfo pi : apps) {
        if (pi.packageName.toLowerCase().contains(brand) || pi.packageName.toLowerCase().contains(manufacturer)) {
            boolean print = false;
            StringBuilder activityInfo = new StringBuilder();

            if (pi.activities != null && pi.activities.length > 0) {
                List<ActivityInfo> activities = Arrays.asList(pi.activities);

                Collections.sort(activities, (a, b) -> a.name.compareTo(b.name));
                for (ActivityInfo ai : activities) {
                    if (ai.name.toLowerCase().contains(brand) || ai.name.toLowerCase().contains(manufacturer)) {
                        activityInfo.append("  Activity: ").append(ai.name)
                                .append(ai.permission == null || ai.permission.length() == 0 ? "" : " - Permission: " + ai.permission)
                                .append("\n");
                        print = true;
                    }
                }
            }

            if (print) {
                Log.e("brand.activities", "PackageName: " + pi.packageName);
                Log.w("brand.activities", activityInfo.toString());
            }
        }
    }
}

Execute on startup and search through the log file, add a logcat filter on TAG of brand.activities

MainActivity =>
protected override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);

    MyUtils.LogDeviceBrandActivities(this);
}

Sample Output:

E/brand.activities: PackageName: com.samsung.android.lool
W/brand.activities: ...
W/brand.activities:   Activity: com.samsung.android.sm.ui.battery.AppSleepSettingActivity
W/brand.activities:   Activity: com.samsung.android.sm.ui.battery.BatteryActivity <-- This is the one...
W/brand.activities:   Activity: com.samsung.android.sm.ui.battery.BatteryActivityForCard
W/brand.activities: ...

So the component name will be:

new ComponentName("<PackageName>", "<Activity>")
new ComponentName("com.samsung.android.lool", "com.samsung.android.sm.ui.battery.BatteryActivity")

If the activity has a permission next to it, the following entry in the Android.Manifest is required to open the activity:

<uses-permission android:name="<permission>" />

Comment or edit the new component into this answer. All help will me much appreciated.


You can use this library to navigate the user to protected apps or autostart:

AutoStarter

If the phone supports autostart feature you can show to the user a hint to enable your app in these apps

You can check by this method:

AutoStartPermissionHelper.getInstance().isAutoStartPermissionAvailable(context)

And for navigating the user to that page, simply call this:

AutoStartPermissionHelper.getInstance().getAutoStartPermission(context)