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