1 /* 2 * Copyright (C) 2019 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.car.developeroptions.fuelgauge.batterytip; 18 19 import android.content.Context; 20 import android.os.Bundle; 21 22 import androidx.annotation.VisibleForTesting; 23 import androidx.preference.Preference; 24 import androidx.preference.PreferenceScreen; 25 26 import com.android.car.developeroptions.SettingsActivity; 27 import com.android.car.developeroptions.core.BasePreferenceController; 28 import com.android.car.developeroptions.core.InstrumentedPreferenceFragment; 29 import com.android.car.developeroptions.fuelgauge.Estimate; 30 import com.android.car.developeroptions.fuelgauge.batterytip.actions.BatteryTipAction; 31 import com.android.car.developeroptions.fuelgauge.batterytip.tips.BatteryTip; 32 import com.android.car.developeroptions.fuelgauge.batterytip.tips.SummaryTip; 33 import com.android.car.developeroptions.overlay.FeatureFactory; 34 import com.android.car.developeroptions.widget.CardPreference; 35 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; 36 37 import java.util.HashMap; 38 import java.util.List; 39 import java.util.Map; 40 41 /** 42 * Controller in charge of the battery tip group 43 */ 44 public class BatteryTipPreferenceController extends BasePreferenceController { 45 46 public static final String PREF_NAME = "battery_tip"; 47 48 private static final String TAG = "BatteryTipPreferenceController"; 49 private static final int REQUEST_ANOMALY_ACTION = 0; 50 private static final String KEY_BATTERY_TIPS = "key_battery_tips"; 51 52 private BatteryTipListener mBatteryTipListener; 53 private List<BatteryTip> mBatteryTips; 54 private Map<String, BatteryTip> mBatteryTipMap; 55 private SettingsActivity mSettingsActivity; 56 private MetricsFeatureProvider mMetricsFeatureProvider; 57 private boolean mNeedUpdate; 58 @VisibleForTesting 59 CardPreference mCardPreference; 60 @VisibleForTesting 61 Context mPrefContext; 62 InstrumentedPreferenceFragment mFragment; 63 BatteryTipPreferenceController(Context context, String preferenceKey)64 public BatteryTipPreferenceController(Context context, String preferenceKey) { 65 super(context, preferenceKey); 66 mBatteryTipMap = new HashMap<>(); 67 mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); 68 mNeedUpdate = true; 69 } 70 setActivity(SettingsActivity activity)71 public void setActivity(SettingsActivity activity) { 72 mSettingsActivity = activity; 73 } 74 setFragment(InstrumentedPreferenceFragment fragment)75 public void setFragment(InstrumentedPreferenceFragment fragment) { 76 mFragment = fragment; 77 } 78 setBatteryTipListener(BatteryTipListener lsn)79 public void setBatteryTipListener(BatteryTipListener lsn) { 80 mBatteryTipListener = lsn; 81 } 82 83 @Override getAvailabilityStatus()84 public int getAvailabilityStatus() { 85 return AVAILABLE_UNSEARCHABLE; 86 } 87 88 @Override displayPreference(PreferenceScreen screen)89 public void displayPreference(PreferenceScreen screen) { 90 super.displayPreference(screen); 91 mPrefContext = screen.getContext(); 92 mCardPreference = screen.findPreference(getPreferenceKey()); 93 94 // Add summary tip in advance to avoid UI flakiness 95 final SummaryTip summaryTip = new SummaryTip(BatteryTip.StateType.NEW, 96 Estimate.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN); 97 summaryTip.updatePreference(mCardPreference); 98 } 99 updateBatteryTips(List<BatteryTip> batteryTips)100 public void updateBatteryTips(List<BatteryTip> batteryTips) { 101 if (batteryTips == null) { 102 return; 103 } 104 if (mBatteryTips == null) { 105 mBatteryTips = batteryTips; 106 } else { 107 // mBatteryTips and batteryTips always have the same length and same sequence. 108 for (int i = 0, size = batteryTips.size(); i < size; i++) { 109 mBatteryTips.get(i).updateState(batteryTips.get(i)); 110 } 111 } 112 113 for (int i = 0, size = batteryTips.size(); i < size; i++) { 114 final BatteryTip batteryTip = mBatteryTips.get(i); 115 batteryTip.sanityCheck(mContext); 116 if (batteryTip.getState() != BatteryTip.StateType.INVISIBLE) { 117 batteryTip.updatePreference(mCardPreference); 118 mBatteryTipMap.put(mCardPreference.getKey(), batteryTip); 119 batteryTip.log(mContext, mMetricsFeatureProvider); 120 mNeedUpdate = batteryTip.needUpdate(); 121 break; 122 } 123 } 124 } 125 126 @Override handlePreferenceTreeClick(Preference preference)127 public boolean handlePreferenceTreeClick(Preference preference) { 128 final BatteryTip batteryTip = mBatteryTipMap.get(preference.getKey()); 129 if (batteryTip != null) { 130 if (batteryTip.shouldShowDialog()) { 131 BatteryTipDialogFragment dialogFragment = BatteryTipDialogFragment.newInstance( 132 batteryTip, mFragment.getMetricsCategory()); 133 dialogFragment.setTargetFragment(mFragment, REQUEST_ANOMALY_ACTION); 134 dialogFragment.show(mFragment.getFragmentManager(), TAG); 135 } else { 136 final BatteryTipAction action = BatteryTipUtils.getActionForBatteryTip(batteryTip, 137 mSettingsActivity, mFragment); 138 if (action != null) { 139 action.handlePositiveAction(mFragment.getMetricsCategory()); 140 } 141 if (mBatteryTipListener != null) { 142 mBatteryTipListener.onBatteryTipHandled(batteryTip); 143 } 144 } 145 146 return true; 147 } 148 149 return super.handlePreferenceTreeClick(preference); 150 } 151 restoreInstanceState(Bundle bundle)152 public void restoreInstanceState(Bundle bundle) { 153 if (bundle != null) { 154 List<BatteryTip> batteryTips = bundle.getParcelableArrayList(KEY_BATTERY_TIPS); 155 updateBatteryTips(batteryTips); 156 } 157 } 158 saveInstanceState(Bundle outState)159 public void saveInstanceState(Bundle outState) { 160 outState.putParcelableList(KEY_BATTERY_TIPS, mBatteryTips); 161 } 162 needUpdate()163 public boolean needUpdate() { 164 return mNeedUpdate; 165 } 166 167 /** 168 * Listener to give the control back to target fragment 169 */ 170 public interface BatteryTipListener { 171 /** 172 * This method is invoked once battery tip is handled, then target fragment could do 173 * extra work. 174 * 175 * @param batteryTip that has been handled 176 */ onBatteryTipHandled(BatteryTip batteryTip)177 void onBatteryTipHandled(BatteryTip batteryTip); 178 } 179 } 180