1 /* 2 * Copyright (C) 2018 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 android.app.settings.SettingsEnums; 20 import android.content.Context; 21 import android.content.pm.ApplicationInfo; 22 import android.content.pm.PackageManager; 23 import android.os.Bundle; 24 import android.os.UserHandle; 25 import android.util.IconDrawableFactory; 26 import android.util.Log; 27 import android.util.SparseLongArray; 28 29 import androidx.annotation.VisibleForTesting; 30 import androidx.preference.CheckBoxPreference; 31 import androidx.preference.Preference; 32 import androidx.preference.PreferenceGroup; 33 34 import com.android.settings.R; 35 import com.android.settings.Utils; 36 import com.android.settings.core.InstrumentedPreferenceFragment; 37 import com.android.settings.core.SubSettingLauncher; 38 import com.android.settings.dashboard.DashboardFragment; 39 import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper; 40 import com.android.settings.fuelgauge.batterytip.AppInfo; 41 import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager; 42 import com.android.settings.fuelgauge.batterytip.BatteryTipDialogFragment; 43 import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController; 44 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; 45 import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip; 46 import com.android.settings.fuelgauge.batterytip.tips.UnrestrictAppTip; 47 import com.android.settings.overlay.FeatureFactory; 48 import com.android.settings.widget.AppCheckBoxPreference; 49 import com.android.settingslib.core.AbstractPreferenceController; 50 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; 51 import com.android.settingslib.utils.StringUtil; 52 53 import java.util.List; 54 55 /** 56 * Fragment to show a list of anomaly apps, where user could handle these anomalies 57 */ 58 public class RestrictedAppDetails extends DashboardFragment implements 59 BatteryTipPreferenceController.BatteryTipListener { 60 61 public static final String TAG = "RestrictedAppDetails"; 62 63 @VisibleForTesting 64 static final String EXTRA_APP_INFO_LIST = "app_info_list"; 65 private static final String KEY_PREF_RESTRICTED_APP_LIST = "restrict_app_list"; 66 private static final long TIME_NULL = -1; 67 68 @VisibleForTesting 69 List<AppInfo> mAppInfos; 70 @VisibleForTesting 71 IconDrawableFactory mIconDrawableFactory; 72 @VisibleForTesting 73 PreferenceGroup mRestrictedAppListGroup; 74 @VisibleForTesting 75 BatteryUtils mBatteryUtils; 76 @VisibleForTesting 77 PackageManager mPackageManager; 78 @VisibleForTesting 79 BatteryDatabaseManager mBatteryDatabaseManager; 80 81 private MetricsFeatureProvider mMetricsFeatureProvider; 82 startRestrictedAppDetails(InstrumentedPreferenceFragment fragment, List<AppInfo> appInfos)83 public static void startRestrictedAppDetails(InstrumentedPreferenceFragment fragment, 84 List<AppInfo> appInfos) { 85 final Bundle args = new Bundle(); 86 args.putParcelableList(EXTRA_APP_INFO_LIST, appInfos); 87 88 new SubSettingLauncher(fragment.getContext()) 89 .setDestination(RestrictedAppDetails.class.getName()) 90 .setArguments(args) 91 .setTitleRes(R.string.restricted_app_title) 92 .setSourceMetricsCategory(fragment.getMetricsCategory()) 93 .launch(); 94 } 95 96 @Override onCreate(Bundle icicle)97 public void onCreate(Bundle icicle) { 98 super.onCreate(icicle); 99 final Context context = getContext(); 100 101 mRestrictedAppListGroup = (PreferenceGroup) findPreference(KEY_PREF_RESTRICTED_APP_LIST); 102 mAppInfos = getArguments().getParcelableArrayList(EXTRA_APP_INFO_LIST); 103 mPackageManager = context.getPackageManager(); 104 mIconDrawableFactory = IconDrawableFactory.newInstance(context); 105 mBatteryUtils = BatteryUtils.getInstance(context); 106 mBatteryDatabaseManager = BatteryDatabaseManager.getInstance(context); 107 mMetricsFeatureProvider = 108 FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider(); 109 refreshUi(); 110 } 111 112 @Override onPreferenceTreeClick(Preference preference)113 public boolean onPreferenceTreeClick(Preference preference) { 114 115 return super.onPreferenceTreeClick(preference); 116 } 117 118 @Override getLogTag()119 protected String getLogTag() { 120 return TAG; 121 } 122 123 @Override getPreferenceScreenResId()124 protected int getPreferenceScreenResId() { 125 return R.xml.restricted_apps_detail; 126 } 127 128 @Override createPreferenceControllers(Context context)129 protected List<AbstractPreferenceController> createPreferenceControllers(Context context) { 130 return null; 131 } 132 133 @Override getMetricsCategory()134 public int getMetricsCategory() { 135 return SettingsEnums.FUELGAUGE_RESTRICTED_APP_DETAILS; 136 } 137 138 @Override getHelpResource()139 public int getHelpResource() { 140 return R.string.help_uri_restricted_apps; 141 } 142 143 @VisibleForTesting refreshUi()144 void refreshUi() { 145 mRestrictedAppListGroup.removeAll(); 146 final Context context = getPrefContext(); 147 final SparseLongArray timestampArray = mBatteryDatabaseManager 148 .queryActionTime(AnomalyDatabaseHelper.ActionType.RESTRICTION); 149 final long now = System.currentTimeMillis(); 150 151 for (int i = 0, size = mAppInfos.size(); i < size; i++) { 152 final CheckBoxPreference checkBoxPreference = new AppCheckBoxPreference(context); 153 final AppInfo appInfo = mAppInfos.get(i); 154 try { 155 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfoAsUser( 156 appInfo.packageName, 0 /* flags */, UserHandle.getUserId(appInfo.uid)); 157 checkBoxPreference.setChecked( 158 mBatteryUtils.isForceAppStandbyEnabled(appInfo.uid, appInfo.packageName)); 159 checkBoxPreference.setTitle(mPackageManager.getApplicationLabel(applicationInfo)); 160 checkBoxPreference.setIcon( 161 Utils.getBadgedIcon(mIconDrawableFactory, mPackageManager, 162 appInfo.packageName, 163 UserHandle.getUserId(appInfo.uid))); 164 checkBoxPreference.setKey(getKeyFromAppInfo(appInfo)); 165 checkBoxPreference.setOnPreferenceChangeListener((pref, value) -> { 166 final BatteryTipDialogFragment fragment = createDialogFragment(appInfo, 167 (Boolean) value); 168 fragment.setTargetFragment(this, 0 /* requestCode */); 169 fragment.show(getFragmentManager(), TAG); 170 mMetricsFeatureProvider.action(getContext(), 171 SettingsEnums.ACTION_APP_RESTRICTED_LIST_UNCHECKED, 172 appInfo.packageName); 173 return false; 174 }); 175 176 final long timestamp = timestampArray.get(appInfo.uid, TIME_NULL); 177 if (timestamp != TIME_NULL) { 178 checkBoxPreference.setSummary(getString(R.string.restricted_app_time_summary, 179 StringUtil.formatRelativeTime(context, now - timestamp, false))); 180 } 181 final CharSequence test = checkBoxPreference.getSummaryOn(); 182 mRestrictedAppListGroup.addPreference(checkBoxPreference); 183 } catch (PackageManager.NameNotFoundException e) { 184 Log.e(TAG, "Can't find package: " + appInfo.packageName); 185 } 186 } 187 } 188 189 @Override onBatteryTipHandled(BatteryTip batteryTip)190 public void onBatteryTipHandled(BatteryTip batteryTip) { 191 final AppInfo appInfo; 192 final boolean isRestricted = batteryTip instanceof RestrictAppTip; 193 if (isRestricted) { 194 appInfo = ((RestrictAppTip) batteryTip).getRestrictAppList().get(0); 195 } else { 196 appInfo = ((UnrestrictAppTip) batteryTip).getUnrestrictAppInfo(); 197 } 198 199 CheckBoxPreference preference = (CheckBoxPreference) mRestrictedAppListGroup 200 .findPreference(getKeyFromAppInfo(appInfo)); 201 if (preference != null) { 202 preference.setChecked(isRestricted); 203 } 204 } 205 206 @VisibleForTesting createDialogFragment(AppInfo appInfo, boolean toRestrict)207 BatteryTipDialogFragment createDialogFragment(AppInfo appInfo, boolean toRestrict) { 208 final BatteryTip batteryTip = toRestrict 209 ? new RestrictAppTip(BatteryTip.StateType.NEW, appInfo) 210 : new UnrestrictAppTip(BatteryTip.StateType.NEW, appInfo); 211 212 return BatteryTipDialogFragment.newInstance( 213 batteryTip, getMetricsCategory()); 214 } 215 216 @VisibleForTesting getKeyFromAppInfo(AppInfo appInfo)217 String getKeyFromAppInfo(AppInfo appInfo) { 218 return appInfo.uid + "," + appInfo.packageName; 219 } 220 } 221