blob: 6a8c19ad0e770594663d83e46a867a570e20b43a [file] [log] [blame]
Jason Monke5b770e2017-03-03 21:49:29 -05001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. 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 distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11 * KIND, either express or implied. See the License for the specific language governing
12 * permissions and limitations under the License.
13 */
14
15package com.android.systemui.qs;
16
Charles Hece2a7c02017-10-11 20:25:20 +010017import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
Evan Laird4bf21df2018-10-22 14:24:32 -040018import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
Charles Hece2a7c02017-10-11 20:25:20 +010019
Jason Monkea54e8a2018-12-20 10:01:48 -050020import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
21
Rohan Shahd3cf7562018-02-23 11:12:28 -080022import android.animation.Animator;
23import android.animation.AnimatorListenerAdapter;
Amin Shaikh0e003312018-03-08 11:39:01 -050024import android.annotation.ColorInt;
Lucas Dupin1f7374a2018-02-26 18:08:33 -080025import android.app.ActivityManager;
Rohan Shahd3cf7562018-02-23 11:12:28 -080026import android.app.AlarmManager;
Fabian Kozynski12638242018-10-12 15:33:41 -040027import android.app.Dialog;
Amin Shaikh761c5662018-03-27 16:55:43 -040028import android.content.BroadcastReceiver;
Jason Monke5b770e2017-03-03 21:49:29 -050029import android.content.Context;
Evan Laird4ea2a492018-01-22 11:29:12 -050030import android.content.Intent;
Amin Shaikh761c5662018-03-27 16:55:43 -040031import android.content.IntentFilter;
Jason Monke5b770e2017-03-03 21:49:29 -050032import android.content.res.Configuration;
Rohan Shahcc3d1d82018-03-30 21:24:17 +000033import android.content.res.Resources;
Evan Laird4bf21df2018-10-22 14:24:32 -040034import android.database.ContentObserver;
Jason Monke5b770e2017-03-03 21:49:29 -050035import android.graphics.Color;
36import android.graphics.Rect;
Amin Shaikh761c5662018-03-27 16:55:43 -040037import android.media.AudioManager;
Evan Laird4bf21df2018-10-22 14:24:32 -040038import android.net.Uri;
Rohan Shahd3cf7562018-02-23 11:12:28 -080039import android.os.Handler;
Fabian Kozynski12638242018-10-12 15:33:41 -040040import android.os.Looper;
Evan Laird4ea2a492018-01-22 11:29:12 -050041import android.provider.AlarmClock;
Evan Laird4bf21df2018-10-22 14:24:32 -040042import android.provider.Settings;
Beverlyb9826dd2018-04-12 15:02:45 -040043import android.service.notification.ZenModeConfig;
Rohan Shahd3cf7562018-02-23 11:12:28 -080044import android.text.format.DateUtils;
Jason Monke5b770e2017-03-03 21:49:29 -050045import android.util.AttributeSet;
Rohan Shaha160ab12018-03-09 15:47:36 -080046import android.util.Log;
Adrian Roos13836052018-03-15 21:06:37 +010047import android.util.Pair;
Fabian Kozynski8d06c712018-11-07 10:33:02 -050048import android.view.DisplayCutout;
Jason Monk824ffff2017-04-11 15:49:06 -040049import android.view.View;
Adrian Roos13836052018-03-15 21:06:37 +010050import android.view.WindowInsets;
Beverlyff2df9b2018-10-10 16:54:10 -040051import android.widget.FrameLayout;
Amin Shaikh761c5662018-03-27 16:55:43 -040052import android.widget.ImageView;
Fabian Kozynski8d06c712018-11-07 10:33:02 -050053import android.widget.LinearLayout;
Jason Monke5b770e2017-03-03 21:49:29 -050054import android.widget.RelativeLayout;
Fabian Kozynski8d06c712018-11-07 10:33:02 -050055import android.widget.Space;
Rohan Shahd3cf7562018-02-23 11:12:28 -080056import android.widget.TextView;
Jason Monke5b770e2017-03-03 21:49:29 -050057
Beverlyff2df9b2018-10-10 16:54:10 -040058import androidx.annotation.VisibleForTesting;
59
Jason Monke5b770e2017-03-03 21:49:29 -050060import com.android.settingslib.Utils;
61import com.android.systemui.BatteryMeterView;
Rohan Shahd3cf7562018-02-23 11:12:28 -080062import com.android.systemui.Prefs;
Jason Monke5b770e2017-03-03 21:49:29 -050063import com.android.systemui.R;
64import com.android.systemui.plugins.ActivityStarter;
Beverly1be62f42018-12-19 17:17:48 -050065import com.android.systemui.plugins.DarkIconDispatcher;
66import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
Fabian Kozynski12638242018-10-12 15:33:41 -040067import com.android.systemui.privacy.OngoingPrivacyChip;
68import com.android.systemui.privacy.OngoingPrivacyDialog;
Fabian Kozynskiafd50022019-02-05 09:41:42 -050069import com.android.systemui.privacy.PrivacyDialogBuilder;
Fabian Kozynski8d06c712018-11-07 10:33:02 -050070import com.android.systemui.privacy.PrivacyItem;
71import com.android.systemui.privacy.PrivacyItemController;
Jason Monke5b770e2017-03-03 21:49:29 -050072import com.android.systemui.qs.QSDetail.Callback;
Adrian Roos13836052018-03-15 21:06:37 +010073import com.android.systemui.statusbar.phone.PhoneStatusBarView;
Evan Laird95896952018-01-22 19:30:05 -050074import com.android.systemui.statusbar.phone.StatusBarIconController;
75import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
Evan Laird20b87bf2018-04-12 09:54:11 -040076import com.android.systemui.statusbar.phone.StatusIconContainer;
Fabian Kozynski12638242018-10-12 15:33:41 -040077import com.android.systemui.statusbar.phone.SystemUIDialog;
Evan Laird4bf21df2018-10-22 14:24:32 -040078import com.android.systemui.statusbar.policy.BatteryController;
Beverlyff2df9b2018-10-10 16:54:10 -040079import com.android.systemui.statusbar.policy.Clock;
Rohan Shahcc3d1d82018-03-30 21:24:17 +000080import com.android.systemui.statusbar.policy.DateView;
Rohan Shahd3cf7562018-02-23 11:12:28 -080081import com.android.systemui.statusbar.policy.NextAlarmController;
Beverlyb9826dd2018-04-12 15:02:45 -040082import com.android.systemui.statusbar.policy.ZenModeController;
Jason Monke5b770e2017-03-03 21:49:29 -050083
Evan Lairdf435fd22019-02-15 13:35:45 -050084import java.util.ArrayList;
Fabian Kozynski8d06c712018-11-07 10:33:02 -050085import java.util.List;
Lucas Dupin1f7374a2018-02-26 18:08:33 -080086import java.util.Locale;
Beverlyb9826dd2018-04-12 15:02:45 -040087import java.util.Objects;
Lucas Dupin1f7374a2018-02-26 18:08:33 -080088
Jason Monkea54e8a2018-12-20 10:01:48 -050089import javax.inject.Inject;
90import javax.inject.Named;
91
Rohan Shahd3cf7562018-02-23 11:12:28 -080092/**
93 * View that contains the top-most bits of the screen (primarily the status bar with date, time, and
94 * battery) and also contains the {@link QuickQSPanel} along with some of the panel's inner
95 * contents.
96 */
Amin Shaikhf09450b2018-04-06 17:32:45 -040097public class QuickStatusBarHeader extends RelativeLayout implements
Beverlyb9826dd2018-04-12 15:02:45 -040098 View.OnClickListener, NextAlarmController.NextAlarmChangeCallback,
99 ZenModeController.Callback {
Rohan Shaha160ab12018-03-09 15:47:36 -0800100 private static final String TAG = "QuickStatusBarHeader";
101 private static final boolean DEBUG = false;
Jason Monke5b770e2017-03-03 21:49:29 -0500102
Rohan Shahd3cf7562018-02-23 11:12:28 -0800103 /** Delay for auto fading out the long press tooltip after it's fully visible (in ms). */
104 private static final long AUTO_FADE_OUT_DELAY_MS = DateUtils.SECOND_IN_MILLIS * 6;
105 private static final int FADE_ANIMATION_DURATION_MS = 300;
106 private static final int TOOLTIP_NOT_YET_SHOWN_COUNT = 0;
Rohan Shahb6a915c2018-03-01 11:57:00 -0800107 public static final int MAX_TOOLTIP_SHOWN_COUNT = 2;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800108
109 private final Handler mHandler = new Handler();
Jason Monkea54e8a2018-12-20 10:01:48 -0500110 private final BatteryController mBatteryController;
111 private final NextAlarmController mAlarmController;
112 private final ZenModeController mZenController;
113 private final StatusBarIconController mStatusBarIconController;
114 private final ActivityStarter mActivityStarter;
Jason Monke5b770e2017-03-03 21:49:29 -0500115
116 private QSPanel mQsPanel;
117
118 private boolean mExpanded;
119 private boolean mListening;
Charles Hece2a7c02017-10-11 20:25:20 +0100120 private boolean mQsDisabled;
Jason Monke5b770e2017-03-03 21:49:29 -0500121
122 protected QuickQSPanel mHeaderQsPanel;
123 protected QSTileHost mHost;
Evan Laird95896952018-01-22 19:30:05 -0500124 private TintedIconManager mIconManager;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800125 private TouchAnimator mStatusIconsAlphaAnimator;
126 private TouchAnimator mHeaderTextContainerAlphaAnimator;
Fabian Kozynski216812e2019-02-01 13:49:00 -0500127 private TouchAnimator mPrivacyChipAlphaAnimator;
Evan Laird95896952018-01-22 19:30:05 -0500128
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000129 private View mSystemIconsView;
Evan Laird95896952018-01-22 19:30:05 -0500130 private View mQuickQsStatusIcons;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800131 private View mHeaderTextContainerView;
Amin Shaikh761c5662018-03-27 16:55:43 -0400132 /** View containing the next alarm and ringer mode info. */
133 private View mStatusContainer;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800134 /** Tooltip for educating users that they can long press on icons to see more details. */
135 private View mLongPressTooltipView;
Amin Shaikh761c5662018-03-27 16:55:43 -0400136
137 private int mRingerMode = AudioManager.RINGER_MODE_NORMAL;
138 private AlarmManager.AlarmClockInfo mNextAlarm;
139
140 private ImageView mNextAlarmIcon;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800141 /** {@link TextView} containing the actual text indicating when the next alarm will go off. */
142 private TextView mNextAlarmTextView;
Amin Shaikh761c5662018-03-27 16:55:43 -0400143 private View mStatusSeparator;
144 private ImageView mRingerModeIcon;
145 private TextView mRingerModeTextView;
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000146 private Clock mClockView;
147 private DateView mDateView;
Fabian Kozynski12638242018-10-12 15:33:41 -0400148 private OngoingPrivacyChip mPrivacyChip;
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500149 private Space mSpace;
Evan Laird4bf21df2018-10-22 14:24:32 -0400150 private BatteryMeterView mBatteryRemainingIcon;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800151
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500152 private PrivacyItemController mPrivacyItemController;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800153 /** Counts how many times the long press tooltip has been shown to the user. */
154 private int mShownCount;
155
Amin Shaikh761c5662018-03-27 16:55:43 -0400156 private final BroadcastReceiver mRingerReceiver = new BroadcastReceiver() {
157 @Override
158 public void onReceive(Context context, Intent intent) {
159 mRingerMode = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
160 updateStatusText();
161 }
162 };
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500163 private boolean mHasTopCutout = false;
Amin Shaikh761c5662018-03-27 16:55:43 -0400164
Evan Laird4bf21df2018-10-22 14:24:32 -0400165 private final PercentSettingObserver mPercentSettingObserver =
166 new PercentSettingObserver(new Handler(mContext.getMainLooper()));
167
Rohan Shahd3cf7562018-02-23 11:12:28 -0800168 /**
169 * Runnable for automatically fading out the long press tooltip (as if it were animating away).
170 */
171 private final Runnable mAutoFadeOutTooltipRunnable = () -> hideLongPressTooltip(false);
Evan Laird4ea2a492018-01-22 11:29:12 -0500172
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500173 private PrivacyItemController.Callback mPICCallback = new PrivacyItemController.Callback() {
174 @Override
175 public void privacyChanged(List<PrivacyItem> privacyItems) {
176 mPrivacyChip.setPrivacyList(privacyItems);
177 setChipVisibility(!privacyItems.isEmpty());
178 }
179 };
180
Jason Monkea54e8a2018-12-20 10:01:48 -0500181 @Inject
182 public QuickStatusBarHeader(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
183 NextAlarmController nextAlarmController, ZenModeController zenModeController,
184 BatteryController batteryController, StatusBarIconController statusBarIconController,
Fabian Kozynski04f83eb2019-01-22 10:38:40 -0500185 ActivityStarter activityStarter, PrivacyItemController privacyItemController) {
Jason Monke5b770e2017-03-03 21:49:29 -0500186 super(context, attrs);
Jason Monkea54e8a2018-12-20 10:01:48 -0500187 mAlarmController = nextAlarmController;
188 mZenController = zenModeController;
189 mBatteryController = batteryController;
190 mStatusBarIconController = statusBarIconController;
191 mActivityStarter = activityStarter;
Fabian Kozynski04f83eb2019-01-22 10:38:40 -0500192 mPrivacyItemController = privacyItemController;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800193 mShownCount = getStoredShownCount();
Jason Monke5b770e2017-03-03 21:49:29 -0500194 }
195
196 @Override
197 protected void onFinishInflate() {
198 super.onFinishInflate();
Jason Monke5b770e2017-03-03 21:49:29 -0500199
200 mHeaderQsPanel = findViewById(R.id.quick_qs_panel);
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000201 mSystemIconsView = findViewById(R.id.quick_status_bar_system_icons);
Evan Laird95896952018-01-22 19:30:05 -0500202 mQuickQsStatusIcons = findViewById(R.id.quick_qs_status_icons);
Evan Laird20b87bf2018-04-12 09:54:11 -0400203 StatusIconContainer iconContainer = findViewById(R.id.statusIcons);
Evan Lairdf435fd22019-02-15 13:35:45 -0500204 // Ignore privacy icons because they show in the space above QQS
205 iconContainer.addIgnoredSlots(getIgnoredIconSlots());
Evan Laird20b87bf2018-04-12 09:54:11 -0400206 iconContainer.setShouldRestrictIcons(false);
207 mIconManager = new TintedIconManager(iconContainer);
Jason Monke5b770e2017-03-03 21:49:29 -0500208
Rohan Shahd3cf7562018-02-23 11:12:28 -0800209 // Views corresponding to the header info section (e.g. tooltip and next alarm).
210 mHeaderTextContainerView = findViewById(R.id.header_text_container);
211 mLongPressTooltipView = findViewById(R.id.long_press_tooltip);
Amin Shaikh761c5662018-03-27 16:55:43 -0400212 mStatusContainer = findViewById(R.id.status_container);
213 mStatusSeparator = findViewById(R.id.status_separator);
214 mNextAlarmIcon = findViewById(R.id.next_alarm_icon);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800215 mNextAlarmTextView = findViewById(R.id.next_alarm_text);
Amin Shaikh761c5662018-03-27 16:55:43 -0400216 mRingerModeIcon = findViewById(R.id.ringer_mode_icon);
217 mRingerModeTextView = findViewById(R.id.ringer_mode_text);
Fabian Kozynski216812e2019-02-01 13:49:00 -0500218 mPrivacyChip = findViewById(R.id.privacy_chip);
219 mPrivacyChip.setOnClickListener(this);
Jason Monke5b770e2017-03-03 21:49:29 -0500220
221 updateResources();
222
Jason Monk824ffff2017-04-11 15:49:06 -0400223 Rect tintArea = new Rect(0, 0, 0, 0);
Jason Changb4e879d2018-04-11 11:17:58 +0800224 int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
225 android.R.attr.colorForeground);
Amin Shaikh0e003312018-03-08 11:39:01 -0500226 float intensity = getColorIntensity(colorForeground);
Evan Laird95896952018-01-22 19:30:05 -0500227 int fillColor = fillColorForIntensity(intensity, getContext());
228
229 // Set light text on the header icons because they will always be on a black background
Evan Laird39254d42018-01-18 16:05:30 -0500230 applyDarkness(R.id.clock, tintArea, 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
Evan Laird95896952018-01-22 19:30:05 -0500231
232 // Set the correct tint for the status icons so they contrast
233 mIconManager.setTint(fillColor);
Jason Monke5b770e2017-03-03 21:49:29 -0500234
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000235 mClockView = findViewById(R.id.clock);
Amin Shaikh39bdc502018-05-15 23:43:34 -0400236 mClockView.setOnClickListener(this);
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000237 mDateView = findViewById(R.id.date);
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500238 mSpace = findViewById(R.id.space);
Evan Laird4bf21df2018-10-22 14:24:32 -0400239
240 // Tint for the battery icons are handled in setupHost()
241 mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon);
Evan Laird698839b2018-12-05 15:49:12 -0500242 // Don't need to worry about tuner settings for this icon
243 mBatteryRemainingIcon.setIgnoreTunerUpdates(true);
Evan Laird4bf21df2018-10-22 14:24:32 -0400244 updateShowPercent();
Jason Monke5b770e2017-03-03 21:49:29 -0500245 }
246
Evan Lairdf435fd22019-02-15 13:35:45 -0500247 private List<String> getIgnoredIconSlots() {
248 ArrayList<String> ignored = new ArrayList<>();
249 ignored.add(mContext.getResources().getString(
250 com.android.internal.R.string.status_bar_camera));
251 ignored.add(mContext.getResources().getString(
252 com.android.internal.R.string.status_bar_microphone));
253 ignored.add(mContext.getResources().getString(
254 com.android.internal.R.string.status_bar_location));
255
256 return ignored;
257 }
258
Amin Shaikh761c5662018-03-27 16:55:43 -0400259 private void updateStatusText() {
Beverlyb9826dd2018-04-12 15:02:45 -0400260 boolean changed = updateRingerStatus() || updateAlarmStatus();
261
262 if (changed) {
263 boolean alarmVisible = mNextAlarmTextView.getVisibility() == View.VISIBLE;
264 boolean ringerVisible = mRingerModeTextView.getVisibility() == View.VISIBLE;
265 mStatusSeparator.setVisibility(alarmVisible && ringerVisible ? View.VISIBLE
266 : View.GONE);
267 updateTooltipShow();
268 }
269 }
270
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500271 private void setChipVisibility(boolean chipVisible) {
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500272 if (chipVisible) {
273 mPrivacyChip.setVisibility(View.VISIBLE);
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500274 } else {
275 mPrivacyChip.setVisibility(View.GONE);
276 }
277 }
278
Beverlyb9826dd2018-04-12 15:02:45 -0400279 private boolean updateRingerStatus() {
280 boolean isOriginalVisible = mRingerModeTextView.getVisibility() == View.VISIBLE;
281 CharSequence originalRingerText = mRingerModeTextView.getText();
282
Amin Shaikh761c5662018-03-27 16:55:43 -0400283 boolean ringerVisible = false;
Beverlyb9826dd2018-04-12 15:02:45 -0400284 if (!ZenModeConfig.isZenOverridingRinger(mZenController.getZen(),
Beverlyff2df9b2018-10-10 16:54:10 -0400285 mZenController.getConsolidatedPolicy())) {
Beverlyb9826dd2018-04-12 15:02:45 -0400286 if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
287 mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_vibrate);
288 mRingerModeTextView.setText(R.string.qs_status_phone_vibrate);
289 ringerVisible = true;
290 } else if (mRingerMode == AudioManager.RINGER_MODE_SILENT) {
291 mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_silent);
292 mRingerModeTextView.setText(R.string.qs_status_phone_muted);
293 ringerVisible = true;
294 }
Amin Shaikh761c5662018-03-27 16:55:43 -0400295 }
296 mRingerModeIcon.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
297 mRingerModeTextView.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
298
Beverlyb9826dd2018-04-12 15:02:45 -0400299 return isOriginalVisible != ringerVisible ||
300 !Objects.equals(originalRingerText, mRingerModeTextView.getText());
301 }
302
303 private boolean updateAlarmStatus() {
304 boolean isOriginalVisible = mNextAlarmTextView.getVisibility() == View.VISIBLE;
305 CharSequence originalAlarmText = mNextAlarmTextView.getText();
306
Amin Shaikh761c5662018-03-27 16:55:43 -0400307 boolean alarmVisible = false;
308 if (mNextAlarm != null) {
309 alarmVisible = true;
310 mNextAlarmTextView.setText(formatNextAlarm(mNextAlarm));
311 }
312 mNextAlarmIcon.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
313 mNextAlarmTextView.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
Amin Shaikh761c5662018-03-27 16:55:43 -0400314
Beverlyb9826dd2018-04-12 15:02:45 -0400315 return isOriginalVisible != alarmVisible ||
316 !Objects.equals(originalAlarmText, mNextAlarmTextView.getText());
317 }
Amin Shaikh761c5662018-03-27 16:55:43 -0400318
Jason Monk824ffff2017-04-11 15:49:06 -0400319 private void applyDarkness(int id, Rect tintArea, float intensity, int color) {
320 View v = findViewById(id);
321 if (v instanceof DarkReceiver) {
322 ((DarkReceiver) v).onDarkChanged(tintArea, intensity, color);
323 }
324 }
325
Evan Laird95896952018-01-22 19:30:05 -0500326 private int fillColorForIntensity(float intensity, Context context) {
327 if (intensity == 0) {
Amin Shaikh9cac3382018-04-11 17:10:07 -0400328 return context.getColor(R.color.light_mode_icon_color_single_tone);
Evan Laird95896952018-01-22 19:30:05 -0500329 }
Amin Shaikh9cac3382018-04-11 17:10:07 -0400330 return context.getColor(R.color.dark_mode_icon_color_single_tone);
Evan Laird95896952018-01-22 19:30:05 -0500331 }
332
Jason Monke5b770e2017-03-03 21:49:29 -0500333 @Override
334 protected void onConfigurationChanged(Configuration newConfig) {
335 super.onConfigurationChanged(newConfig);
336 updateResources();
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000337
338 // Update color schemes in landscape to use wallpaperTextColor
339 boolean shouldUseWallpaperTextColor =
340 newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE;
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000341 mClockView.useWallpaperTextColor(shouldUseWallpaperTextColor);
Jason Monke5b770e2017-03-03 21:49:29 -0500342 }
343
Fabian Kozynskief124492018-11-02 11:02:11 -0400344
345
Jason Monke5b770e2017-03-03 21:49:29 -0500346 @Override
347 public void onRtlPropertiesChanged(int layoutDirection) {
348 super.onRtlPropertiesChanged(layoutDirection);
349 updateResources();
350 }
351
Evan Laird84b98952018-07-02 17:43:59 -0400352 /**
353 * The height of QQS should always be the status bar height + 128dp. This is normally easy, but
354 * when there is a notch involved the status bar can remain a fixed pixel size.
355 */
356 private void updateMinimumHeight() {
357 int sbHeight = mContext.getResources().getDimensionPixelSize(
358 com.android.internal.R.dimen.status_bar_height);
359 int qqsHeight = mContext.getResources().getDimensionPixelSize(
360 R.dimen.qs_quick_header_panel_height);
361
362 setMinimumHeight(sbHeight + qqsHeight);
363 }
364
Jason Monke5b770e2017-03-03 21:49:29 -0500365 private void updateResources() {
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000366 Resources resources = mContext.getResources();
Evan Laird84b98952018-07-02 17:43:59 -0400367 updateMinimumHeight();
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000368
369 // Update height for a few views, especially due to landscape mode restricting space.
Rohan Shahd3cf7562018-02-23 11:12:28 -0800370 mHeaderTextContainerView.getLayoutParams().height =
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000371 resources.getDimensionPixelSize(R.dimen.qs_header_tooltip_height);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800372 mHeaderTextContainerView.setLayoutParams(mHeaderTextContainerView.getLayoutParams());
373
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000374 mSystemIconsView.getLayoutParams().height = resources.getDimensionPixelSize(
375 com.android.internal.R.dimen.quick_qs_offset_height);
376 mSystemIconsView.setLayoutParams(mSystemIconsView.getLayoutParams());
377
Evan Laird84b98952018-07-02 17:43:59 -0400378 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
379 if (mQsDisabled) {
380 lp.height = resources.getDimensionPixelSize(
381 com.android.internal.R.dimen.quick_qs_offset_height);
382 } else {
383 lp.height = Math.max(getMinimumHeight(),
384 resources.getDimensionPixelSize(
Evan Lairdbf3794a2018-07-17 15:55:40 -0400385 com.android.internal.R.dimen.quick_qs_total_height));
Evan Laird84b98952018-07-02 17:43:59 -0400386 }
387
388 setLayoutParams(lp);
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000389
Rohan Shahd3cf7562018-02-23 11:12:28 -0800390 updateStatusIconAlphaAnimator();
391 updateHeaderTextContainerAlphaAnimator();
Fabian Kozynski216812e2019-02-01 13:49:00 -0500392 updatePrivacyChipAlphaAnimator();
Evan Laird95896952018-01-22 19:30:05 -0500393 }
394
Rohan Shahd3cf7562018-02-23 11:12:28 -0800395 private void updateStatusIconAlphaAnimator() {
396 mStatusIconsAlphaAnimator = new TouchAnimator.Builder()
Evan Laird95896952018-01-22 19:30:05 -0500397 .addFloat(mQuickQsStatusIcons, "alpha", 1, 0)
398 .build();
Jason Monke5b770e2017-03-03 21:49:29 -0500399 }
400
Rohan Shahd3cf7562018-02-23 11:12:28 -0800401 private void updateHeaderTextContainerAlphaAnimator() {
402 mHeaderTextContainerAlphaAnimator = new TouchAnimator.Builder()
403 .addFloat(mHeaderTextContainerView, "alpha", 0, 1)
404 .setStartDelay(.5f)
405 .build();
Jason Monke5b770e2017-03-03 21:49:29 -0500406 }
407
Fabian Kozynski216812e2019-02-01 13:49:00 -0500408 private void updatePrivacyChipAlphaAnimator() {
409 mPrivacyChipAlphaAnimator = new TouchAnimator.Builder()
410 .addFloat(mPrivacyChip, "alpha", 1, 0, 1)
411 .build();
412 }
413
Jason Monke5b770e2017-03-03 21:49:29 -0500414 public void setExpanded(boolean expanded) {
415 if (mExpanded == expanded) return;
416 mExpanded = expanded;
417 mHeaderQsPanel.setExpanded(expanded);
Fabian Kozynskif3a77012019-01-09 15:37:30 +0000418 updateEverything();
Jason Monke5b770e2017-03-03 21:49:29 -0500419 }
420
Rohan Shahd3cf7562018-02-23 11:12:28 -0800421 /**
422 * Animates the inner contents based on the given expansion details.
423 *
424 * @param isKeyguardShowing whether or not we're showing the keyguard (a.k.a. lockscreen)
425 * @param expansionFraction how much the QS panel is expanded/pulled out (up to 1f)
426 * @param panelTranslationY how much the panel has physically moved down vertically (required
427 * for keyguard animations only)
428 */
429 public void setExpansion(boolean isKeyguardShowing, float expansionFraction,
430 float panelTranslationY) {
431 final float keyguardExpansionFraction = isKeyguardShowing ? 1f : expansionFraction;
432 if (mStatusIconsAlphaAnimator != null) {
433 mStatusIconsAlphaAnimator.setPosition(keyguardExpansionFraction);
Evan Laird95896952018-01-22 19:30:05 -0500434 }
Rohan Shahd3cf7562018-02-23 11:12:28 -0800435
436 if (isKeyguardShowing) {
437 // If the keyguard is showing, we want to offset the text so that it comes in at the
438 // same time as the panel as it slides down.
439 mHeaderTextContainerView.setTranslationY(panelTranslationY);
440 } else {
441 mHeaderTextContainerView.setTranslationY(0f);
442 }
443
444 if (mHeaderTextContainerAlphaAnimator != null) {
445 mHeaderTextContainerAlphaAnimator.setPosition(keyguardExpansionFraction);
446 }
Fabian Kozynski216812e2019-02-01 13:49:00 -0500447 if (mPrivacyChipAlphaAnimator != null) {
448 mPrivacyChip.setExpanded(expansionFraction > 0.5);
449 mPrivacyChipAlphaAnimator.setPosition(keyguardExpansionFraction);
450 }
Rohan Shahd3cf7562018-02-23 11:12:28 -0800451
452 // Check the original expansion fraction - we don't want to show the tooltip until the
453 // panel is pulled all the way out.
454 if (expansionFraction == 1f) {
455 // QS is fully expanded, bring in the tooltip.
456 showLongPressTooltip();
457 }
458 }
459
460 /** Returns the latest stored tooltip shown count from SharedPreferences. */
461 private int getStoredShownCount() {
462 return Prefs.getInt(
463 mContext,
464 Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
465 TOOLTIP_NOT_YET_SHOWN_COUNT);
Jason Monke5b770e2017-03-03 21:49:29 -0500466 }
467
Charles Hece2a7c02017-10-11 20:25:20 +0100468 public void disable(int state1, int state2, boolean animate) {
469 final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
470 if (disabled == mQsDisabled) return;
471 mQsDisabled = disabled;
472 mHeaderQsPanel.setDisabledByPolicy(disabled);
Amin Shaikhf09450b2018-04-06 17:32:45 -0400473 mHeaderTextContainerView.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
474 mQuickQsStatusIcons.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
475 updateResources();
Charles Hece2a7c02017-10-11 20:25:20 +0100476 }
477
478 @Override
479 public void onAttachedToWindow() {
Amin Shaikha59215a2018-04-23 08:52:38 -0400480 super.onAttachedToWindow();
Jason Monkea54e8a2018-12-20 10:01:48 -0500481 mStatusBarIconController.addIconGroup(mIconManager);
Adrian Roos13836052018-03-15 21:06:37 +0100482 requestApplyInsets();
Evan Laird4bf21df2018-10-22 14:24:32 -0400483 mContext.getContentResolver().registerContentObserver(
484 Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mPercentSettingObserver,
485 ActivityManager.getCurrentUser());
Adrian Roos13836052018-03-15 21:06:37 +0100486 }
487
488 @Override
489 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500490 DisplayCutout cutout = insets.getDisplayCutout();
Adrian Roos13836052018-03-15 21:06:37 +0100491 Pair<Integer, Integer> padding = PhoneStatusBarView.cornerCutoutMargins(
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500492 cutout, getDisplay());
Adrian Roos13836052018-03-15 21:06:37 +0100493 if (padding == null) {
Amin Shaikh7d86b042018-04-16 16:00:12 -0400494 mSystemIconsView.setPaddingRelative(
495 getResources().getDimensionPixelSize(R.dimen.status_bar_padding_start), 0,
496 getResources().getDimensionPixelSize(R.dimen.status_bar_padding_end), 0);
Adrian Roos13836052018-03-15 21:06:37 +0100497 } else {
Amin Shaikh7d86b042018-04-16 16:00:12 -0400498 mSystemIconsView.setPadding(padding.first, 0, padding.second, 0);
499
Adrian Roos13836052018-03-15 21:06:37 +0100500 }
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500501 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mSpace.getLayoutParams();
502 if (cutout != null) {
503 Rect topCutout = cutout.getBoundingRectTop();
504 if (topCutout.isEmpty()) {
505 mHasTopCutout = false;
506 lp.width = 0;
507 mSpace.setVisibility(View.GONE);
508 } else {
509 mHasTopCutout = true;
510 lp.width = topCutout.width();
511 mSpace.setVisibility(View.VISIBLE);
512 }
513 }
514 mSpace.setLayoutParams(lp);
Fabian Kozynski8d06c712018-11-07 10:33:02 -0500515 setChipVisibility(mPrivacyChip.getVisibility() == View.VISIBLE);
Adrian Roos13836052018-03-15 21:06:37 +0100516 return super.onApplyWindowInsets(insets);
Charles Hece2a7c02017-10-11 20:25:20 +0100517 }
518
519 @Override
Jason Monke5b770e2017-03-03 21:49:29 -0500520 @VisibleForTesting
521 public void onDetachedFromWindow() {
522 setListening(false);
Jason Monkea54e8a2018-12-20 10:01:48 -0500523 mStatusBarIconController.removeIconGroup(mIconManager);
Evan Laird4bf21df2018-10-22 14:24:32 -0400524 mContext.getContentResolver().unregisterContentObserver(mPercentSettingObserver);
Jason Monke5b770e2017-03-03 21:49:29 -0500525 super.onDetachedFromWindow();
526 }
527
528 public void setListening(boolean listening) {
529 if (listening == mListening) {
530 return;
531 }
532 mHeaderQsPanel.setListening(listening);
533 mListening = listening;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800534
535 if (listening) {
Beverlyb9826dd2018-04-12 15:02:45 -0400536 mZenController.addCallback(this);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800537 mAlarmController.addCallback(this);
Amin Shaikh761c5662018-03-27 16:55:43 -0400538 mContext.registerReceiver(mRingerReceiver,
539 new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
Fabian Kozynski04f83eb2019-01-22 10:38:40 -0500540 mPrivacyItemController.addCallback(mPICCallback);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800541 } else {
Beverlyb9826dd2018-04-12 15:02:45 -0400542 mZenController.removeCallback(this);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800543 mAlarmController.removeCallback(this);
Fabian Kozynski04f83eb2019-01-22 10:38:40 -0500544 mPrivacyItemController.removeCallback(mPICCallback);
Amin Shaikh761c5662018-03-27 16:55:43 -0400545 mContext.unregisterReceiver(mRingerReceiver);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800546 }
Jason Monke5b770e2017-03-03 21:49:29 -0500547 }
548
Evan Laird95896952018-01-22 19:30:05 -0500549 @Override
550 public void onClick(View v) {
Amin Shaikh39bdc502018-05-15 23:43:34 -0400551 if (v == mClockView) {
Jason Monkea54e8a2018-12-20 10:01:48 -0500552 mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
Evan Laird95896952018-01-22 19:30:05 -0500553 AlarmClock.ACTION_SHOW_ALARMS),0);
Fabian Kozynski12638242018-10-12 15:33:41 -0400554 } else if (v == mPrivacyChip) {
Fabian Kozynskiafd50022019-02-05 09:41:42 -0500555 // Makes sure that the builder is grabbed as soon as the chip is pressed
556 PrivacyDialogBuilder builder = mPrivacyChip.getBuilder();
557 if (builder.getAppsAndTypes().size() == 0) return;
Fabian Kozynski12638242018-10-12 15:33:41 -0400558 Handler mUiHandler = new Handler(Looper.getMainLooper());
559 mUiHandler.post(() -> {
Fabian Kozynskiafd50022019-02-05 09:41:42 -0500560 Dialog mDialog = new OngoingPrivacyDialog(mContext, builder).createDialog();
Fabian Kozynski8f3660e2019-02-11 11:02:11 -0500561 SystemUIDialog.setShowForAllUsers(mDialog, false);
Fabian Kozynski12638242018-10-12 15:33:41 -0400562 SystemUIDialog.registerDismissListener(mDialog);
563 SystemUIDialog.setWindowOnTop(mDialog);
Fabian Kozynski8f3660e2019-02-11 11:02:11 -0500564 mActivityStarter.postQSRunnableDismissingKeyguard(() -> mDialog.show());
Fabian Kozynski12638242018-10-12 15:33:41 -0400565 mHost.collapsePanels();
566 });
Evan Laird95896952018-01-22 19:30:05 -0500567 }
568 }
569
Rohan Shahd3cf7562018-02-23 11:12:28 -0800570 @Override
571 public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
Amin Shaikh761c5662018-03-27 16:55:43 -0400572 mNextAlarm = nextAlarm;
573 updateStatusText();
574 }
Rohan Shaha160ab12018-03-09 15:47:36 -0800575
Beverlyb9826dd2018-04-12 15:02:45 -0400576 @Override
577 public void onZenChanged(int zen) {
578 updateStatusText();
579
580 }
581
582 @Override
583 public void onConfigChanged(ZenModeConfig config) {
584 updateStatusText();
585 }
586
Amin Shaikh761c5662018-03-27 16:55:43 -0400587 private void updateTooltipShow() {
588 if (hasStatusText()) {
589 hideLongPressTooltip(true /* shouldShowStatusText */);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800590 } else {
Amin Shaikh761c5662018-03-27 16:55:43 -0400591 hideStatusText();
Rohan Shahd3cf7562018-02-23 11:12:28 -0800592 }
593 updateHeaderTextContainerAlphaAnimator();
594 }
595
Amin Shaikh761c5662018-03-27 16:55:43 -0400596 private boolean hasStatusText() {
597 return mNextAlarmTextView.getVisibility() == View.VISIBLE
598 || mRingerModeTextView.getVisibility() == View.VISIBLE;
599 }
600
Rohan Shahd3cf7562018-02-23 11:12:28 -0800601 /**
602 * Animates in the long press tooltip (as long as the next alarm text isn't currently occupying
603 * the space).
604 */
605 public void showLongPressTooltip() {
Amin Shaikh761c5662018-03-27 16:55:43 -0400606 // If we have status text to show, don't bother fading in the tooltip.
607 if (hasStatusText()) {
Rohan Shahd3cf7562018-02-23 11:12:28 -0800608 return;
609 }
610
611 if (mShownCount < MAX_TOOLTIP_SHOWN_COUNT) {
612 mLongPressTooltipView.animate().cancel();
613 mLongPressTooltipView.setVisibility(View.VISIBLE);
614 mLongPressTooltipView.animate()
615 .alpha(1f)
616 .setDuration(FADE_ANIMATION_DURATION_MS)
617 .setListener(new AnimatorListenerAdapter() {
618 @Override
619 public void onAnimationEnd(Animator animation) {
620 mHandler.postDelayed(
621 mAutoFadeOutTooltipRunnable, AUTO_FADE_OUT_DELAY_MS);
622 }
623 })
624 .start();
625
626 // Increment and drop the shown count in prefs for the next time we're deciding to
627 // fade in the tooltip. We first sanity check that the tooltip count hasn't changed yet
628 // in prefs (say, from a long press).
629 if (getStoredShownCount() <= mShownCount) {
630 Prefs.putInt(mContext, Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT, ++mShownCount);
631 }
632 }
633 }
634
635 /**
636 * Fades out the long press tooltip if it's partially visible - short circuits any running
Amin Shaikh761c5662018-03-27 16:55:43 -0400637 * animation. Additionally has the ability to fade in the status info text.
Rohan Shahd3cf7562018-02-23 11:12:28 -0800638 *
Amin Shaikh761c5662018-03-27 16:55:43 -0400639 * @param shouldShowStatusText whether we should fade in the status text
Rohan Shahd3cf7562018-02-23 11:12:28 -0800640 */
Amin Shaikh761c5662018-03-27 16:55:43 -0400641 private void hideLongPressTooltip(boolean shouldShowStatusText) {
Rohan Shahd3cf7562018-02-23 11:12:28 -0800642 mLongPressTooltipView.animate().cancel();
643 if (mLongPressTooltipView.getVisibility() == View.VISIBLE
644 && mLongPressTooltipView.getAlpha() != 0f) {
645 mHandler.removeCallbacks(mAutoFadeOutTooltipRunnable);
646 mLongPressTooltipView.animate()
647 .alpha(0f)
648 .setDuration(FADE_ANIMATION_DURATION_MS)
649 .setListener(new AnimatorListenerAdapter() {
650 @Override
651 public void onAnimationEnd(Animator animation) {
Rohan Shaha160ab12018-03-09 15:47:36 -0800652 if (DEBUG) Log.d(TAG, "hideLongPressTooltip: Hid long press tip");
Rohan Shahd3cf7562018-02-23 11:12:28 -0800653 mLongPressTooltipView.setVisibility(View.INVISIBLE);
654
Amin Shaikh761c5662018-03-27 16:55:43 -0400655 if (shouldShowStatusText) {
656 showStatus();
Rohan Shahd3cf7562018-02-23 11:12:28 -0800657 }
658 }
659 })
660 .start();
661 } else {
662 mLongPressTooltipView.setVisibility(View.INVISIBLE);
Amin Shaikh761c5662018-03-27 16:55:43 -0400663 if (shouldShowStatusText) {
664 showStatus();
Rohan Shahd3cf7562018-02-23 11:12:28 -0800665 }
666 }
667 }
668
669 /**
Amin Shaikh761c5662018-03-27 16:55:43 -0400670 * Fades in the updated status text. Note that if there's already a status showing, this will
Fabian Kozynski3f789332018-09-04 16:42:43 -0400671 * immediately fade it out and fade in the updated status.
Rohan Shahd3cf7562018-02-23 11:12:28 -0800672 */
Amin Shaikh761c5662018-03-27 16:55:43 -0400673 private void showStatus() {
674 mStatusContainer.setAlpha(0f);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800675
Amin Shaikh761c5662018-03-27 16:55:43 -0400676 mStatusContainer.animate()
Rohan Shahd3cf7562018-02-23 11:12:28 -0800677 .alpha(1f)
678 .setDuration(FADE_ANIMATION_DURATION_MS)
679 .start();
680 }
681
Fabian Kozynski3f789332018-09-04 16:42:43 -0400682 /** Fades out the status text. */
Amin Shaikh761c5662018-03-27 16:55:43 -0400683 private void hideStatusText() {
Fabian Kozynski3f789332018-09-04 16:42:43 -0400684 mStatusContainer.animate()
685 .alpha(0f)
686 .setDuration(FADE_ANIMATION_DURATION_MS)
687 .start();
Rohan Shahd3cf7562018-02-23 11:12:28 -0800688 }
689
Fabian Kozynskif3a77012019-01-09 15:37:30 +0000690 public void updateEverything() {
Fabian Kozynski9a15b7c2019-01-10 11:13:27 -0500691 post(() -> setClickable(!mExpanded));
Fabian Kozynskif3a77012019-01-09 15:37:30 +0000692 }
693
Jason Monke5b770e2017-03-03 21:49:29 -0500694 public void setQSPanel(final QSPanel qsPanel) {
695 mQsPanel = qsPanel;
696 setupHost(qsPanel.getHost());
697 }
698
699 public void setupHost(final QSTileHost host) {
700 mHost = host;
701 //host.setHeaderView(mExpandIndicator);
702 mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
703 mHeaderQsPanel.setHost(host, null /* No customization in header */);
Evan Lairdef160f22018-01-29 14:08:45 -0500704
Evan Laird4bf21df2018-10-22 14:24:32 -0400705
706 Rect tintArea = new Rect(0, 0, 0, 0);
707 int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
708 android.R.attr.colorForeground);
709 float intensity = getColorIntensity(colorForeground);
710 int fillColor = fillColorForIntensity(intensity, getContext());
711 mBatteryRemainingIcon.setColorsFromContext(mHost.getContext());
712 mBatteryRemainingIcon.onDarkChanged(tintArea, intensity, fillColor);
Jason Monke5b770e2017-03-03 21:49:29 -0500713 }
714
715 public void setCallback(Callback qsPanelCallback) {
716 mHeaderQsPanel.setCallback(qsPanelCallback);
717 }
Lucas Dupin1f7374a2018-02-26 18:08:33 -0800718
719 private String formatNextAlarm(AlarmManager.AlarmClockInfo info) {
720 if (info == null) {
721 return "";
722 }
723 String skeleton = android.text.format.DateFormat
724 .is24HourFormat(mContext, ActivityManager.getCurrentUser()) ? "EHm" : "Ehma";
725 String pattern = android.text.format.DateFormat
726 .getBestDateTimePattern(Locale.getDefault(), skeleton);
727 return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString();
728 }
Amin Shaikh0e003312018-03-08 11:39:01 -0500729
730 public static float getColorIntensity(@ColorInt int color) {
731 return color == Color.WHITE ? 0 : 1;
732 }
Amin Shaikh50d2d1e2018-04-25 14:48:13 -0400733
734 public void setMargins(int sideMargins) {
735 for (int i = 0; i < getChildCount(); i++) {
736 View v = getChildAt(i);
Fabian Kozynskief124492018-11-02 11:02:11 -0400737 if (v == mSystemIconsView || v == mQuickQsStatusIcons || v == mHeaderQsPanel
738 || v == mPrivacyChip) {
Amin Shaikh50d2d1e2018-04-25 14:48:13 -0400739 continue;
740 }
741 RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) v.getLayoutParams();
742 lp.leftMargin = sideMargins;
743 lp.rightMargin = sideMargins;
744 }
745 }
Evan Laird4bf21df2018-10-22 14:24:32 -0400746
747 private void updateShowPercent() {
748 final boolean systemSetting = 0 != Settings.System
749 .getIntForUser(getContext().getContentResolver(),
750 SHOW_BATTERY_PERCENT, 0, ActivityManager.getCurrentUser());
751
Evan Lairda5a73c52019-01-11 13:36:32 -0500752 mBatteryRemainingIcon.setPercentShowMode(systemSetting
753 ? BatteryMeterView.MODE_ESTIMATE : BatteryMeterView.MODE_ON);
Evan Laird4bf21df2018-10-22 14:24:32 -0400754 }
755
756 private final class PercentSettingObserver extends ContentObserver {
757 PercentSettingObserver(Handler handler) {
758 super(handler);
759 }
760
761 @Override
762 public void onChange(boolean selfChange, Uri uri) {
763 super.onChange(selfChange, uri);
764 updateShowPercent();
765 }
766 }
Jason Monke5b770e2017-03-03 21:49:29 -0500767}