1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.fuelgauge; 18 19 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE; 20 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED; 21 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT; 22 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER; 23 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE; 24 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RESTRICTED; 25 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET; 26 27 import android.app.settings.SettingsEnums; 28 import android.app.usage.UsageStatsManager; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.content.pm.PackageManager; 32 import android.content.pm.ResolveInfo; 33 import android.content.res.Resources; 34 import android.os.Bundle; 35 import android.text.TextUtils; 36 37 import androidx.preference.ListPreference; 38 import androidx.preference.Preference; 39 import androidx.preference.PreferenceGroup; 40 41 import com.android.settings.R; 42 import com.android.settings.SettingsPreferenceFragment; 43 44 import java.util.Arrays; 45 import java.util.List; 46 47 public class InactiveApps extends SettingsPreferenceFragment 48 implements Preference.OnPreferenceChangeListener { 49 50 private static final CharSequence[] FULL_SETTABLE_BUCKETS_NAMES = 51 {"ACTIVE", "WORKING_SET", "FREQUENT", "RARE", "RESTRICTED"}; 52 53 private static final CharSequence[] FULL_SETTABLE_BUCKETS_VALUES = { 54 Integer.toString(STANDBY_BUCKET_ACTIVE), 55 Integer.toString(STANDBY_BUCKET_WORKING_SET), 56 Integer.toString(STANDBY_BUCKET_FREQUENT), 57 Integer.toString(STANDBY_BUCKET_RARE), 58 Integer.toString(STANDBY_BUCKET_RESTRICTED) 59 }; 60 61 private UsageStatsManager mUsageStats; 62 63 @Override getMetricsCategory()64 public int getMetricsCategory() { 65 return SettingsEnums.FUELGAUGE_INACTIVE_APPS; 66 } 67 68 @Override onCreate(Bundle icicle)69 public void onCreate(Bundle icicle) { 70 super.onCreate(icicle); 71 72 mUsageStats = getActivity().getSystemService(UsageStatsManager.class); 73 addPreferencesFromResource(R.xml.placeholder_preference_screen); 74 getActivity().setTitle(R.string.inactive_apps_title); 75 } 76 77 @Override onResume()78 public void onResume() { 79 super.onResume(); 80 init(); 81 } 82 init()83 private void init() { 84 PreferenceGroup screen = getPreferenceScreen(); 85 screen.removeAll(); 86 screen.setOrderingAsAdded(false); 87 final Context context = getActivity(); 88 final PackageManager pm = context.getPackageManager(); 89 final String settingsPackage = context.getPackageName(); 90 final CharSequence[] bucketNames = FULL_SETTABLE_BUCKETS_NAMES; 91 final CharSequence[] bucketValues = FULL_SETTABLE_BUCKETS_VALUES; 92 93 Intent launcherIntent = new Intent(Intent.ACTION_MAIN); 94 launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER); 95 List<ResolveInfo> apps = pm.queryIntentActivities(launcherIntent, 0); 96 for (ResolveInfo app : apps) { 97 String packageName = app.activityInfo.applicationInfo.packageName; 98 ListPreference p = new ListPreference(getPrefContext()); 99 p.setTitle(app.loadLabel(pm)); 100 p.setIcon(app.loadIcon(pm)); 101 p.setKey(packageName); 102 p.setEntries(getAllowableBuckets(packageName, bucketNames)); 103 p.setEntryValues(getAllowableBuckets(packageName, bucketValues)); 104 updateSummary(p); 105 // Don't allow Settings to change its own standby bucket. 106 if (TextUtils.equals(packageName, settingsPackage)) { 107 p.setEnabled(false); 108 } 109 p.setOnPreferenceChangeListener(this); 110 111 screen.addPreference(p); 112 } 113 } 114 getAllowableBuckets(String packageName, CharSequence[] possibleBuckets)115 private CharSequence[] getAllowableBuckets(String packageName, CharSequence[] possibleBuckets) { 116 final int minBucket = mUsageStats.getAppMinStandbyBucket(packageName); 117 if (minBucket > STANDBY_BUCKET_RESTRICTED) { 118 return possibleBuckets; 119 } 120 if (minBucket < STANDBY_BUCKET_ACTIVE) { 121 return new CharSequence[]{}; 122 } 123 // Use FULL_SETTABLE_BUCKETS_VALUES since we're searching using the int value. The index 124 // should apply no matter which array we're going to copy from. 125 final int idx = 126 Arrays.binarySearch(FULL_SETTABLE_BUCKETS_VALUES, Integer.toString(minBucket)); 127 if (idx < 0) { 128 // Include everything 129 return possibleBuckets; 130 } 131 return Arrays.copyOfRange(possibleBuckets, 0, idx + 1); 132 } 133 bucketToName(int bucket)134 static String bucketToName(int bucket) { 135 switch (bucket) { 136 case STANDBY_BUCKET_EXEMPTED: return "EXEMPTED"; 137 case STANDBY_BUCKET_ACTIVE: return "ACTIVE"; 138 case STANDBY_BUCKET_WORKING_SET: return "WORKING_SET"; 139 case STANDBY_BUCKET_FREQUENT: return "FREQUENT"; 140 case STANDBY_BUCKET_RARE: return "RARE"; 141 case STANDBY_BUCKET_RESTRICTED: return "RESTRICTED"; 142 case STANDBY_BUCKET_NEVER: return "NEVER"; 143 } 144 return ""; 145 } 146 updateSummary(ListPreference p)147 private void updateSummary(ListPreference p) { 148 final Resources res = getActivity().getResources(); 149 final int appBucket = mUsageStats.getAppStandbyBucket(p.getKey()); 150 final String bucketName = bucketToName(appBucket); 151 p.setSummary(res.getString(R.string.standby_bucket_summary, bucketName)); 152 // Buckets outside of the range of the dynamic ones are only used for special 153 // purposes and can either not be changed out of, or might have undesirable 154 // side-effects in combination with other assumptions. 155 final boolean changeable = appBucket >= STANDBY_BUCKET_ACTIVE 156 && appBucket <= STANDBY_BUCKET_RESTRICTED; 157 if (changeable) { 158 p.setValue(Integer.toString(appBucket)); 159 } 160 p.setEnabled(changeable); 161 } 162 163 @Override onPreferenceChange(Preference preference, Object newValue)164 public boolean onPreferenceChange(Preference preference, Object newValue) { 165 mUsageStats.setAppStandbyBucket(preference.getKey(), Integer.parseInt((String) newValue)); 166 updateSummary((ListPreference) preference); 167 return false; 168 } 169 } 170