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.content.Context; 19 import android.content.pm.ApplicationInfo; 20 import android.content.pm.PackageManager; 21 import android.os.Build; 22 import android.support.annotation.VisibleForTesting; 23 import android.support.v14.preference.SwitchPreference; 24 import android.support.v7.preference.Preference; 25 import android.util.Log; 26 27 import com.android.settings.R; 28 import com.android.settings.core.PreferenceController; 29 30 /** 31 * Controller to control whether an app can run in the background 32 */ 33 public class BackgroundActivityPreferenceController extends PreferenceController implements 34 Preference.OnPreferenceChangeListener { 35 36 private static final String TAG = "BgActivityPrefContr"; 37 private static final String KEY_BACKGROUND_ACTIVITY = "background_activity"; 38 39 private final PackageManager mPackageManager; 40 private final AppOpsManager mAppOpsManager; 41 private final String[] mPackages; 42 private final int mUid; 43 44 private String mTargetPackage; 45 46 public BackgroundActivityPreferenceController(Context context, int uid) { 47 super(context); 48 mPackageManager = context.getPackageManager(); 49 mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 50 mUid = uid; 51 mPackages = mPackageManager.getPackagesForUid(mUid); 52 } 53 54 @Override 55 public void updateState(Preference preference) { 56 final int mode = mAppOpsManager 57 .checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, mUid, mTargetPackage); 58 if (mode == AppOpsManager.MODE_ERRORED) { 59 preference.setEnabled(false); 60 } else { 61 final boolean checked = mode != AppOpsManager.MODE_IGNORED; 62 ((SwitchPreference) preference).setChecked(checked); 63 } 64 65 updateSummary(preference); 66 } 67 68 @Override 69 public boolean isAvailable() { 70 if (mPackages == null) { 71 return false; 72 } 73 for (final String packageName : mPackages) { 74 if (isLegacyApp(packageName)) { 75 mTargetPackage = packageName; 76 return true; 77 } 78 } 79 80 return false; 81 } 82 83 @Override 84 public String getPreferenceKey() { 85 return KEY_BACKGROUND_ACTIVITY; 86 } 87 88 @Override 89 public boolean onPreferenceChange(Preference preference, Object newValue) { 90 boolean switchOn = (Boolean) newValue; 91 mAppOpsManager.setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, mUid, mTargetPackage, 92 switchOn ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED); 93 94 updateSummary(preference); 95 return true; 96 } 97 98 @VisibleForTesting 99 String getTargetPackage() { 100 return mTargetPackage; 101 } 102 103 @VisibleForTesting 104 boolean isLegacyApp(final String packageName) { 105 try { 106 ApplicationInfo info = mPackageManager.getApplicationInfo(packageName, 107 PackageManager.GET_META_DATA); 108 109 return info.targetSdkVersion < Build.VERSION_CODES.O; 110 } catch (PackageManager.NameNotFoundException e) { 111 Log.e(TAG, "Cannot find package: " + packageName, e); 112 } 113 114 return false; 115 } 116 117 @VisibleForTesting 118 void updateSummary(Preference preference) { 119 final int mode = mAppOpsManager 120 .checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, mUid, mTargetPackage); 121 122 if (mode == AppOpsManager.MODE_ERRORED) { 123 preference.setSummary(R.string.background_activity_summary_disabled); 124 } else { 125 final boolean checked = mode != AppOpsManager.MODE_IGNORED; 126 preference.setSummary(checked ? R.string.background_activity_summary_on 127 : R.string.background_activity_summary_off); 128 } 129 } 130 } 131