1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15 package com.android.settings.fuelgauge; 16 17 import android.app.AppOpsManager; 18 import android.app.admin.DevicePolicyManager; 19 import android.content.Context; 20 import android.os.UserManager; 21 import android.support.annotation.VisibleForTesting; 22 import android.support.v7.preference.Preference; 23 24 import com.android.settings.R; 25 import com.android.settings.Utils; 26 import com.android.settings.core.InstrumentedPreferenceFragment; 27 import com.android.settings.core.PreferenceControllerMixin; 28 import com.android.settings.fuelgauge.batterytip.AppInfo; 29 import com.android.settings.fuelgauge.batterytip.BatteryTipDialogFragment; 30 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; 31 import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip; 32 import com.android.settings.fuelgauge.batterytip.tips.UnrestrictAppTip; 33 import com.android.settingslib.core.AbstractPreferenceController; 34 import com.android.settingslib.fuelgauge.PowerWhitelistBackend; 35 36 /** 37 * Controller to control whether an app can run in the background 38 */ 39 public class BackgroundActivityPreferenceController extends AbstractPreferenceController 40 implements PreferenceControllerMixin { 41 42 private static final String TAG = "BgActivityPrefContr"; 43 @VisibleForTesting 44 static final String KEY_BACKGROUND_ACTIVITY = "background_activity"; 45 46 private final AppOpsManager mAppOpsManager; 47 private final UserManager mUserManager; 48 private final int mUid; 49 @VisibleForTesting 50 DevicePolicyManager mDpm; 51 @VisibleForTesting 52 BatteryUtils mBatteryUtils; 53 private InstrumentedPreferenceFragment mFragment; 54 private String mTargetPackage; 55 private PowerWhitelistBackend mPowerWhitelistBackend; 56 57 public BackgroundActivityPreferenceController(Context context, 58 InstrumentedPreferenceFragment fragment, int uid, String packageName) { 59 this(context, fragment, uid, packageName, PowerWhitelistBackend.getInstance(context)); 60 } 61 62 @VisibleForTesting 63 BackgroundActivityPreferenceController(Context context, InstrumentedPreferenceFragment fragment, 64 int uid, String packageName, PowerWhitelistBackend backend) { 65 super(context); 66 mPowerWhitelistBackend = backend; 67 mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 68 mDpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); 69 mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 70 mUid = uid; 71 mFragment = fragment; 72 mTargetPackage = packageName; 73 mBatteryUtils = BatteryUtils.getInstance(context); 74 } 75 76 @Override 77 public void updateState(Preference preference) { 78 final int mode = mAppOpsManager 79 .checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mTargetPackage); 80 final boolean whitelisted = mPowerWhitelistBackend.isWhitelisted(mTargetPackage); 81 if (whitelisted || mode == AppOpsManager.MODE_ERRORED 82 || Utils.isProfileOrDeviceOwner(mUserManager, mDpm, mTargetPackage)) { 83 preference.setEnabled(false); 84 } else { 85 preference.setEnabled(true); 86 } 87 updateSummary(preference); 88 } 89 90 @Override 91 public boolean isAvailable() { 92 return mTargetPackage != null; 93 } 94 95 @Override 96 public String getPreferenceKey() { 97 return KEY_BACKGROUND_ACTIVITY; 98 } 99 100 @Override 101 public boolean handlePreferenceTreeClick(Preference preference) { 102 if (KEY_BACKGROUND_ACTIVITY.equals(preference.getKey())) { 103 final int mode = mAppOpsManager 104 .checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mTargetPackage); 105 final boolean restricted = mode == AppOpsManager.MODE_IGNORED; 106 showDialog(restricted); 107 } 108 109 return false; 110 } 111 112 public void updateSummary(Preference preference) { 113 if (mPowerWhitelistBackend.isWhitelisted(mTargetPackage)) { 114 preference.setSummary(R.string.background_activity_summary_whitelisted); 115 return; 116 } 117 final int mode = mAppOpsManager 118 .checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mTargetPackage); 119 120 if (mode == AppOpsManager.MODE_ERRORED) { 121 preference.setSummary(R.string.background_activity_summary_disabled); 122 } else { 123 final boolean restricted = mode == AppOpsManager.MODE_IGNORED; 124 preference.setSummary(restricted ? R.string.restricted_true_label 125 : R.string.restricted_false_label); 126 } 127 } 128 129 @VisibleForTesting 130 void showDialog(boolean restricted) { 131 final AppInfo appInfo = new AppInfo.Builder() 132 .setUid(mUid) 133 .setPackageName(mTargetPackage) 134 .build(); 135 BatteryTip tip = restricted 136 ? new UnrestrictAppTip(BatteryTip.StateType.NEW, appInfo) 137 : new RestrictAppTip(BatteryTip.StateType.NEW, appInfo); 138 139 final BatteryTipDialogFragment dialogFragment = BatteryTipDialogFragment.newInstance(tip, 140 mFragment.getMetricsCategory()); 141 dialogFragment.setTargetFragment(mFragment, 0 /* requestCode */); 142 dialogFragment.show(mFragment.getFragmentManager(), TAG); 143 } 144 } 145