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

后端 未结 7 1457
-上瘾入骨i
-上瘾入骨i 2020-11-22 09:48

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 t

相关标签:
7条回答
  • 2020-11-22 10:04
    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();
        }
    
    0 讨论(0)
  • 2020-11-22 10:07

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

    0 讨论(0)
  • 2020-11-22 10:20

    PowerMaster -> AutoStart ->Find your app in blocked section and allow

    0 讨论(0)
  • 2020-11-22 10:26

    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 "";
    }
    
    0 讨论(0)
  • 2020-11-22 10:26

    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.

    0 讨论(0)
  • 2020-11-22 10:31

    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.

    0 讨论(0)
提交回复
热议问题