Home | History | Annotate | Download | only in fuelgauge
      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