1 /*
2  * Copyright (C) 2017 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.batterytip.tips;
18 
19 import android.content.Context;
20 import android.os.Parcel;
21 import android.os.Parcelable;
22 import android.util.SparseIntArray;
23 
24 import androidx.annotation.DrawableRes;
25 import androidx.annotation.IntDef;
26 import androidx.annotation.Nullable;
27 import androidx.annotation.VisibleForTesting;
28 import androidx.preference.Preference;
29 
30 import com.android.settings.widget.TipCardPreference;
31 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
32 
33 import java.lang.annotation.Retention;
34 import java.lang.annotation.RetentionPolicy;
35 
36 /**
37  * Base model for a battery tip(e.g. suggest user to turn on battery saver)
38  *
39  * <p>Each {@link BatteryTip} contains basic data(e.g. title, summary, icon) as well as the
40  * pre-defined action(e.g. turn on battery saver)
41  */
42 public abstract class BatteryTip implements Comparable<BatteryTip>, Parcelable {
43 
44     @Retention(RetentionPolicy.SOURCE)
45     @IntDef({StateType.NEW, StateType.HANDLED, StateType.INVISIBLE})
46     public @interface StateType {
47 
48         int NEW = 0;
49         int HANDLED = 1;
50         int INVISIBLE = 2;
51     }
52 
53     @Retention(RetentionPolicy.SOURCE)
54     @IntDef({
55         TipType.SUMMARY,
56         TipType.BATTERY_SAVER,
57         TipType.HIGH_DEVICE_USAGE,
58         TipType.SMART_BATTERY_MANAGER,
59         TipType.APP_RESTRICTION,
60         TipType.REDUCED_BATTERY,
61         TipType.LOW_BATTERY,
62         TipType.REMOVE_APP_RESTRICTION,
63         TipType.BATTERY_DEFENDER,
64         TipType.DOCK_DEFENDER,
65         TipType.INCOMPATIBLE_CHARGER,
66         TipType.BATTERY_WARNING
67     })
68     public @interface TipType {
69         int SMART_BATTERY_MANAGER = 0;
70         int APP_RESTRICTION = 1;
71         int HIGH_DEVICE_USAGE = 2;
72         int BATTERY_SAVER = 3;
73         int REDUCED_BATTERY = 4;
74         int LOW_BATTERY = 5;
75         int SUMMARY = 6;
76         int REMOVE_APP_RESTRICTION = 7;
77         int BATTERY_DEFENDER = 8;
78         int DOCK_DEFENDER = 9;
79         int INCOMPATIBLE_CHARGER = 10;
80         int BATTERY_WARNING = 11;
81     }
82 
83     @VisibleForTesting static final SparseIntArray TIP_ORDER;
84 
85     static {
86         TIP_ORDER = new SparseIntArray();
TIP_ORDER.append(TipType.BATTERY_SAVER, 0)87         TIP_ORDER.append(TipType.BATTERY_SAVER, 0);
TIP_ORDER.append(TipType.LOW_BATTERY, 1)88         TIP_ORDER.append(TipType.LOW_BATTERY, 1);
TIP_ORDER.append(TipType.BATTERY_DEFENDER, 2)89         TIP_ORDER.append(TipType.BATTERY_DEFENDER, 2);
TIP_ORDER.append(TipType.DOCK_DEFENDER, 3)90         TIP_ORDER.append(TipType.DOCK_DEFENDER, 3);
TIP_ORDER.append(TipType.INCOMPATIBLE_CHARGER, 4)91         TIP_ORDER.append(TipType.INCOMPATIBLE_CHARGER, 4);
TIP_ORDER.append(TipType.APP_RESTRICTION, 5)92         TIP_ORDER.append(TipType.APP_RESTRICTION, 5);
TIP_ORDER.append(TipType.HIGH_DEVICE_USAGE, 6)93         TIP_ORDER.append(TipType.HIGH_DEVICE_USAGE, 6);
TIP_ORDER.append(TipType.SUMMARY, 7)94         TIP_ORDER.append(TipType.SUMMARY, 7);
TIP_ORDER.append(TipType.SMART_BATTERY_MANAGER, 8)95         TIP_ORDER.append(TipType.SMART_BATTERY_MANAGER, 8);
TIP_ORDER.append(TipType.REDUCED_BATTERY, 9)96         TIP_ORDER.append(TipType.REDUCED_BATTERY, 9);
TIP_ORDER.append(TipType.REMOVE_APP_RESTRICTION, 10)97         TIP_ORDER.append(TipType.REMOVE_APP_RESTRICTION, 10);
TIP_ORDER.append(TipType.BATTERY_WARNING, 11)98         TIP_ORDER.append(TipType.BATTERY_WARNING, 11);
99     }
100 
101     private static final String KEY_PREFIX = "key_battery_tip";
102 
103     protected int mState;
104     protected int mType;
105     protected boolean mShowDialog;
106 
107     /** Whether we need to update battery tip when configuration change */
108     protected boolean mNeedUpdate;
109 
BatteryTip(Parcel in)110     public BatteryTip(Parcel in) {
111         mType = in.readInt();
112         mState = in.readInt();
113         mShowDialog = in.readBoolean();
114         mNeedUpdate = in.readBoolean();
115     }
116 
BatteryTip(int type, int state, boolean showDialog)117     public BatteryTip(int type, int state, boolean showDialog) {
118         mType = type;
119         mState = state;
120         mShowDialog = showDialog;
121         mNeedUpdate = true;
122     }
123 
124     @Override
describeContents()125     public int describeContents() {
126         return 0;
127     }
128 
129     @Override
writeToParcel(Parcel dest, int flags)130     public void writeToParcel(Parcel dest, int flags) {
131         dest.writeInt(mType);
132         dest.writeInt(mState);
133         dest.writeBoolean(mShowDialog);
134         dest.writeBoolean(mNeedUpdate);
135     }
136 
getTitle(Context context)137     public abstract CharSequence getTitle(Context context);
138 
getSummary(Context context)139     public abstract CharSequence getSummary(Context context);
140 
141     /** Gets the drawable resource id for the icon. */
142     @DrawableRes
getIconId()143     public abstract int getIconId();
144 
145     /**
146      * Update the current {@link #mState} using the new {@code tip}.
147      *
148      * @param tip used to update
149      */
updateState(BatteryTip tip)150     public abstract void updateState(BatteryTip tip);
151 
152     /**
153      * Check whether data is still make sense. If not, try recover.
154      *
155      * @param context used to do validate check
156      */
validateCheck(Context context)157     public void validateCheck(Context context) {
158         // do nothing
159     }
160 
161     /** Log the battery tip */
log(Context context, MetricsFeatureProvider metricsFeatureProvider)162     public abstract void log(Context context, MetricsFeatureProvider metricsFeatureProvider);
163 
updatePreference(Preference preference)164     public void updatePreference(Preference preference) {
165         final Context context = preference.getContext();
166         preference.setTitle(getTitle(context));
167         preference.setSummary(getSummary(context));
168         preference.setIcon(getIconId());
169         final TipCardPreference cardPreference = castToTipCardPreferenceSafely(preference);
170         if (cardPreference != null) {
171             cardPreference.resetLayoutState();
172         }
173     }
174 
shouldShowDialog()175     public boolean shouldShowDialog() {
176         return mShowDialog;
177     }
178 
needUpdate()179     public boolean needUpdate() {
180         return mNeedUpdate;
181     }
182 
getKey()183     public String getKey() {
184         return KEY_PREFIX + mType;
185     }
186 
getType()187     public int getType() {
188         return mType;
189     }
190 
191     @StateType
getState()192     public int getState() {
193         return mState;
194     }
195 
isVisible()196     public boolean isVisible() {
197         return mState != StateType.INVISIBLE;
198     }
199 
200     @Override
compareTo(BatteryTip o)201     public int compareTo(BatteryTip o) {
202         return TIP_ORDER.get(mType) - TIP_ORDER.get(o.mType);
203     }
204 
205     @Override
toString()206     public String toString() {
207         return "type=" + mType + " state=" + mState;
208     }
209 
210     /** Returns the converted {@link TipCardPreference} if it is valid. */
211     @Nullable
castToTipCardPreferenceSafely(Preference preference)212     public TipCardPreference castToTipCardPreferenceSafely(Preference preference) {
213         return preference instanceof TipCardPreference ? (TipCardPreference) preference : null;
214     }
215 }
216