1 /* 2 * Copyright (C) 2023 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.batteryusage; 18 19 import android.content.Context; 20 import android.os.Bundle; 21 import android.provider.Settings; 22 import android.text.TextUtils; 23 import android.util.Log; 24 import android.util.Pair; 25 26 import androidx.annotation.Nullable; 27 28 import com.android.settings.R; 29 import com.android.settings.SettingsActivity; 30 import com.android.settings.core.SubSettingLauncher; 31 32 import java.util.function.Function; 33 34 final class AnomalyEventWrapper { 35 private static final String TAG = "AnomalyEventWrapper"; 36 37 private final Context mContext; 38 private final PowerAnomalyEvent mPowerAnomalyEvent; 39 40 private final int mCardStyleId; 41 private final int mResourceIndex; 42 43 private SubSettingLauncher mSubSettingLauncher = null; 44 private Pair<Integer, Integer> mHighlightSlotPair = null; 45 private BatteryDiffEntry mRelatedBatteryDiffEntry = null; 46 AnomalyEventWrapper(Context context, PowerAnomalyEvent powerAnomalyEvent)47 AnomalyEventWrapper(Context context, PowerAnomalyEvent powerAnomalyEvent) { 48 mContext = context; 49 mPowerAnomalyEvent = powerAnomalyEvent; 50 // Set basic battery tips card info 51 mCardStyleId = mPowerAnomalyEvent.getType().getNumber(); 52 mResourceIndex = mPowerAnomalyEvent.getKey().getNumber(); 53 } 54 getInfo( @ullable Function<WarningBannerInfo, T> warningBannerInfoSupplier, @Nullable Function<WarningItemInfo, T> warningItemInfoSupplier)55 private <T> T getInfo( 56 @Nullable Function<WarningBannerInfo, T> warningBannerInfoSupplier, 57 @Nullable Function<WarningItemInfo, T> warningItemInfoSupplier) { 58 if (warningBannerInfoSupplier != null && mPowerAnomalyEvent.hasWarningBannerInfo()) { 59 return warningBannerInfoSupplier.apply(mPowerAnomalyEvent.getWarningBannerInfo()); 60 } else if (warningItemInfoSupplier != null && mPowerAnomalyEvent.hasWarningItemInfo()) { 61 return warningItemInfoSupplier.apply(mPowerAnomalyEvent.getWarningItemInfo()); 62 } 63 return null; 64 } 65 getResourceId(int resourceId, int resourceIndex, String defType)66 private int getResourceId(int resourceId, int resourceIndex, String defType) { 67 final String key = getStringFromArrayResource(resourceId, resourceIndex); 68 return TextUtils.isEmpty(key) 69 ? 0 70 : mContext.getResources().getIdentifier(key, defType, mContext.getPackageName()); 71 } 72 getString( Function<WarningBannerInfo, String> warningBannerInfoSupplier, Function<WarningItemInfo, String> warningItemInfoSupplier, int resourceId, int resourceIndex)73 private String getString( 74 Function<WarningBannerInfo, String> warningBannerInfoSupplier, 75 Function<WarningItemInfo, String> warningItemInfoSupplier, 76 int resourceId, 77 int resourceIndex) { 78 final String string = getInfo(warningBannerInfoSupplier, warningItemInfoSupplier); 79 return (!TextUtils.isEmpty(string) || resourceId <= 0) 80 ? string 81 : getStringFromArrayResource(resourceId, resourceIndex); 82 } 83 getStringFromArrayResource(int resourceId, int resourceIndex)84 private String getStringFromArrayResource(int resourceId, int resourceIndex) { 85 if (resourceId <= 0 || resourceIndex < 0) { 86 return null; 87 } 88 final String[] stringArray = mContext.getResources().getStringArray(resourceId); 89 return (resourceIndex >= 0 && resourceIndex < stringArray.length) 90 ? stringArray[resourceIndex] 91 : null; 92 } 93 setRelatedBatteryDiffEntry(BatteryDiffEntry batteryDiffEntry)94 void setRelatedBatteryDiffEntry(BatteryDiffEntry batteryDiffEntry) { 95 mRelatedBatteryDiffEntry = batteryDiffEntry; 96 } 97 getAnomalyKeyNumber()98 int getAnomalyKeyNumber() { 99 return mPowerAnomalyEvent.getKey().getNumber(); 100 } 101 getEventId()102 String getEventId() { 103 return mPowerAnomalyEvent.hasEventId() ? mPowerAnomalyEvent.getEventId() : null; 104 } 105 getIconResId()106 int getIconResId() { 107 return getResourceId(R.array.battery_tips_card_icons, mCardStyleId, "drawable"); 108 } 109 getColorResId()110 int getColorResId() { 111 return getResourceId(R.array.battery_tips_card_colors, mCardStyleId, "color"); 112 } 113 getTitleString()114 String getTitleString() { 115 final String titleStringFromProto = 116 getInfo(WarningBannerInfo::getTitleString, WarningItemInfo::getTitleString); 117 if (!TextUtils.isEmpty(titleStringFromProto)) { 118 return titleStringFromProto; 119 } 120 final int titleFormatResId = 121 getResourceId(R.array.power_anomaly_title_ids, mResourceIndex, "string"); 122 if (mPowerAnomalyEvent.hasWarningBannerInfo()) { 123 return mContext.getString(titleFormatResId); 124 } else if (mPowerAnomalyEvent.hasWarningItemInfo() && mRelatedBatteryDiffEntry != null) { 125 final String appLabel = mRelatedBatteryDiffEntry.getAppLabel(); 126 return mContext.getString(titleFormatResId, appLabel); 127 } 128 return null; 129 } 130 getMainBtnString()131 String getMainBtnString() { 132 return getString( 133 WarningBannerInfo::getMainButtonString, 134 WarningItemInfo::getMainButtonString, 135 R.array.power_anomaly_main_btn_strings, 136 mResourceIndex); 137 } 138 getDismissBtnString()139 String getDismissBtnString() { 140 return getString( 141 WarningBannerInfo::getCancelButtonString, 142 WarningItemInfo::getCancelButtonString, 143 R.array.power_anomaly_dismiss_btn_strings, 144 mResourceIndex); 145 } 146 getAnomalyHintString()147 String getAnomalyHintString() { 148 final String anomalyHintStringFromProto = 149 getInfo(null, WarningItemInfo::getWarningInfoString); 150 return TextUtils.isEmpty(anomalyHintStringFromProto) 151 ? getStringFromArrayResource(R.array.power_anomaly_hint_messages, mResourceIndex) 152 : anomalyHintStringFromProto; 153 } 154 getAnomalyHintPrefKey()155 String getAnomalyHintPrefKey() { 156 return getInfo(null, WarningItemInfo::getAnomalyHintPrefKey); 157 } 158 getDismissRecordKey()159 String getDismissRecordKey() { 160 return mPowerAnomalyEvent.getDismissRecordKey(); 161 } 162 hasAnomalyEntryKey()163 boolean hasAnomalyEntryKey() { 164 return getAnomalyEntryKey() != null; 165 } 166 getAnomalyEntryKey()167 String getAnomalyEntryKey() { 168 return mPowerAnomalyEvent.hasWarningItemInfo() 169 && mPowerAnomalyEvent.getWarningItemInfo().hasItemKey() 170 ? mPowerAnomalyEvent.getWarningItemInfo().getItemKey() 171 : null; 172 } 173 hasSubSettingLauncher()174 boolean hasSubSettingLauncher() { 175 if (mSubSettingLauncher == null) { 176 mSubSettingLauncher = getSubSettingLauncher(); 177 } 178 return mSubSettingLauncher != null; 179 } 180 getSubSettingLauncher()181 SubSettingLauncher getSubSettingLauncher() { 182 if (mSubSettingLauncher != null) { 183 return mSubSettingLauncher; 184 } 185 final String destinationClassName = 186 getInfo(WarningBannerInfo::getMainButtonDestination, null); 187 if (!TextUtils.isEmpty(destinationClassName)) { 188 final Integer sourceMetricsCategory = 189 getInfo(WarningBannerInfo::getMainButtonSourceMetricsCategory, null); 190 final String preferenceHighlightKey = 191 getInfo(WarningBannerInfo::getMainButtonSourceHighlightKey, null); 192 Bundle arguments = Bundle.EMPTY; 193 if (!TextUtils.isEmpty(preferenceHighlightKey)) { 194 arguments = new Bundle(1); 195 arguments.putString( 196 SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, preferenceHighlightKey); 197 } 198 mSubSettingLauncher = 199 new SubSettingLauncher(mContext) 200 .setDestination(destinationClassName) 201 .setSourceMetricsCategory(sourceMetricsCategory) 202 .setArguments(arguments); 203 } 204 return mSubSettingLauncher; 205 } 206 hasHighlightSlotPair(BatteryLevelData batteryLevelData)207 boolean hasHighlightSlotPair(BatteryLevelData batteryLevelData) { 208 if (mHighlightSlotPair == null) { 209 mHighlightSlotPair = getHighlightSlotPair(batteryLevelData); 210 } 211 return mHighlightSlotPair != null; 212 } 213 getHighlightSlotPair(BatteryLevelData batteryLevelData)214 Pair<Integer, Integer> getHighlightSlotPair(BatteryLevelData batteryLevelData) { 215 if (mHighlightSlotPair != null) { 216 return mHighlightSlotPair; 217 } 218 if (!mPowerAnomalyEvent.hasWarningItemInfo()) { 219 return null; 220 } 221 final WarningItemInfo warningItemInfo = mPowerAnomalyEvent.getWarningItemInfo(); 222 final Long startTimestamp = 223 warningItemInfo.hasStartTimestamp() ? warningItemInfo.getStartTimestamp() : null; 224 final Long endTimestamp = 225 warningItemInfo.hasEndTimestamp() ? warningItemInfo.getEndTimestamp() : null; 226 if (startTimestamp != null && endTimestamp != null) { 227 mHighlightSlotPair = 228 batteryLevelData.getIndexByTimestamps(startTimestamp, endTimestamp); 229 if (mHighlightSlotPair.first == BatteryChartViewModel.SELECTED_INDEX_INVALID 230 || mHighlightSlotPair.second == BatteryChartViewModel.SELECTED_INDEX_INVALID) { 231 // Drop invalid mHighlightSlotPair index 232 mHighlightSlotPair = null; 233 } 234 } 235 return mHighlightSlotPair; 236 } 237 updateTipsCardPreference(BatteryTipsCardPreference preference)238 boolean updateTipsCardPreference(BatteryTipsCardPreference preference) { 239 final String titleString = getTitleString(); 240 if (TextUtils.isEmpty(titleString)) { 241 return false; 242 } 243 preference.setTitle(titleString); 244 preference.setIconResourceId(getIconResId()); 245 preference.setButtonColorResourceId(getColorResId()); 246 preference.setMainButtonLabel(getMainBtnString()); 247 preference.setDismissButtonLabel(getDismissBtnString()); 248 return true; 249 } 250 launchSubSetting()251 boolean launchSubSetting() { 252 if (!hasSubSettingLauncher()) { 253 return false; 254 } 255 // Navigate to sub setting page 256 mSubSettingLauncher.launch(); 257 return true; 258 } 259 updateSystemSettingsIfAvailable()260 boolean updateSystemSettingsIfAvailable() { 261 final String settingsName = 262 getInfo(WarningBannerInfo::getMainButtonConfigSettingsName, null); 263 final Integer settingsValue = 264 getInfo(WarningBannerInfo::getMainButtonConfigSettingsValue, null); 265 if (TextUtils.isEmpty(settingsName) || settingsValue == null) { 266 Log.d(TAG, "Failed to update settings due to invalid key or value"); 267 return false; 268 } 269 270 try { 271 Settings.System.putInt(mContext.getContentResolver(), settingsName, settingsValue); 272 Log.d( 273 TAG, 274 String.format( 275 "Update settings name=%s to value=%d", settingsName, settingsValue)); 276 return true; 277 } catch (SecurityException e) { 278 Log.w( 279 TAG, 280 String.format( 281 "Failed to update settings name=%s to value=%d", 282 settingsName, settingsValue), 283 e); 284 return false; 285 } 286 } 287 } 288