blob: 90088eaa6e894e52f4d9d68b4319ffc800a22f98 [file] [log] [blame]
Jason Monkabe19742015-09-29 09:47:06 -04001/*
2 * Copyright (C) 2015 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 */
16package com.android.systemui.qs.tiles;
17
Jason Monkf12cfb72016-02-22 15:46:12 -050018import android.content.BroadcastReceiver;
Jason Monkabe19742015-09-29 09:47:06 -040019import android.content.Context;
20import android.content.Intent;
Jason Monkf12cfb72016-02-22 15:46:12 -050021import android.content.IntentFilter;
Jason Monkabe19742015-09-29 09:47:06 -040022import android.graphics.drawable.Drawable;
23import android.os.Handler;
Jason Monk8b2ce602016-03-31 11:30:41 -040024import android.os.Looper;
Jason Monk96ab6362016-02-11 11:33:09 -050025import android.text.SpannableStringBuilder;
26import android.text.Spanned;
27import android.text.style.RelativeSizeSpan;
Jason Monk006572a2016-04-08 14:43:08 -040028import android.util.TypedValue;
Jason Monkc06fbb12016-01-08 14:12:18 -050029import android.view.LayoutInflater;
30import android.view.View;
Jason Monkf12cfb72016-02-22 15:46:12 -050031import android.view.View.OnAttachStateChangeListener;
32import android.view.View.OnClickListener;
Jason Monkc06fbb12016-01-08 14:12:18 -050033import android.view.ViewGroup;
Julia Reynolds20aef8a2016-05-04 16:44:08 -040034import android.widget.Button;
Jason Monkc06fbb12016-01-08 14:12:18 -050035import android.widget.Checkable;
36import android.widget.ImageView;
37import android.widget.TextView;
Tamas Berghammercbd3f0c2016-06-22 15:21:38 +010038import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Jason Monkc06fbb12016-01-08 14:12:18 -050039import com.android.settingslib.BatteryInfo;
Jason Monk96ab6362016-02-11 11:33:09 -050040import com.android.settingslib.graph.UsageView;
Jason Monkabe19742015-09-29 09:47:06 -040041import com.android.systemui.BatteryMeterDrawable;
42import com.android.systemui.R;
43import com.android.systemui.qs.QSTile;
44import com.android.systemui.statusbar.policy.BatteryController;
45
46import java.text.NumberFormat;
47
48public class BatteryTile extends QSTile<QSTile.State> implements BatteryController.BatteryStateChangeCallback {
49
Jason Monkabe19742015-09-29 09:47:06 -040050 private final BatteryController mBatteryController;
Jason Monkc06fbb12016-01-08 14:12:18 -050051 private final BatteryDetail mBatteryDetail = new BatteryDetail();
Jason Monkabe19742015-09-29 09:47:06 -040052
53 private int mLevel;
Jason Monkc06fbb12016-01-08 14:12:18 -050054 private boolean mPowerSave;
55 private boolean mCharging;
Jason Monkf12cfb72016-02-22 15:46:12 -050056 private boolean mDetailShown;
Jason Monk8b2ce602016-03-31 11:30:41 -040057 private boolean mPluggedIn;
Jason Monkabe19742015-09-29 09:47:06 -040058
59 public BatteryTile(Host host) {
60 super(host);
61 mBatteryController = host.getBatteryController();
Jason Monkabe19742015-09-29 09:47:06 -040062 }
63
64 @Override
Jason Monk62b63a02016-02-02 15:15:31 -050065 public State newTileState() {
Jason Monkabe19742015-09-29 09:47:06 -040066 return new QSTile.State();
67 }
68
69 @Override
Jason Monkc06fbb12016-01-08 14:12:18 -050070 public DetailAdapter getDetailAdapter() {
71 return mBatteryDetail;
72 }
73
74 @Override
Jason Monkabe19742015-09-29 09:47:06 -040075 public int getMetricsCategory() {
Chris Wrenf6e9228b2016-01-26 18:04:35 -050076 return MetricsEvent.QS_BATTERY_TILE;
Jason Monkabe19742015-09-29 09:47:06 -040077 }
78
79 @Override
80 public void setListening(boolean listening) {
81 if (listening) {
Jason Monkabe19742015-09-29 09:47:06 -040082 mBatteryController.addStateChangedCallback(this);
83 } else {
Jason Monkabe19742015-09-29 09:47:06 -040084 mBatteryController.removeStateChangedCallback(this);
85 }
86 }
87
88 @Override
Jason Monkc06fbb12016-01-08 14:12:18 -050089 public void setDetailListening(boolean listening) {
90 super.setDetailListening(listening);
91 if (!listening) {
92 mBatteryDetail.mCurrentView = null;
93 }
94 }
95
96 @Override
Jason Monk76c67aa2016-02-19 14:49:42 -050097 public Intent getLongClickIntent() {
98 return new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
99 }
100
101 @Override
Jason Monkabe19742015-09-29 09:47:06 -0400102 protected void handleClick() {
Jason Monkc06fbb12016-01-08 14:12:18 -0500103 showDetail(true);
Jason Monkabe19742015-09-29 09:47:06 -0400104 }
105
106 @Override
Jason Monk39c98e62016-03-16 09:18:35 -0400107 public CharSequence getTileLabel() {
108 return mContext.getString(R.string.battery);
109 }
110
111 @Override
Jason Monkabe19742015-09-29 09:47:06 -0400112 protected void handleUpdateState(State state, Object arg) {
113 int level = (arg != null) ? (Integer) arg : mLevel;
114 String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
115
Jason Monkabe19742015-09-29 09:47:06 -0400116 state.icon = new Icon() {
117 @Override
118 public Drawable getDrawable(Context context) {
Jason Monk8b2ce602016-03-31 11:30:41 -0400119 BatteryMeterDrawable drawable =
120 new BatteryMeterDrawable(context, new Handler(Looper.getMainLooper()),
121 context.getColor(R.color.batterymeter_frame_color));
122 drawable.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
123 drawable.onPowerSaveChanged(mPowerSave);
124 return drawable;
Jason Monkabe19742015-09-29 09:47:06 -0400125 }
Jason Monkb53b6c52016-02-24 17:25:49 -0500126
127 @Override
128 public int getPadding() {
129 return mHost.getContext().getResources().getDimensionPixelSize(
130 R.dimen.qs_battery_padding);
131 }
Jason Monkabe19742015-09-29 09:47:06 -0400132 };
133 state.label = percentage;
Jason Monkbc457432016-04-11 11:31:32 -0400134 state.contentDescription = mContext.getString(R.string.accessibility_quick_settings_battery,
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400135 percentage) + "," +
136 (mPowerSave ? mContext.getString(R.string.battery_saver_notification_title)
137 : mCharging ? mContext.getString(R.string.expanded_header_battery_charging)
138 : "")
139 + "," + mContext.getString(R.string.accessibility_battery_details);
140 state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
141 = Button.class.getName();
Jason Monkabe19742015-09-29 09:47:06 -0400142 }
143
144 @Override
145 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
146 mLevel = level;
Jason Monk8b2ce602016-03-31 11:30:41 -0400147 mPluggedIn = pluggedIn;
Jason Monkc06fbb12016-01-08 14:12:18 -0500148 mCharging = charging;
Jason Monkabe19742015-09-29 09:47:06 -0400149 refreshState((Integer) level);
Jason Monkf12cfb72016-02-22 15:46:12 -0500150 if (mDetailShown) {
151 mBatteryDetail.postBindView();
Jason Monkc06fbb12016-01-08 14:12:18 -0500152 }
Jason Monkabe19742015-09-29 09:47:06 -0400153 }
154
155 @Override
Jason Monkc06fbb12016-01-08 14:12:18 -0500156 public void onPowerSaveChanged(boolean isPowerSave) {
157 mPowerSave = isPowerSave;
Jason Monk8b2ce602016-03-31 11:30:41 -0400158 refreshState(null);
Jason Monkf12cfb72016-02-22 15:46:12 -0500159 if (mDetailShown) {
160 mBatteryDetail.postBindView();
Jason Monkc06fbb12016-01-08 14:12:18 -0500161 }
162 }
Jason Monkabe19742015-09-29 09:47:06 -0400163
Jason Monkf12cfb72016-02-22 15:46:12 -0500164 private final class BatteryDetail implements DetailAdapter, OnClickListener,
165 OnAttachStateChangeListener {
Jason Monkc06fbb12016-01-08 14:12:18 -0500166 private final BatteryMeterDrawable mDrawable = new BatteryMeterDrawable(mHost.getContext(),
167 new Handler(), mHost.getContext().getColor(R.color.batterymeter_frame_color));
168 private View mCurrentView;
169
170 @Override
171 public CharSequence getTitle() {
172 return mContext.getString(R.string.battery_panel_title, mLevel);
173 }
174
175 @Override
176 public Boolean getToggleState() {
177 return null;
178 }
179
180 @Override
181 public View createDetailView(Context context, View convertView, ViewGroup parent) {
182 if (convertView == null) {
183 convertView = LayoutInflater.from(mContext).inflate(R.layout.battery_detail, parent,
184 false);
185 }
186 mCurrentView = convertView;
Jason Monkf12cfb72016-02-22 15:46:12 -0500187 mCurrentView.addOnAttachStateChangeListener(this);
Jason Monkc06fbb12016-01-08 14:12:18 -0500188 bindView();
189 return convertView;
190 }
191
Jason Monkf12cfb72016-02-22 15:46:12 -0500192 private void postBindView() {
Jason Monk6cb90122016-03-02 12:40:43 -0500193 if (mCurrentView == null) return;
Jason Monkf12cfb72016-02-22 15:46:12 -0500194 mCurrentView.post(new Runnable() {
195 @Override
196 public void run() {
197 bindView();
198 }
199 });
200 }
201
Jason Monkc06fbb12016-01-08 14:12:18 -0500202 private void bindView() {
Jason Monk2462a502016-03-02 16:04:39 -0500203 if (mCurrentView == null) {
204 return;
205 }
Jason Monkc06fbb12016-01-08 14:12:18 -0500206 mDrawable.onBatteryLevelChanged(100, false, false);
207 mDrawable.onPowerSaveChanged(true);
Jason Monk5c404c82016-02-05 15:54:10 -0500208 mDrawable.disableShowPercent();
Jason Monkc06fbb12016-01-08 14:12:18 -0500209 ((ImageView) mCurrentView.findViewById(android.R.id.icon)).setImageDrawable(mDrawable);
210 Checkable checkbox = (Checkable) mCurrentView.findViewById(android.R.id.toggle);
211 checkbox.setChecked(mPowerSave);
Jason Monkf12cfb72016-02-22 15:46:12 -0500212 BatteryInfo.getBatteryInfo(mContext, new BatteryInfo.Callback() {
213 @Override
214 public void onBatteryInfoLoaded(BatteryInfo info) {
215 if (mCurrentView != null) {
216 bindBatteryInfo(info);
Jason Monkc06fbb12016-01-08 14:12:18 -0500217 }
Jason Monkf12cfb72016-02-22 15:46:12 -0500218 }
219 });
Jason Monk006572a2016-04-08 14:43:08 -0400220 final TextView batterySaverTitle =
221 (TextView) mCurrentView.findViewById(android.R.id.title);
222 final TextView batterySaverSummary =
223 (TextView) mCurrentView.findViewById(android.R.id.summary);
Jason Monkf12cfb72016-02-22 15:46:12 -0500224 if (mCharging) {
Jason Monk006572a2016-04-08 14:43:08 -0400225 mCurrentView.findViewById(R.id.switch_container).setAlpha(.7f);
226 batterySaverTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
227 batterySaverTitle.setText(R.string.battery_detail_charging_summary);
Jason Monk96ab6362016-02-11 11:33:09 -0500228 mCurrentView.findViewById(android.R.id.toggle).setVisibility(View.GONE);
229 mCurrentView.findViewById(R.id.switch_container).setClickable(false);
Jason Monkc06fbb12016-01-08 14:12:18 -0500230 } else {
Jason Monk006572a2016-04-08 14:43:08 -0400231 mCurrentView.findViewById(R.id.switch_container).setAlpha(1);
232 batterySaverTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
233 batterySaverTitle.setText(R.string.battery_detail_switch_title);
234 batterySaverSummary.setText(R.string.battery_detail_switch_summary);
Jason Monkc06fbb12016-01-08 14:12:18 -0500235 mCurrentView.findViewById(android.R.id.toggle).setVisibility(View.VISIBLE);
Jason Monk96ab6362016-02-11 11:33:09 -0500236 mCurrentView.findViewById(R.id.switch_container).setClickable(true);
237 mCurrentView.findViewById(R.id.switch_container).setOnClickListener(this);
Jason Monkc06fbb12016-01-08 14:12:18 -0500238 }
239 }
240
Jason Monk96ab6362016-02-11 11:33:09 -0500241 private void bindBatteryInfo(BatteryInfo info) {
242 SpannableStringBuilder builder = new SpannableStringBuilder();
Jason Monk006572a2016-04-08 14:43:08 -0400243 builder.append(info.batteryPercentString, new RelativeSizeSpan(2.6f),
Jason Monk96ab6362016-02-11 11:33:09 -0500244 Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
245 if (info.remainingLabel != null) {
246 if (mContext.getResources().getBoolean(R.bool.quick_settings_wide)) {
247 builder.append(' ');
248 } else {
249 builder.append('\n');
250 }
251 builder.append(info.remainingLabel);
252 }
253 ((TextView) mCurrentView.findViewById(R.id.charge_and_estimation)).setText(builder);
254
255 info.bindHistory((UsageView) mCurrentView.findViewById(R.id.battery_usage));
256 }
257
Jason Monkc06fbb12016-01-08 14:12:18 -0500258 @Override
259 public void onClick(View v) {
260 mBatteryController.setPowerSaveMode(!mPowerSave);
261 }
262
263 @Override
264 public Intent getSettingsIntent() {
265 return new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
266 }
267
268 @Override
269 public void setToggleState(boolean state) {
270 // No toggle state.
271 }
272
273 @Override
274 public int getMetricsCategory() {
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500275 return MetricsEvent.QS_BATTERY_DETAIL;
Jason Monkc06fbb12016-01-08 14:12:18 -0500276 }
Jason Monkf12cfb72016-02-22 15:46:12 -0500277
278 @Override
279 public void onViewAttachedToWindow(View v) {
280 if (!mDetailShown) {
281 mDetailShown = true;
282 v.getContext().registerReceiver(mReceiver,
283 new IntentFilter(Intent.ACTION_TIME_TICK));
284 }
285 }
286
287 @Override
288 public void onViewDetachedFromWindow(View v) {
289 if (mDetailShown) {
290 mDetailShown = false;
291 v.getContext().unregisterReceiver(mReceiver);
292 }
293 }
294
295 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
296 @Override
297 public void onReceive(Context context, Intent intent) {
298 postBindView();
299 }
300 };
Jason Monkabe19742015-09-29 09:47:06 -0400301 }
302}