blob: 6ddd46ec134e05774715a613927cfa7c6a89f3b0 [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 Monk96ab6362016-02-11 11:33:09 -050024import android.text.SpannableStringBuilder;
25import android.text.Spanned;
26import android.text.style.RelativeSizeSpan;
Jason Monkc06fbb12016-01-08 14:12:18 -050027import android.view.LayoutInflater;
28import android.view.View;
Jason Monkf12cfb72016-02-22 15:46:12 -050029import android.view.View.OnAttachStateChangeListener;
30import android.view.View.OnClickListener;
Jason Monkc06fbb12016-01-08 14:12:18 -050031import android.view.ViewGroup;
32import android.widget.Checkable;
33import android.widget.ImageView;
34import android.widget.TextView;
Chris Wrenf6e9228b2016-01-26 18:04:35 -050035import com.android.internal.logging.MetricsProto.MetricsEvent;
Jason Monkc06fbb12016-01-08 14:12:18 -050036import com.android.settingslib.BatteryInfo;
Jason Monk96ab6362016-02-11 11:33:09 -050037import com.android.settingslib.graph.UsageView;
Jason Monkabe19742015-09-29 09:47:06 -040038import com.android.systemui.BatteryMeterDrawable;
39import com.android.systemui.R;
40import com.android.systemui.qs.QSTile;
41import com.android.systemui.statusbar.policy.BatteryController;
42
43import java.text.NumberFormat;
44
45public class BatteryTile extends QSTile<QSTile.State> implements BatteryController.BatteryStateChangeCallback {
46
47 private final BatteryMeterDrawable mDrawable;
48 private final BatteryController mBatteryController;
Jason Monkc06fbb12016-01-08 14:12:18 -050049 private final BatteryDetail mBatteryDetail = new BatteryDetail();
Jason Monkabe19742015-09-29 09:47:06 -040050
51 private int mLevel;
Jason Monkc06fbb12016-01-08 14:12:18 -050052 private boolean mPowerSave;
53 private boolean mCharging;
Jason Monkf12cfb72016-02-22 15:46:12 -050054 private boolean mDetailShown;
Jason Monkabe19742015-09-29 09:47:06 -040055
56 public BatteryTile(Host host) {
57 super(host);
58 mBatteryController = host.getBatteryController();
59 mDrawable = new BatteryMeterDrawable(host.getContext(), new Handler(),
60 host.getContext().getColor(R.color.batterymeter_frame_color));
61 mDrawable.setBatteryController(mBatteryController);
62 }
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) {
82 mDrawable.startListening();
83 mBatteryController.addStateChangedCallback(this);
84 } else {
85 mDrawable.stopListening();
86 mBatteryController.removeStateChangedCallback(this);
87 }
88 }
89
90 @Override
Jason Monkc06fbb12016-01-08 14:12:18 -050091 public void setDetailListening(boolean listening) {
92 super.setDetailListening(listening);
93 if (!listening) {
94 mBatteryDetail.mCurrentView = null;
95 }
96 }
97
98 @Override
Jason Monk76c67aa2016-02-19 14:49:42 -050099 public Intent getLongClickIntent() {
100 return new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
101 }
102
103 @Override
Jason Monkabe19742015-09-29 09:47:06 -0400104 protected void handleClick() {
Jason Monkc06fbb12016-01-08 14:12:18 -0500105 showDetail(true);
Jason Monkabe19742015-09-29 09:47:06 -0400106 }
107
108 @Override
Jason Monk39c98e62016-03-16 09:18:35 -0400109 public CharSequence getTileLabel() {
110 return mContext.getString(R.string.battery);
111 }
112
113 @Override
Jason Monkabe19742015-09-29 09:47:06 -0400114 protected void handleUpdateState(State state, Object arg) {
115 int level = (arg != null) ? (Integer) arg : mLevel;
116 String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
117
Jason Monkabe19742015-09-29 09:47:06 -0400118 state.icon = new Icon() {
119 @Override
120 public Drawable getDrawable(Context context) {
121 return mDrawable;
122 }
Jason Monkb53b6c52016-02-24 17:25:49 -0500123
124 @Override
125 public int getPadding() {
126 return mHost.getContext().getResources().getDimensionPixelSize(
127 R.dimen.qs_battery_padding);
128 }
Jason Monkabe19742015-09-29 09:47:06 -0400129 };
130 state.label = percentage;
131 }
132
133 @Override
134 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
135 mLevel = level;
Jason Monkc06fbb12016-01-08 14:12:18 -0500136 mCharging = charging;
Jason Monkabe19742015-09-29 09:47:06 -0400137 refreshState((Integer) level);
Jason Monkf12cfb72016-02-22 15:46:12 -0500138 if (mDetailShown) {
139 mBatteryDetail.postBindView();
Jason Monkc06fbb12016-01-08 14:12:18 -0500140 }
Jason Monkabe19742015-09-29 09:47:06 -0400141 }
142
143 @Override
Jason Monkc06fbb12016-01-08 14:12:18 -0500144 public void onPowerSaveChanged(boolean isPowerSave) {
145 mPowerSave = isPowerSave;
Jason Monkf12cfb72016-02-22 15:46:12 -0500146 if (mDetailShown) {
147 mBatteryDetail.postBindView();
Jason Monkc06fbb12016-01-08 14:12:18 -0500148 }
149 }
Jason Monkabe19742015-09-29 09:47:06 -0400150
Jason Monkf12cfb72016-02-22 15:46:12 -0500151 private final class BatteryDetail implements DetailAdapter, OnClickListener,
152 OnAttachStateChangeListener {
Jason Monkc06fbb12016-01-08 14:12:18 -0500153 private final BatteryMeterDrawable mDrawable = new BatteryMeterDrawable(mHost.getContext(),
154 new Handler(), mHost.getContext().getColor(R.color.batterymeter_frame_color));
155 private View mCurrentView;
156
157 @Override
158 public CharSequence getTitle() {
159 return mContext.getString(R.string.battery_panel_title, mLevel);
160 }
161
162 @Override
163 public Boolean getToggleState() {
164 return null;
165 }
166
167 @Override
168 public View createDetailView(Context context, View convertView, ViewGroup parent) {
169 if (convertView == null) {
170 convertView = LayoutInflater.from(mContext).inflate(R.layout.battery_detail, parent,
171 false);
172 }
173 mCurrentView = convertView;
Jason Monkf12cfb72016-02-22 15:46:12 -0500174 mCurrentView.addOnAttachStateChangeListener(this);
Jason Monkc06fbb12016-01-08 14:12:18 -0500175 bindView();
176 return convertView;
177 }
178
Jason Monkf12cfb72016-02-22 15:46:12 -0500179 private void postBindView() {
Jason Monk6cb90122016-03-02 12:40:43 -0500180 if (mCurrentView == null) return;
Jason Monkf12cfb72016-02-22 15:46:12 -0500181 mCurrentView.post(new Runnable() {
182 @Override
183 public void run() {
184 bindView();
185 }
186 });
187 }
188
Jason Monkc06fbb12016-01-08 14:12:18 -0500189 private void bindView() {
Jason Monk2462a502016-03-02 16:04:39 -0500190 if (mCurrentView == null) {
191 return;
192 }
Jason Monkc06fbb12016-01-08 14:12:18 -0500193 mDrawable.onBatteryLevelChanged(100, false, false);
194 mDrawable.onPowerSaveChanged(true);
Jason Monk5c404c82016-02-05 15:54:10 -0500195 mDrawable.disableShowPercent();
Jason Monkc06fbb12016-01-08 14:12:18 -0500196 ((ImageView) mCurrentView.findViewById(android.R.id.icon)).setImageDrawable(mDrawable);
197 Checkable checkbox = (Checkable) mCurrentView.findViewById(android.R.id.toggle);
198 checkbox.setChecked(mPowerSave);
Jason Monkf12cfb72016-02-22 15:46:12 -0500199 BatteryInfo.getBatteryInfo(mContext, new BatteryInfo.Callback() {
200 @Override
201 public void onBatteryInfoLoaded(BatteryInfo info) {
202 if (mCurrentView != null) {
203 bindBatteryInfo(info);
Jason Monkc06fbb12016-01-08 14:12:18 -0500204 }
Jason Monkf12cfb72016-02-22 15:46:12 -0500205 }
206 });
207 if (mCharging) {
Jason Monk96ab6362016-02-11 11:33:09 -0500208 ((TextView) mCurrentView.findViewById(android.R.id.title)).setText(
Jason Monkc06fbb12016-01-08 14:12:18 -0500209 R.string.battery_detail_charging_summary);
Jason Monkc06fbb12016-01-08 14:12:18 -0500210 mCurrentView.findViewById(android.R.id.icon).setVisibility(View.INVISIBLE);
Jason Monk96ab6362016-02-11 11:33:09 -0500211 mCurrentView.findViewById(android.R.id.toggle).setVisibility(View.GONE);
212 mCurrentView.findViewById(R.id.switch_container).setClickable(false);
Jason Monkc06fbb12016-01-08 14:12:18 -0500213 } else {
214 ((TextView) mCurrentView.findViewById(android.R.id.title)).setText(
215 R.string.battery_detail_switch_title);
216 ((TextView) mCurrentView.findViewById(android.R.id.summary)).setText(
217 R.string.battery_detail_switch_summary);
Jason Monkc06fbb12016-01-08 14:12:18 -0500218 mCurrentView.findViewById(android.R.id.icon).setVisibility(View.VISIBLE);
219 mCurrentView.findViewById(android.R.id.toggle).setVisibility(View.VISIBLE);
Jason Monk96ab6362016-02-11 11:33:09 -0500220 mCurrentView.findViewById(R.id.switch_container).setClickable(true);
221 mCurrentView.findViewById(R.id.switch_container).setOnClickListener(this);
Jason Monkc06fbb12016-01-08 14:12:18 -0500222 }
223 }
224
Jason Monk96ab6362016-02-11 11:33:09 -0500225 private void bindBatteryInfo(BatteryInfo info) {
226 SpannableStringBuilder builder = new SpannableStringBuilder();
227 builder.append(info.batteryPercentString, new RelativeSizeSpan(2),
228 Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
229 if (info.remainingLabel != null) {
230 if (mContext.getResources().getBoolean(R.bool.quick_settings_wide)) {
231 builder.append(' ');
232 } else {
233 builder.append('\n');
234 }
235 builder.append(info.remainingLabel);
236 }
237 ((TextView) mCurrentView.findViewById(R.id.charge_and_estimation)).setText(builder);
238
239 info.bindHistory((UsageView) mCurrentView.findViewById(R.id.battery_usage));
240 }
241
Jason Monkc06fbb12016-01-08 14:12:18 -0500242 @Override
243 public void onClick(View v) {
244 mBatteryController.setPowerSaveMode(!mPowerSave);
245 }
246
247 @Override
248 public Intent getSettingsIntent() {
249 return new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
250 }
251
252 @Override
253 public void setToggleState(boolean state) {
254 // No toggle state.
255 }
256
257 @Override
258 public int getMetricsCategory() {
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500259 return MetricsEvent.QS_BATTERY_DETAIL;
Jason Monkc06fbb12016-01-08 14:12:18 -0500260 }
Jason Monkf12cfb72016-02-22 15:46:12 -0500261
262 @Override
263 public void onViewAttachedToWindow(View v) {
264 if (!mDetailShown) {
265 mDetailShown = true;
266 v.getContext().registerReceiver(mReceiver,
267 new IntentFilter(Intent.ACTION_TIME_TICK));
268 }
269 }
270
271 @Override
272 public void onViewDetachedFromWindow(View v) {
273 if (mDetailShown) {
274 mDetailShown = false;
275 v.getContext().unregisterReceiver(mReceiver);
276 }
277 }
278
279 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
280 @Override
281 public void onReceive(Context context, Intent intent) {
282 postBindView();
283 }
284 };
Jason Monkabe19742015-09-29 09:47:06 -0400285 }
286}