1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package com.android.settings.fuelgauge.batterysaver; 17 18 import android.content.ContentResolver; 19 import android.content.Context; 20 import android.database.ContentObserver; 21 import android.net.Uri; 22 import android.os.Handler; 23 import android.os.Looper; 24 import android.provider.Settings; 25 import android.support.annotation.VisibleForTesting; 26 import android.support.v7.preference.Preference; 27 import android.support.v7.preference.PreferenceScreen; 28 import android.util.Log; 29 import android.view.accessibility.AccessibilityNodeInfo; 30 31 import com.android.settings.R; 32 import com.android.settings.Utils; 33 import com.android.settings.core.BasePreferenceController; 34 import com.android.settings.widget.SeekBarPreference; 35 import com.android.settingslib.core.lifecycle.Lifecycle; 36 import com.android.settingslib.core.lifecycle.LifecycleObserver; 37 import com.android.settingslib.core.lifecycle.events.OnStart; 38 import com.android.settingslib.core.lifecycle.events.OnStop; 39 40 /** 41 * Controller that update the battery saver seekbar 42 */ 43 public class AutoBatterySeekBarPreferenceController extends BasePreferenceController implements 44 LifecycleObserver, OnStart, OnStop, SeekBarPreference.OnPreferenceChangeListener { 45 private static final String TAG = "AutoBatterySeekBarPreferenceController"; 46 @VisibleForTesting 47 static final String KEY_AUTO_BATTERY_SEEK_BAR = "battery_saver_seek_bar"; 48 private SeekBarPreference mPreference; 49 private AutoBatterySaverSettingObserver mContentObserver; 50 51 public AutoBatterySeekBarPreferenceController(Context context, Lifecycle lifecycle) { 52 super(context, KEY_AUTO_BATTERY_SEEK_BAR); 53 mContentObserver = new AutoBatterySaverSettingObserver(new Handler(Looper.getMainLooper())); 54 if (lifecycle != null) { 55 lifecycle.addObserver(this); 56 } 57 } 58 59 @Override 60 public void displayPreference(PreferenceScreen screen) { 61 super.displayPreference(screen); 62 mPreference = (SeekBarPreference) screen.findPreference( 63 KEY_AUTO_BATTERY_SEEK_BAR); 64 mPreference.setContinuousUpdates(true); 65 mPreference.setAccessibilityRangeInfoType( 66 AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_PERCENT); 67 updatePreference(mPreference); 68 } 69 70 @Override 71 public int getAvailabilityStatus() { 72 return AVAILABLE; 73 } 74 75 @Override 76 public void updateState(Preference preference) { 77 super.updateState(preference); 78 updatePreference(preference); 79 } 80 81 @Override 82 public void onStart() { 83 mContentObserver.registerContentObserver(); 84 } 85 86 @Override 87 public void onStop() { 88 mContentObserver.unRegisterContentObserver(); 89 } 90 91 @Override 92 public boolean onPreferenceChange(Preference preference, Object newValue) { 93 final int progress = (int) newValue; 94 Settings.Global.putInt(mContext.getContentResolver(), 95 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, progress); 96 return true; 97 } 98 99 @VisibleForTesting 100 void updatePreference(Preference preference) { 101 final ContentResolver contentResolver = mContext.getContentResolver(); 102 103 // Override the max value with LOW_POWER_MODE_TRIGGER_LEVEL_MAX, if set. 104 final int maxLevel = Settings.Global.getInt(contentResolver, 105 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL_MAX, 0); 106 if (maxLevel > 0) { 107 if (!(preference instanceof SeekBarPreference)) { 108 Log.e(TAG, "Unexpected preference class: " + preference.getClass()); 109 } else { 110 final SeekBarPreference seekBarPreference = (SeekBarPreference) preference; 111 if (maxLevel < seekBarPreference.getMin()) { 112 Log.e(TAG, "LOW_POWER_MODE_TRIGGER_LEVEL_MAX too low; ignored."); 113 } else { 114 seekBarPreference.setMax(maxLevel); 115 } 116 } 117 } 118 119 // Set the current value. 120 final int level = Settings.Global.getInt(contentResolver, 121 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 122 AutoBatterySaverPreferenceController.DEFAULT_TRIGGER_LEVEL); 123 if (level == 0) { 124 preference.setVisible(false); 125 } else { 126 preference.setVisible(true); 127 preference.setTitle(mContext.getString(R.string.battery_saver_seekbar_title, 128 Utils.formatPercentage(level))); 129 SeekBarPreference seekBarPreference = (SeekBarPreference) preference; 130 seekBarPreference.setProgress(level); 131 seekBarPreference.setSeekBarContentDescription( 132 mContext.getString(R.string.battery_saver_turn_on_automatically_title)); 133 } 134 } 135 136 /** 137 * Observer that listens to change from {@link Settings.Global#LOW_POWER_MODE_TRIGGER_LEVEL} 138 */ 139 private final class AutoBatterySaverSettingObserver extends ContentObserver { 140 private final Uri mUri = Settings.Global.getUriFor( 141 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL); 142 private final ContentResolver mContentResolver; 143 144 public AutoBatterySaverSettingObserver(Handler handler) { 145 super(handler); 146 mContentResolver = mContext.getContentResolver(); 147 } 148 149 public void registerContentObserver() { 150 mContentResolver.registerContentObserver(mUri, false, this); 151 } 152 153 public void unRegisterContentObserver() { 154 mContentResolver.unregisterContentObserver(this); 155 } 156 157 @Override 158 public void onChange(boolean selfChange, Uri uri, int userId) { 159 if (mUri.equals(uri)) { 160 updatePreference(mPreference); 161 } 162 } 163 } 164 } 165