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