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