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