blob: a9bfa45b6a734c255d33dbf306e8b4764ecdfb40 [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;
Charles Hece2a7c02017-10-11 20:25:20 +010018
Rohan Shahd3cf7562018-02-23 11:12:28 -080019import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
Amin Shaikh0e003312018-03-08 11:39:01 -050021import android.annotation.ColorInt;
Lucas Dupin1f7374a2018-02-26 18:08:33 -080022import android.app.ActivityManager;
Rohan Shahd3cf7562018-02-23 11:12:28 -080023import android.app.AlarmManager;
Amin Shaikh761c5662018-03-27 16:55:43 -040024import android.content.BroadcastReceiver;
Jason Monke5b770e2017-03-03 21:49:29 -050025import android.content.Context;
Evan Laird4ea2a492018-01-22 11:29:12 -050026import android.content.Intent;
Amin Shaikh761c5662018-03-27 16:55:43 -040027import android.content.IntentFilter;
Jason Monke5b770e2017-03-03 21:49:29 -050028import android.content.res.Configuration;
Rohan Shahcc3d1d82018-03-30 21:24:17 +000029import android.content.res.Resources;
Jason Monke5b770e2017-03-03 21:49:29 -050030import android.graphics.Color;
31import android.graphics.Rect;
Amin Shaikh761c5662018-03-27 16:55:43 -040032import android.media.AudioManager;
Rohan Shahd3cf7562018-02-23 11:12:28 -080033import android.os.Handler;
Evan Laird4ea2a492018-01-22 11:29:12 -050034import android.provider.AlarmClock;
Beverlyb9826dd2018-04-12 15:02:45 -040035import android.service.notification.ZenModeConfig;
Jason Monke5b770e2017-03-03 21:49:29 -050036import android.support.annotation.VisibleForTesting;
Rohan Shahd3cf7562018-02-23 11:12:28 -080037import android.text.format.DateUtils;
Jason Monke5b770e2017-03-03 21:49:29 -050038import android.util.AttributeSet;
Rohan Shaha160ab12018-03-09 15:47:36 -080039import android.util.Log;
Adrian Roos13836052018-03-15 21:06:37 +010040import android.util.Pair;
Jason Monk824ffff2017-04-11 15:49:06 -040041import android.view.View;
Adrian Roos13836052018-03-15 21:06:37 +010042import android.view.WindowInsets;
Amin Shaikh761c5662018-03-27 16:55:43 -040043import android.widget.ImageView;
Amin Shaikh50d2d1e2018-04-25 14:48:13 -040044import android.widget.LinearLayout;
Jason Monke5b770e2017-03-03 21:49:29 -050045import android.widget.RelativeLayout;
Rohan Shahd3cf7562018-02-23 11:12:28 -080046import android.widget.TextView;
Jason Monke5b770e2017-03-03 21:49:29 -050047
48import com.android.settingslib.Utils;
49import com.android.systemui.BatteryMeterView;
50import com.android.systemui.Dependency;
Rohan Shahd3cf7562018-02-23 11:12:28 -080051import com.android.systemui.Prefs;
Jason Monke5b770e2017-03-03 21:49:29 -050052import com.android.systemui.R;
53import com.android.systemui.plugins.ActivityStarter;
54import com.android.systemui.qs.QSDetail.Callback;
Adrian Roos13836052018-03-15 21:06:37 +010055import com.android.systemui.statusbar.phone.PhoneStatusBarView;
Evan Laird95896952018-01-22 19:30:05 -050056import com.android.systemui.statusbar.phone.StatusBarIconController;
57import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
Rohan Shahcc3d1d82018-03-30 21:24:17 +000058import com.android.systemui.statusbar.policy.Clock;
Evan Laird20b87bf2018-04-12 09:54:11 -040059import com.android.systemui.statusbar.phone.StatusIconContainer;
Evan Laird39254d42018-01-18 16:05:30 -050060import com.android.systemui.statusbar.policy.DarkIconDispatcher;
Jason Monk824ffff2017-04-11 15:49:06 -040061import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
Rohan Shahcc3d1d82018-03-30 21:24:17 +000062import com.android.systemui.statusbar.policy.DateView;
Rohan Shahd3cf7562018-02-23 11:12:28 -080063import com.android.systemui.statusbar.policy.NextAlarmController;
Beverlyb9826dd2018-04-12 15:02:45 -040064import com.android.systemui.statusbar.policy.ZenModeController;
Jason Monke5b770e2017-03-03 21:49:29 -050065
Lucas Dupin1f7374a2018-02-26 18:08:33 -080066import java.util.Locale;
Beverlyb9826dd2018-04-12 15:02:45 -040067import java.util.Objects;
Lucas Dupin1f7374a2018-02-26 18:08:33 -080068
Rohan Shahd3cf7562018-02-23 11:12:28 -080069/**
70 * View that contains the top-most bits of the screen (primarily the status bar with date, time, and
71 * battery) and also contains the {@link QuickQSPanel} along with some of the panel's inner
72 * contents.
73 */
Amin Shaikhf09450b2018-04-06 17:32:45 -040074public class QuickStatusBarHeader extends RelativeLayout implements
Beverlyb9826dd2018-04-12 15:02:45 -040075 View.OnClickListener, NextAlarmController.NextAlarmChangeCallback,
76 ZenModeController.Callback {
Rohan Shaha160ab12018-03-09 15:47:36 -080077 private static final String TAG = "QuickStatusBarHeader";
78 private static final boolean DEBUG = false;
Jason Monke5b770e2017-03-03 21:49:29 -050079
Rohan Shahd3cf7562018-02-23 11:12:28 -080080 /** Delay for auto fading out the long press tooltip after it's fully visible (in ms). */
81 private static final long AUTO_FADE_OUT_DELAY_MS = DateUtils.SECOND_IN_MILLIS * 6;
82 private static final int FADE_ANIMATION_DURATION_MS = 300;
83 private static final int TOOLTIP_NOT_YET_SHOWN_COUNT = 0;
Rohan Shahb6a915c2018-03-01 11:57:00 -080084 public static final int MAX_TOOLTIP_SHOWN_COUNT = 2;
Rohan Shahd3cf7562018-02-23 11:12:28 -080085
86 private final Handler mHandler = new Handler();
Jason Monke5b770e2017-03-03 21:49:29 -050087
88 private QSPanel mQsPanel;
89
90 private boolean mExpanded;
91 private boolean mListening;
Charles Hece2a7c02017-10-11 20:25:20 +010092 private boolean mQsDisabled;
Jason Monke5b770e2017-03-03 21:49:29 -050093
94 protected QuickQSPanel mHeaderQsPanel;
95 protected QSTileHost mHost;
Evan Laird95896952018-01-22 19:30:05 -050096 private TintedIconManager mIconManager;
Rohan Shahd3cf7562018-02-23 11:12:28 -080097 private TouchAnimator mStatusIconsAlphaAnimator;
98 private TouchAnimator mHeaderTextContainerAlphaAnimator;
Evan Laird95896952018-01-22 19:30:05 -050099
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000100 private View mSystemIconsView;
Evan Laird95896952018-01-22 19:30:05 -0500101 private View mQuickQsStatusIcons;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800102 private View mHeaderTextContainerView;
Amin Shaikh761c5662018-03-27 16:55:43 -0400103 /** View containing the next alarm and ringer mode info. */
104 private View mStatusContainer;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800105 /** Tooltip for educating users that they can long press on icons to see more details. */
106 private View mLongPressTooltipView;
Amin Shaikh761c5662018-03-27 16:55:43 -0400107
108 private int mRingerMode = AudioManager.RINGER_MODE_NORMAL;
109 private AlarmManager.AlarmClockInfo mNextAlarm;
110
111 private ImageView mNextAlarmIcon;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800112 /** {@link TextView} containing the actual text indicating when the next alarm will go off. */
113 private TextView mNextAlarmTextView;
Amin Shaikh761c5662018-03-27 16:55:43 -0400114 private View mStatusSeparator;
115 private ImageView mRingerModeIcon;
116 private TextView mRingerModeTextView;
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000117 private BatteryMeterView mBatteryMeterView;
118 private Clock mClockView;
119 private DateView mDateView;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800120
121 private NextAlarmController mAlarmController;
Beverlyb9826dd2018-04-12 15:02:45 -0400122 private ZenModeController mZenController;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800123 /** Counts how many times the long press tooltip has been shown to the user. */
124 private int mShownCount;
125
Amin Shaikh761c5662018-03-27 16:55:43 -0400126 private final BroadcastReceiver mRingerReceiver = new BroadcastReceiver() {
127 @Override
128 public void onReceive(Context context, Intent intent) {
129 mRingerMode = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
130 updateStatusText();
131 }
132 };
133
Rohan Shahd3cf7562018-02-23 11:12:28 -0800134 /**
135 * Runnable for automatically fading out the long press tooltip (as if it were animating away).
136 */
137 private final Runnable mAutoFadeOutTooltipRunnable = () -> hideLongPressTooltip(false);
Evan Laird4ea2a492018-01-22 11:29:12 -0500138
Jason Monke5b770e2017-03-03 21:49:29 -0500139 public QuickStatusBarHeader(Context context, AttributeSet attrs) {
140 super(context, attrs);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800141 mAlarmController = Dependency.get(NextAlarmController.class);
Beverlyb9826dd2018-04-12 15:02:45 -0400142 mZenController = Dependency.get(ZenModeController.class);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800143 mShownCount = getStoredShownCount();
Jason Monke5b770e2017-03-03 21:49:29 -0500144 }
145
146 @Override
147 protected void onFinishInflate() {
148 super.onFinishInflate();
Jason Monke5b770e2017-03-03 21:49:29 -0500149
150 mHeaderQsPanel = findViewById(R.id.quick_qs_panel);
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000151 mSystemIconsView = findViewById(R.id.quick_status_bar_system_icons);
Evan Laird95896952018-01-22 19:30:05 -0500152 mQuickQsStatusIcons = findViewById(R.id.quick_qs_status_icons);
Evan Laird20b87bf2018-04-12 09:54:11 -0400153 StatusIconContainer iconContainer = findViewById(R.id.statusIcons);
154 iconContainer.setShouldRestrictIcons(false);
155 mIconManager = new TintedIconManager(iconContainer);
Jason Monke5b770e2017-03-03 21:49:29 -0500156
Rohan Shahd3cf7562018-02-23 11:12:28 -0800157 // Views corresponding to the header info section (e.g. tooltip and next alarm).
158 mHeaderTextContainerView = findViewById(R.id.header_text_container);
159 mLongPressTooltipView = findViewById(R.id.long_press_tooltip);
Amin Shaikh761c5662018-03-27 16:55:43 -0400160 mStatusContainer = findViewById(R.id.status_container);
161 mStatusSeparator = findViewById(R.id.status_separator);
162 mNextAlarmIcon = findViewById(R.id.next_alarm_icon);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800163 mNextAlarmTextView = findViewById(R.id.next_alarm_text);
Amin Shaikh761c5662018-03-27 16:55:43 -0400164 mRingerModeIcon = findViewById(R.id.ringer_mode_icon);
165 mRingerModeTextView = findViewById(R.id.ringer_mode_text);
Jason Monke5b770e2017-03-03 21:49:29 -0500166
167 updateResources();
168
Jason Monk824ffff2017-04-11 15:49:06 -0400169 Rect tintArea = new Rect(0, 0, 0, 0);
Evan Laird95896952018-01-22 19:30:05 -0500170 int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground);
Amin Shaikh0e003312018-03-08 11:39:01 -0500171 float intensity = getColorIntensity(colorForeground);
Evan Laird95896952018-01-22 19:30:05 -0500172 int fillColor = fillColorForIntensity(intensity, getContext());
173
174 // Set light text on the header icons because they will always be on a black background
Evan Laird39254d42018-01-18 16:05:30 -0500175 applyDarkness(R.id.clock, tintArea, 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
Evan Laird95896952018-01-22 19:30:05 -0500176
177 // Set the correct tint for the status icons so they contrast
178 mIconManager.setTint(fillColor);
Jason Monke5b770e2017-03-03 21:49:29 -0500179
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000180 mBatteryMeterView = findViewById(R.id.battery);
181 mBatteryMeterView.setForceShowPercent(true);
Amin Shaikh39bdc502018-05-15 23:43:34 -0400182 mBatteryMeterView.setOnClickListener(this);
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000183 mClockView = findViewById(R.id.clock);
Amin Shaikh39bdc502018-05-15 23:43:34 -0400184 mClockView.setOnClickListener(this);
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000185 mDateView = findViewById(R.id.date);
Jason Monke5b770e2017-03-03 21:49:29 -0500186 }
187
Amin Shaikh761c5662018-03-27 16:55:43 -0400188 private void updateStatusText() {
Beverlyb9826dd2018-04-12 15:02:45 -0400189 boolean changed = updateRingerStatus() || updateAlarmStatus();
190
191 if (changed) {
192 boolean alarmVisible = mNextAlarmTextView.getVisibility() == View.VISIBLE;
193 boolean ringerVisible = mRingerModeTextView.getVisibility() == View.VISIBLE;
194 mStatusSeparator.setVisibility(alarmVisible && ringerVisible ? View.VISIBLE
195 : View.GONE);
196 updateTooltipShow();
197 }
198 }
199
200 private boolean updateRingerStatus() {
201 boolean isOriginalVisible = mRingerModeTextView.getVisibility() == View.VISIBLE;
202 CharSequence originalRingerText = mRingerModeTextView.getText();
203
Amin Shaikh761c5662018-03-27 16:55:43 -0400204 boolean ringerVisible = false;
Beverlyb9826dd2018-04-12 15:02:45 -0400205 if (!ZenModeConfig.isZenOverridingRinger(mZenController.getZen(),
206 mZenController.getConfig())) {
207 if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
208 mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_vibrate);
209 mRingerModeTextView.setText(R.string.qs_status_phone_vibrate);
210 ringerVisible = true;
211 } else if (mRingerMode == AudioManager.RINGER_MODE_SILENT) {
212 mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_silent);
213 mRingerModeTextView.setText(R.string.qs_status_phone_muted);
214 ringerVisible = true;
215 }
Amin Shaikh761c5662018-03-27 16:55:43 -0400216 }
217 mRingerModeIcon.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
218 mRingerModeTextView.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
219
Beverlyb9826dd2018-04-12 15:02:45 -0400220 return isOriginalVisible != ringerVisible ||
221 !Objects.equals(originalRingerText, mRingerModeTextView.getText());
222 }
223
224 private boolean updateAlarmStatus() {
225 boolean isOriginalVisible = mNextAlarmTextView.getVisibility() == View.VISIBLE;
226 CharSequence originalAlarmText = mNextAlarmTextView.getText();
227
Amin Shaikh761c5662018-03-27 16:55:43 -0400228 boolean alarmVisible = false;
229 if (mNextAlarm != null) {
230 alarmVisible = true;
231 mNextAlarmTextView.setText(formatNextAlarm(mNextAlarm));
232 }
233 mNextAlarmIcon.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
234 mNextAlarmTextView.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
Amin Shaikh761c5662018-03-27 16:55:43 -0400235
Beverlyb9826dd2018-04-12 15:02:45 -0400236 return isOriginalVisible != alarmVisible ||
237 !Objects.equals(originalAlarmText, mNextAlarmTextView.getText());
238 }
Amin Shaikh761c5662018-03-27 16:55:43 -0400239
Jason Monk824ffff2017-04-11 15:49:06 -0400240 private void applyDarkness(int id, Rect tintArea, float intensity, int color) {
241 View v = findViewById(id);
242 if (v instanceof DarkReceiver) {
243 ((DarkReceiver) v).onDarkChanged(tintArea, intensity, color);
244 }
245 }
246
Evan Laird95896952018-01-22 19:30:05 -0500247 private int fillColorForIntensity(float intensity, Context context) {
248 if (intensity == 0) {
Amin Shaikh9cac3382018-04-11 17:10:07 -0400249 return context.getColor(R.color.light_mode_icon_color_single_tone);
Evan Laird95896952018-01-22 19:30:05 -0500250 }
Amin Shaikh9cac3382018-04-11 17:10:07 -0400251 return context.getColor(R.color.dark_mode_icon_color_single_tone);
Evan Laird95896952018-01-22 19:30:05 -0500252 }
253
Jason Monke5b770e2017-03-03 21:49:29 -0500254 @Override
255 protected void onConfigurationChanged(Configuration newConfig) {
256 super.onConfigurationChanged(newConfig);
257 updateResources();
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000258
259 // Update color schemes in landscape to use wallpaperTextColor
260 boolean shouldUseWallpaperTextColor =
261 newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE;
262 mBatteryMeterView.useWallpaperTextColor(shouldUseWallpaperTextColor);
263 mClockView.useWallpaperTextColor(shouldUseWallpaperTextColor);
Jason Monke5b770e2017-03-03 21:49:29 -0500264 }
265
266 @Override
267 public void onRtlPropertiesChanged(int layoutDirection) {
268 super.onRtlPropertiesChanged(layoutDirection);
269 updateResources();
270 }
271
272 private void updateResources() {
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000273 Resources resources = mContext.getResources();
274
275 // Update height for a few views, especially due to landscape mode restricting space.
Rohan Shahd3cf7562018-02-23 11:12:28 -0800276 mHeaderTextContainerView.getLayoutParams().height =
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000277 resources.getDimensionPixelSize(R.dimen.qs_header_tooltip_height);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800278 mHeaderTextContainerView.setLayoutParams(mHeaderTextContainerView.getLayoutParams());
279
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000280 mSystemIconsView.getLayoutParams().height = resources.getDimensionPixelSize(
281 com.android.internal.R.dimen.quick_qs_offset_height);
282 mSystemIconsView.setLayoutParams(mSystemIconsView.getLayoutParams());
283
Amin Shaikhf09450b2018-04-06 17:32:45 -0400284 getLayoutParams().height = resources.getDimensionPixelSize(mQsDisabled
285 ? com.android.internal.R.dimen.quick_qs_offset_height
286 : com.android.internal.R.dimen.quick_qs_total_height);
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000287 setLayoutParams(getLayoutParams());
288
Rohan Shahd3cf7562018-02-23 11:12:28 -0800289 updateStatusIconAlphaAnimator();
290 updateHeaderTextContainerAlphaAnimator();
Evan Laird95896952018-01-22 19:30:05 -0500291 }
292
Rohan Shahd3cf7562018-02-23 11:12:28 -0800293 private void updateStatusIconAlphaAnimator() {
294 mStatusIconsAlphaAnimator = new TouchAnimator.Builder()
Evan Laird95896952018-01-22 19:30:05 -0500295 .addFloat(mQuickQsStatusIcons, "alpha", 1, 0)
296 .build();
Jason Monke5b770e2017-03-03 21:49:29 -0500297 }
298
Rohan Shahd3cf7562018-02-23 11:12:28 -0800299 private void updateHeaderTextContainerAlphaAnimator() {
300 mHeaderTextContainerAlphaAnimator = new TouchAnimator.Builder()
301 .addFloat(mHeaderTextContainerView, "alpha", 0, 1)
302 .setStartDelay(.5f)
303 .build();
Jason Monke5b770e2017-03-03 21:49:29 -0500304 }
305
306 public void setExpanded(boolean expanded) {
307 if (mExpanded == expanded) return;
308 mExpanded = expanded;
309 mHeaderQsPanel.setExpanded(expanded);
310 updateEverything();
311 }
312
Rohan Shahd3cf7562018-02-23 11:12:28 -0800313 /**
314 * Animates the inner contents based on the given expansion details.
315 *
316 * @param isKeyguardShowing whether or not we're showing the keyguard (a.k.a. lockscreen)
317 * @param expansionFraction how much the QS panel is expanded/pulled out (up to 1f)
318 * @param panelTranslationY how much the panel has physically moved down vertically (required
319 * for keyguard animations only)
320 */
321 public void setExpansion(boolean isKeyguardShowing, float expansionFraction,
322 float panelTranslationY) {
323 final float keyguardExpansionFraction = isKeyguardShowing ? 1f : expansionFraction;
324 if (mStatusIconsAlphaAnimator != null) {
325 mStatusIconsAlphaAnimator.setPosition(keyguardExpansionFraction);
Evan Laird95896952018-01-22 19:30:05 -0500326 }
Rohan Shahd3cf7562018-02-23 11:12:28 -0800327
328 if (isKeyguardShowing) {
329 // If the keyguard is showing, we want to offset the text so that it comes in at the
330 // same time as the panel as it slides down.
331 mHeaderTextContainerView.setTranslationY(panelTranslationY);
332 } else {
333 mHeaderTextContainerView.setTranslationY(0f);
334 }
335
336 if (mHeaderTextContainerAlphaAnimator != null) {
337 mHeaderTextContainerAlphaAnimator.setPosition(keyguardExpansionFraction);
338 }
339
340 // Check the original expansion fraction - we don't want to show the tooltip until the
341 // panel is pulled all the way out.
342 if (expansionFraction == 1f) {
343 // QS is fully expanded, bring in the tooltip.
344 showLongPressTooltip();
345 }
346 }
347
348 /** Returns the latest stored tooltip shown count from SharedPreferences. */
349 private int getStoredShownCount() {
350 return Prefs.getInt(
351 mContext,
352 Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
353 TOOLTIP_NOT_YET_SHOWN_COUNT);
Jason Monke5b770e2017-03-03 21:49:29 -0500354 }
355
Charles Hece2a7c02017-10-11 20:25:20 +0100356 public void disable(int state1, int state2, boolean animate) {
357 final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
358 if (disabled == mQsDisabled) return;
359 mQsDisabled = disabled;
360 mHeaderQsPanel.setDisabledByPolicy(disabled);
Amin Shaikhf09450b2018-04-06 17:32:45 -0400361 mHeaderTextContainerView.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
362 mQuickQsStatusIcons.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
363 updateResources();
Charles Hece2a7c02017-10-11 20:25:20 +0100364 }
365
366 @Override
367 public void onAttachedToWindow() {
Amin Shaikha59215a2018-04-23 08:52:38 -0400368 super.onAttachedToWindow();
Evan Laird95896952018-01-22 19:30:05 -0500369 Dependency.get(StatusBarIconController.class).addIconGroup(mIconManager);
Adrian Roos13836052018-03-15 21:06:37 +0100370 requestApplyInsets();
371 }
372
373 @Override
374 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
375 Pair<Integer, Integer> padding = PhoneStatusBarView.cornerCutoutMargins(
376 insets.getDisplayCutout(), getDisplay());
377 if (padding == null) {
Amin Shaikh7d86b042018-04-16 16:00:12 -0400378 mSystemIconsView.setPaddingRelative(
379 getResources().getDimensionPixelSize(R.dimen.status_bar_padding_start), 0,
380 getResources().getDimensionPixelSize(R.dimen.status_bar_padding_end), 0);
Adrian Roos13836052018-03-15 21:06:37 +0100381 } else {
Amin Shaikh7d86b042018-04-16 16:00:12 -0400382 mSystemIconsView.setPadding(padding.first, 0, padding.second, 0);
383
Adrian Roos13836052018-03-15 21:06:37 +0100384 }
385 return super.onApplyWindowInsets(insets);
Charles Hece2a7c02017-10-11 20:25:20 +0100386 }
387
388 @Override
Jason Monke5b770e2017-03-03 21:49:29 -0500389 @VisibleForTesting
390 public void onDetachedFromWindow() {
391 setListening(false);
Evan Laird95896952018-01-22 19:30:05 -0500392 Dependency.get(StatusBarIconController.class).removeIconGroup(mIconManager);
Jason Monke5b770e2017-03-03 21:49:29 -0500393 super.onDetachedFromWindow();
394 }
395
396 public void setListening(boolean listening) {
397 if (listening == mListening) {
398 return;
399 }
400 mHeaderQsPanel.setListening(listening);
401 mListening = listening;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800402
403 if (listening) {
Beverlyb9826dd2018-04-12 15:02:45 -0400404 mZenController.addCallback(this);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800405 mAlarmController.addCallback(this);
Amin Shaikh761c5662018-03-27 16:55:43 -0400406 mContext.registerReceiver(mRingerReceiver,
407 new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
Rohan Shahd3cf7562018-02-23 11:12:28 -0800408 } else {
Beverlyb9826dd2018-04-12 15:02:45 -0400409 mZenController.removeCallback(this);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800410 mAlarmController.removeCallback(this);
Amin Shaikh761c5662018-03-27 16:55:43 -0400411 mContext.unregisterReceiver(mRingerReceiver);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800412 }
Jason Monke5b770e2017-03-03 21:49:29 -0500413 }
414
Evan Laird95896952018-01-22 19:30:05 -0500415 @Override
416 public void onClick(View v) {
Amin Shaikh39bdc502018-05-15 23:43:34 -0400417 if (v == mClockView) {
Evan Laird95896952018-01-22 19:30:05 -0500418 Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(new Intent(
419 AlarmClock.ACTION_SHOW_ALARMS),0);
Amin Shaikh39bdc502018-05-15 23:43:34 -0400420 } else if (v == mBatteryMeterView) {
421 Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(new Intent(
422 Intent.ACTION_POWER_USAGE_SUMMARY),0);
Evan Laird95896952018-01-22 19:30:05 -0500423 }
424 }
425
Rohan Shahd3cf7562018-02-23 11:12:28 -0800426 @Override
427 public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
Amin Shaikh761c5662018-03-27 16:55:43 -0400428 mNextAlarm = nextAlarm;
429 updateStatusText();
430 }
Rohan Shaha160ab12018-03-09 15:47:36 -0800431
Beverlyb9826dd2018-04-12 15:02:45 -0400432 @Override
433 public void onZenChanged(int zen) {
434 updateStatusText();
435
436 }
437
438 @Override
439 public void onConfigChanged(ZenModeConfig config) {
440 updateStatusText();
441 }
442
Amin Shaikh761c5662018-03-27 16:55:43 -0400443 private void updateTooltipShow() {
444 if (hasStatusText()) {
445 hideLongPressTooltip(true /* shouldShowStatusText */);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800446 } else {
Amin Shaikh761c5662018-03-27 16:55:43 -0400447 hideStatusText();
Rohan Shahd3cf7562018-02-23 11:12:28 -0800448 }
449 updateHeaderTextContainerAlphaAnimator();
450 }
451
Amin Shaikh761c5662018-03-27 16:55:43 -0400452 private boolean hasStatusText() {
453 return mNextAlarmTextView.getVisibility() == View.VISIBLE
454 || mRingerModeTextView.getVisibility() == View.VISIBLE;
455 }
456
Rohan Shahd3cf7562018-02-23 11:12:28 -0800457 /**
458 * Animates in the long press tooltip (as long as the next alarm text isn't currently occupying
459 * the space).
460 */
461 public void showLongPressTooltip() {
Amin Shaikh761c5662018-03-27 16:55:43 -0400462 // If we have status text to show, don't bother fading in the tooltip.
463 if (hasStatusText()) {
Rohan Shahd3cf7562018-02-23 11:12:28 -0800464 return;
465 }
466
467 if (mShownCount < MAX_TOOLTIP_SHOWN_COUNT) {
468 mLongPressTooltipView.animate().cancel();
469 mLongPressTooltipView.setVisibility(View.VISIBLE);
470 mLongPressTooltipView.animate()
471 .alpha(1f)
472 .setDuration(FADE_ANIMATION_DURATION_MS)
473 .setListener(new AnimatorListenerAdapter() {
474 @Override
475 public void onAnimationEnd(Animator animation) {
476 mHandler.postDelayed(
477 mAutoFadeOutTooltipRunnable, AUTO_FADE_OUT_DELAY_MS);
478 }
479 })
480 .start();
481
482 // Increment and drop the shown count in prefs for the next time we're deciding to
483 // fade in the tooltip. We first sanity check that the tooltip count hasn't changed yet
484 // in prefs (say, from a long press).
485 if (getStoredShownCount() <= mShownCount) {
486 Prefs.putInt(mContext, Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT, ++mShownCount);
487 }
488 }
489 }
490
491 /**
492 * Fades out the long press tooltip if it's partially visible - short circuits any running
Amin Shaikh761c5662018-03-27 16:55:43 -0400493 * animation. Additionally has the ability to fade in the status info text.
Rohan Shahd3cf7562018-02-23 11:12:28 -0800494 *
Amin Shaikh761c5662018-03-27 16:55:43 -0400495 * @param shouldShowStatusText whether we should fade in the status text
Rohan Shahd3cf7562018-02-23 11:12:28 -0800496 */
Amin Shaikh761c5662018-03-27 16:55:43 -0400497 private void hideLongPressTooltip(boolean shouldShowStatusText) {
Rohan Shahd3cf7562018-02-23 11:12:28 -0800498 mLongPressTooltipView.animate().cancel();
499 if (mLongPressTooltipView.getVisibility() == View.VISIBLE
500 && mLongPressTooltipView.getAlpha() != 0f) {
501 mHandler.removeCallbacks(mAutoFadeOutTooltipRunnable);
502 mLongPressTooltipView.animate()
503 .alpha(0f)
504 .setDuration(FADE_ANIMATION_DURATION_MS)
505 .setListener(new AnimatorListenerAdapter() {
506 @Override
507 public void onAnimationEnd(Animator animation) {
Rohan Shaha160ab12018-03-09 15:47:36 -0800508 if (DEBUG) Log.d(TAG, "hideLongPressTooltip: Hid long press tip");
Rohan Shahd3cf7562018-02-23 11:12:28 -0800509 mLongPressTooltipView.setVisibility(View.INVISIBLE);
510
Amin Shaikh761c5662018-03-27 16:55:43 -0400511 if (shouldShowStatusText) {
512 showStatus();
Rohan Shahd3cf7562018-02-23 11:12:28 -0800513 }
514 }
515 })
516 .start();
517 } else {
518 mLongPressTooltipView.setVisibility(View.INVISIBLE);
Amin Shaikh761c5662018-03-27 16:55:43 -0400519 if (shouldShowStatusText) {
520 showStatus();
Rohan Shahd3cf7562018-02-23 11:12:28 -0800521 }
522 }
523 }
524
525 /**
Amin Shaikh761c5662018-03-27 16:55:43 -0400526 * Fades in the updated status text. Note that if there's already a status showing, this will
527 * immediately hide it and fade in the updated status.
Rohan Shahd3cf7562018-02-23 11:12:28 -0800528 */
Amin Shaikh761c5662018-03-27 16:55:43 -0400529 private void showStatus() {
530 mStatusContainer.setAlpha(0f);
531 mStatusContainer.setVisibility(View.VISIBLE);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800532
Rohan Shaha160ab12018-03-09 15:47:36 -0800533 // Animate the alarm back in. Make sure to clear the animator listener for the animation!
Amin Shaikh761c5662018-03-27 16:55:43 -0400534 mStatusContainer.animate()
Rohan Shahd3cf7562018-02-23 11:12:28 -0800535 .alpha(1f)
536 .setDuration(FADE_ANIMATION_DURATION_MS)
Rohan Shaha160ab12018-03-09 15:47:36 -0800537 .setListener(null)
Rohan Shahd3cf7562018-02-23 11:12:28 -0800538 .start();
539 }
540
Amin Shaikh761c5662018-03-27 16:55:43 -0400541 /** Fades out and hides the status text. */
542 private void hideStatusText() {
543 if (mStatusContainer.getVisibility() == View.VISIBLE) {
544 mStatusContainer.animate()
Rohan Shahd3cf7562018-02-23 11:12:28 -0800545 .alpha(0f)
546 .setListener(new AnimatorListenerAdapter() {
547 @Override
548 public void onAnimationEnd(Animator animation) {
Rohan Shaha160ab12018-03-09 15:47:36 -0800549 if (DEBUG) Log.d(TAG, "hideAlarmText: Hid alarm text");
550
Rohan Shahd3cf7562018-02-23 11:12:28 -0800551 // Reset the alpha regardless of how the animation ends for the next
552 // time we show this view/want to animate it.
Amin Shaikh761c5662018-03-27 16:55:43 -0400553 mStatusContainer.setVisibility(View.INVISIBLE);
554 mStatusContainer.setAlpha(1f);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800555 }
556 })
557 .start();
Rohan Shahd3cf7562018-02-23 11:12:28 -0800558 }
559 }
560
Jason Monke5b770e2017-03-03 21:49:29 -0500561 public void updateEverything() {
Jason Monk1fdde2d2017-03-08 09:39:21 -0500562 post(() -> setClickable(false));
Jason Monke5b770e2017-03-03 21:49:29 -0500563 }
564
565 public void setQSPanel(final QSPanel qsPanel) {
566 mQsPanel = qsPanel;
567 setupHost(qsPanel.getHost());
568 }
569
570 public void setupHost(final QSTileHost host) {
571 mHost = host;
572 //host.setHeaderView(mExpandIndicator);
573 mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
574 mHeaderQsPanel.setHost(host, null /* No customization in header */);
Evan Lairdef160f22018-01-29 14:08:45 -0500575
576 // Use SystemUI context to get battery meter colors, and let it use the default tint (white)
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000577 mBatteryMeterView.setColorsFromContext(mHost.getContext());
578 mBatteryMeterView.onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
Jason Monke5b770e2017-03-03 21:49:29 -0500579 }
580
581 public void setCallback(Callback qsPanelCallback) {
582 mHeaderQsPanel.setCallback(qsPanelCallback);
583 }
Lucas Dupin1f7374a2018-02-26 18:08:33 -0800584
585 private String formatNextAlarm(AlarmManager.AlarmClockInfo info) {
586 if (info == null) {
587 return "";
588 }
589 String skeleton = android.text.format.DateFormat
590 .is24HourFormat(mContext, ActivityManager.getCurrentUser()) ? "EHm" : "Ehma";
591 String pattern = android.text.format.DateFormat
592 .getBestDateTimePattern(Locale.getDefault(), skeleton);
593 return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString();
594 }
Amin Shaikh0e003312018-03-08 11:39:01 -0500595
596 public static float getColorIntensity(@ColorInt int color) {
597 return color == Color.WHITE ? 0 : 1;
598 }
Amin Shaikh50d2d1e2018-04-25 14:48:13 -0400599
600 public void setMargins(int sideMargins) {
601 for (int i = 0; i < getChildCount(); i++) {
602 View v = getChildAt(i);
603 if (v == mSystemIconsView || v == mQuickQsStatusIcons || v == mHeaderQsPanel) {
604 continue;
605 }
606 RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) v.getLayoutParams();
607 lp.leftMargin = sideMargins;
608 lp.rightMargin = sideMargins;
609 }
610 }
Jason Monke5b770e2017-03-03 21:49:29 -0500611}