blob: ca88d704fd87be8e5afb28fb488efdf74aba994c [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 Shahbc204ef2018-03-09 15:11:58 -080029import 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;
Jason Monke5b770e2017-03-03 21:49:29 -050035import android.support.annotation.VisibleForTesting;
Rohan Shahd3cf7562018-02-23 11:12:28 -080036import android.text.format.DateUtils;
Jason Monke5b770e2017-03-03 21:49:29 -050037import android.util.AttributeSet;
Rohan Shaha160ab12018-03-09 15:47:36 -080038import android.util.Log;
Adrian Roos13836052018-03-15 21:06:37 +010039import android.util.Pair;
Jason Monk824ffff2017-04-11 15:49:06 -040040import android.view.View;
Adrian Roos13836052018-03-15 21:06:37 +010041import android.view.WindowInsets;
Amin Shaikh761c5662018-03-27 16:55:43 -040042import android.widget.ImageView;
Jason Monke5b770e2017-03-03 21:49:29 -050043import android.widget.RelativeLayout;
Rohan Shahd3cf7562018-02-23 11:12:28 -080044import android.widget.TextView;
Jason Monke5b770e2017-03-03 21:49:29 -050045
46import com.android.settingslib.Utils;
47import com.android.systemui.BatteryMeterView;
48import com.android.systemui.Dependency;
Rohan Shahd3cf7562018-02-23 11:12:28 -080049import com.android.systemui.Prefs;
Jason Monke5b770e2017-03-03 21:49:29 -050050import com.android.systemui.R;
Jason Monk01df36f2017-06-07 13:02:47 -040051import com.android.systemui.R.id;
Charles Hece2a7c02017-10-11 20:25:20 +010052import com.android.systemui.SysUiServiceProvider;
Jason Monke5b770e2017-03-03 21:49:29 -050053import com.android.systemui.plugins.ActivityStarter;
54import com.android.systemui.qs.QSDetail.Callback;
Charles Hece2a7c02017-10-11 20:25:20 +010055import com.android.systemui.statusbar.CommandQueue;
Adrian Roos13836052018-03-15 21:06:37 +010056import com.android.systemui.statusbar.phone.PhoneStatusBarView;
Evan Laird95896952018-01-22 19:30:05 -050057import com.android.systemui.statusbar.phone.StatusBarIconController;
58import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
Rohan Shahbc204ef2018-03-09 15:11:58 -080059import com.android.systemui.statusbar.policy.Clock;
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 Shahbc204ef2018-03-09 15:11:58 -080062import com.android.systemui.statusbar.policy.DateView;
Rohan Shahd3cf7562018-02-23 11:12:28 -080063import com.android.systemui.statusbar.policy.NextAlarmController;
Jason Monke5b770e2017-03-03 21:49:29 -050064
Lucas Dupin1f7374a2018-02-26 18:08:33 -080065import java.util.Locale;
66
Rohan Shahd3cf7562018-02-23 11:12:28 -080067/**
68 * View that contains the top-most bits of the screen (primarily the status bar with date, time, and
69 * battery) and also contains the {@link QuickQSPanel} along with some of the panel's inner
70 * contents.
71 */
72public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue.Callbacks,
73 View.OnClickListener, NextAlarmController.NextAlarmChangeCallback {
Rohan Shaha160ab12018-03-09 15:47:36 -080074 private static final String TAG = "QuickStatusBarHeader";
75 private static final boolean DEBUG = false;
Jason Monke5b770e2017-03-03 21:49:29 -050076
Rohan Shahd3cf7562018-02-23 11:12:28 -080077 /** Delay for auto fading out the long press tooltip after it's fully visible (in ms). */
78 private static final long AUTO_FADE_OUT_DELAY_MS = DateUtils.SECOND_IN_MILLIS * 6;
79 private static final int FADE_ANIMATION_DURATION_MS = 300;
80 private static final int TOOLTIP_NOT_YET_SHOWN_COUNT = 0;
Rohan Shahb6a915c2018-03-01 11:57:00 -080081 public static final int MAX_TOOLTIP_SHOWN_COUNT = 2;
Rohan Shahd3cf7562018-02-23 11:12:28 -080082
83 private final Handler mHandler = new Handler();
Jason Monke5b770e2017-03-03 21:49:29 -050084
85 private QSPanel mQsPanel;
86
87 private boolean mExpanded;
88 private boolean mListening;
Charles Hece2a7c02017-10-11 20:25:20 +010089 private boolean mQsDisabled;
Jason Monke5b770e2017-03-03 21:49:29 -050090
91 protected QuickQSPanel mHeaderQsPanel;
92 protected QSTileHost mHost;
Evan Laird95896952018-01-22 19:30:05 -050093 private TintedIconManager mIconManager;
Rohan Shahd3cf7562018-02-23 11:12:28 -080094 private TouchAnimator mStatusIconsAlphaAnimator;
95 private TouchAnimator mHeaderTextContainerAlphaAnimator;
Evan Laird95896952018-01-22 19:30:05 -050096
Rohan Shahbc204ef2018-03-09 15:11:58 -080097 private View mSystemIconsView;
Evan Laird95896952018-01-22 19:30:05 -050098 private View mQuickQsStatusIcons;
Evan Laird4ea2a492018-01-22 11:29:12 -050099 private View mDate;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800100 private View mHeaderTextContainerView;
Amin Shaikh761c5662018-03-27 16:55:43 -0400101 /** View containing the next alarm and ringer mode info. */
102 private View mStatusContainer;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800103 /** Tooltip for educating users that they can long press on icons to see more details. */
104 private View mLongPressTooltipView;
Amin Shaikh761c5662018-03-27 16:55:43 -0400105
106 private int mRingerMode = AudioManager.RINGER_MODE_NORMAL;
107 private AlarmManager.AlarmClockInfo mNextAlarm;
108
109 private ImageView mNextAlarmIcon;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800110 /** {@link TextView} containing the actual text indicating when the next alarm will go off. */
111 private TextView mNextAlarmTextView;
Amin Shaikh761c5662018-03-27 16:55:43 -0400112 private View mStatusSeparator;
113 private ImageView mRingerModeIcon;
114 private TextView mRingerModeTextView;
Rohan Shahbc204ef2018-03-09 15:11:58 -0800115 private BatteryMeterView mBatteryMeterView;
116 private Clock mClockView;
117 private DateView mDateView;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800118
119 private NextAlarmController mAlarmController;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800120 /** Counts how many times the long press tooltip has been shown to the user. */
121 private int mShownCount;
122
Amin Shaikh761c5662018-03-27 16:55:43 -0400123 private final BroadcastReceiver mRingerReceiver = new BroadcastReceiver() {
124 @Override
125 public void onReceive(Context context, Intent intent) {
126 mRingerMode = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
127 updateStatusText();
128 }
129 };
130
Rohan Shahd3cf7562018-02-23 11:12:28 -0800131 /**
132 * Runnable for automatically fading out the long press tooltip (as if it were animating away).
133 */
134 private final Runnable mAutoFadeOutTooltipRunnable = () -> hideLongPressTooltip(false);
Evan Laird4ea2a492018-01-22 11:29:12 -0500135
Jason Monke5b770e2017-03-03 21:49:29 -0500136 public QuickStatusBarHeader(Context context, AttributeSet attrs) {
137 super(context, attrs);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800138 mAlarmController = Dependency.get(NextAlarmController.class);
139 mShownCount = getStoredShownCount();
Jason Monke5b770e2017-03-03 21:49:29 -0500140 }
141
142 @Override
143 protected void onFinishInflate() {
144 super.onFinishInflate();
Jason Monke5b770e2017-03-03 21:49:29 -0500145
146 mHeaderQsPanel = findViewById(R.id.quick_qs_panel);
Evan Laird4ea2a492018-01-22 11:29:12 -0500147 mDate = findViewById(R.id.date);
148 mDate.setOnClickListener(this);
Rohan Shahbc204ef2018-03-09 15:11:58 -0800149 mSystemIconsView = findViewById(R.id.quick_status_bar_system_icons);
Evan Laird95896952018-01-22 19:30:05 -0500150 mQuickQsStatusIcons = findViewById(R.id.quick_qs_status_icons);
151 mIconManager = new TintedIconManager(findViewById(R.id.statusIcons));
Jason Monke5b770e2017-03-03 21:49:29 -0500152
Rohan Shahd3cf7562018-02-23 11:12:28 -0800153 // Views corresponding to the header info section (e.g. tooltip and next alarm).
154 mHeaderTextContainerView = findViewById(R.id.header_text_container);
155 mLongPressTooltipView = findViewById(R.id.long_press_tooltip);
Amin Shaikh761c5662018-03-27 16:55:43 -0400156 mStatusContainer = findViewById(R.id.status_container);
157 mStatusSeparator = findViewById(R.id.status_separator);
158 mNextAlarmIcon = findViewById(R.id.next_alarm_icon);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800159 mNextAlarmTextView = findViewById(R.id.next_alarm_text);
Amin Shaikh761c5662018-03-27 16:55:43 -0400160 mRingerModeIcon = findViewById(R.id.ringer_mode_icon);
161 mRingerModeTextView = findViewById(R.id.ringer_mode_text);
Jason Monke5b770e2017-03-03 21:49:29 -0500162
163 updateResources();
164
Jason Monk824ffff2017-04-11 15:49:06 -0400165 Rect tintArea = new Rect(0, 0, 0, 0);
Evan Laird95896952018-01-22 19:30:05 -0500166 int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground);
Amin Shaikh0e003312018-03-08 11:39:01 -0500167 float intensity = getColorIntensity(colorForeground);
Evan Laird95896952018-01-22 19:30:05 -0500168 int fillColor = fillColorForIntensity(intensity, getContext());
169
170 // Set light text on the header icons because they will always be on a black background
Evan Laird39254d42018-01-18 16:05:30 -0500171 applyDarkness(R.id.clock, tintArea, 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
Evan Laird95896952018-01-22 19:30:05 -0500172 applyDarkness(id.signal_cluster, tintArea, intensity, colorForeground);
173
174 // Set the correct tint for the status icons so they contrast
175 mIconManager.setTint(fillColor);
Jason Monke5b770e2017-03-03 21:49:29 -0500176
Rohan Shahbc204ef2018-03-09 15:11:58 -0800177 mBatteryMeterView = findViewById(R.id.battery);
178 mBatteryMeterView.setForceShowPercent(true);
179 mClockView = findViewById(R.id.clock);
180 mDateView = findViewById(R.id.date);
Jason Monke5b770e2017-03-03 21:49:29 -0500181 }
182
Amin Shaikh761c5662018-03-27 16:55:43 -0400183 private void updateStatusText() {
184 boolean ringerVisible = false;
185 if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
186 mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_vibrate);
187 mRingerModeTextView.setText(R.string.volume_ringer_status_vibrate);
188 ringerVisible = true;
189 } else if (mRingerMode == AudioManager.RINGER_MODE_SILENT) {
190 mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_silent);
191 mRingerModeTextView.setText(R.string.volume_ringer_status_silent);
192 ringerVisible = true;
193 }
194 mRingerModeIcon.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
195 mRingerModeTextView.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
196
197 boolean alarmVisible = false;
198 if (mNextAlarm != null) {
199 alarmVisible = true;
200 mNextAlarmTextView.setText(formatNextAlarm(mNextAlarm));
201 }
202 mNextAlarmIcon.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
203 mNextAlarmTextView.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
204 mStatusSeparator.setVisibility(alarmVisible && ringerVisible ? View.VISIBLE : View.GONE);
205 updateTooltipShow();
206 }
207
208
Jason Monk824ffff2017-04-11 15:49:06 -0400209 private void applyDarkness(int id, Rect tintArea, float intensity, int color) {
210 View v = findViewById(id);
211 if (v instanceof DarkReceiver) {
212 ((DarkReceiver) v).onDarkChanged(tintArea, intensity, color);
213 }
214 }
215
Evan Laird95896952018-01-22 19:30:05 -0500216 private int fillColorForIntensity(float intensity, Context context) {
217 if (intensity == 0) {
218 return context.getColor(R.color.light_mode_icon_color_dual_tone_fill);
219 }
220 return context.getColor(R.color.dark_mode_icon_color_dual_tone_fill);
221 }
222
Jason Monke5b770e2017-03-03 21:49:29 -0500223 @Override
224 protected void onConfigurationChanged(Configuration newConfig) {
225 super.onConfigurationChanged(newConfig);
226 updateResources();
Rohan Shahbc204ef2018-03-09 15:11:58 -0800227
228 // Update color schemes in landscape to use wallpaperTextColor
229 boolean shouldUseWallpaperTextColor =
230 newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE;
231 mBatteryMeterView.useWallpaperTextColor(shouldUseWallpaperTextColor);
232 mClockView.useWallpaperTextColor(shouldUseWallpaperTextColor);
233 mDateView.useWallpaperTextColor(shouldUseWallpaperTextColor);
Jason Monke5b770e2017-03-03 21:49:29 -0500234 }
235
236 @Override
237 public void onRtlPropertiesChanged(int layoutDirection) {
238 super.onRtlPropertiesChanged(layoutDirection);
239 updateResources();
240 }
241
242 private void updateResources() {
Rohan Shahbc204ef2018-03-09 15:11:58 -0800243 Resources resources = mContext.getResources();
244
245 // Update height for a few views, especially due to landscape mode restricting space.
Rohan Shahd3cf7562018-02-23 11:12:28 -0800246 mHeaderTextContainerView.getLayoutParams().height =
Rohan Shahbc204ef2018-03-09 15:11:58 -0800247 resources.getDimensionPixelSize(R.dimen.qs_header_tooltip_height);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800248 mHeaderTextContainerView.setLayoutParams(mHeaderTextContainerView.getLayoutParams());
249
Rohan Shahbc204ef2018-03-09 15:11:58 -0800250 mSystemIconsView.getLayoutParams().height = resources.getDimensionPixelSize(
251 com.android.internal.R.dimen.quick_qs_offset_height);
252 mSystemIconsView.setLayoutParams(mSystemIconsView.getLayoutParams());
253
254 getLayoutParams().height =
255 resources.getDimensionPixelSize(com.android.internal.R.dimen.quick_qs_total_height);
256 setLayoutParams(getLayoutParams());
257
Rohan Shahd3cf7562018-02-23 11:12:28 -0800258 updateStatusIconAlphaAnimator();
259 updateHeaderTextContainerAlphaAnimator();
Evan Laird95896952018-01-22 19:30:05 -0500260 }
261
Rohan Shahd3cf7562018-02-23 11:12:28 -0800262 private void updateStatusIconAlphaAnimator() {
263 mStatusIconsAlphaAnimator = new TouchAnimator.Builder()
Evan Laird95896952018-01-22 19:30:05 -0500264 .addFloat(mQuickQsStatusIcons, "alpha", 1, 0)
265 .build();
Jason Monke5b770e2017-03-03 21:49:29 -0500266 }
267
Rohan Shahd3cf7562018-02-23 11:12:28 -0800268 private void updateHeaderTextContainerAlphaAnimator() {
269 mHeaderTextContainerAlphaAnimator = new TouchAnimator.Builder()
270 .addFloat(mHeaderTextContainerView, "alpha", 0, 1)
271 .setStartDelay(.5f)
272 .build();
Jason Monke5b770e2017-03-03 21:49:29 -0500273 }
274
275 public void setExpanded(boolean expanded) {
276 if (mExpanded == expanded) return;
277 mExpanded = expanded;
278 mHeaderQsPanel.setExpanded(expanded);
279 updateEverything();
280 }
281
Rohan Shahd3cf7562018-02-23 11:12:28 -0800282 /**
283 * Animates the inner contents based on the given expansion details.
284 *
285 * @param isKeyguardShowing whether or not we're showing the keyguard (a.k.a. lockscreen)
286 * @param expansionFraction how much the QS panel is expanded/pulled out (up to 1f)
287 * @param panelTranslationY how much the panel has physically moved down vertically (required
288 * for keyguard animations only)
289 */
290 public void setExpansion(boolean isKeyguardShowing, float expansionFraction,
291 float panelTranslationY) {
292 final float keyguardExpansionFraction = isKeyguardShowing ? 1f : expansionFraction;
293 if (mStatusIconsAlphaAnimator != null) {
294 mStatusIconsAlphaAnimator.setPosition(keyguardExpansionFraction);
Evan Laird95896952018-01-22 19:30:05 -0500295 }
Rohan Shahd3cf7562018-02-23 11:12:28 -0800296
297 if (isKeyguardShowing) {
298 // If the keyguard is showing, we want to offset the text so that it comes in at the
299 // same time as the panel as it slides down.
300 mHeaderTextContainerView.setTranslationY(panelTranslationY);
301 } else {
302 mHeaderTextContainerView.setTranslationY(0f);
303 }
304
305 if (mHeaderTextContainerAlphaAnimator != null) {
306 mHeaderTextContainerAlphaAnimator.setPosition(keyguardExpansionFraction);
307 }
308
309 // Check the original expansion fraction - we don't want to show the tooltip until the
310 // panel is pulled all the way out.
311 if (expansionFraction == 1f) {
312 // QS is fully expanded, bring in the tooltip.
313 showLongPressTooltip();
314 }
315 }
316
317 /** Returns the latest stored tooltip shown count from SharedPreferences. */
318 private int getStoredShownCount() {
319 return Prefs.getInt(
320 mContext,
321 Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
322 TOOLTIP_NOT_YET_SHOWN_COUNT);
Jason Monke5b770e2017-03-03 21:49:29 -0500323 }
324
325 @Override
Charles Hece2a7c02017-10-11 20:25:20 +0100326 public void disable(int state1, int state2, boolean animate) {
327 final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
328 if (disabled == mQsDisabled) return;
329 mQsDisabled = disabled;
330 mHeaderQsPanel.setDisabledByPolicy(disabled);
Evan Laird19bf52c2018-01-24 19:54:58 -0500331 final int rawHeight = (int) getResources().getDimension(
332 com.android.internal.R.dimen.quick_qs_total_height);
Charles Hece2a7c02017-10-11 20:25:20 +0100333 getLayoutParams().height = disabled ? (rawHeight - mHeaderQsPanel.getHeight()) : rawHeight;
334 }
335
336 @Override
337 public void onAttachedToWindow() {
338 SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this);
Evan Laird95896952018-01-22 19:30:05 -0500339 Dependency.get(StatusBarIconController.class).addIconGroup(mIconManager);
Adrian Roos13836052018-03-15 21:06:37 +0100340 requestApplyInsets();
341 }
342
343 @Override
344 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
345 Pair<Integer, Integer> padding = PhoneStatusBarView.cornerCutoutMargins(
346 insets.getDisplayCutout(), getDisplay());
347 if (padding == null) {
348 setPadding(0, 0, 0, 0);
349 } else {
350 setPadding(padding.first, 0, padding.second, 0);
351 }
352 return super.onApplyWindowInsets(insets);
Charles Hece2a7c02017-10-11 20:25:20 +0100353 }
354
355 @Override
Jason Monke5b770e2017-03-03 21:49:29 -0500356 @VisibleForTesting
357 public void onDetachedFromWindow() {
358 setListening(false);
Charles Hece2a7c02017-10-11 20:25:20 +0100359 SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).removeCallbacks(this);
Evan Laird95896952018-01-22 19:30:05 -0500360 Dependency.get(StatusBarIconController.class).removeIconGroup(mIconManager);
Jason Monke5b770e2017-03-03 21:49:29 -0500361 super.onDetachedFromWindow();
362 }
363
364 public void setListening(boolean listening) {
365 if (listening == mListening) {
366 return;
367 }
368 mHeaderQsPanel.setListening(listening);
369 mListening = listening;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800370
371 if (listening) {
372 mAlarmController.addCallback(this);
Amin Shaikh761c5662018-03-27 16:55:43 -0400373 mContext.registerReceiver(mRingerReceiver,
374 new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
Rohan Shahd3cf7562018-02-23 11:12:28 -0800375 } else {
376 mAlarmController.removeCallback(this);
Amin Shaikh761c5662018-03-27 16:55:43 -0400377 mContext.unregisterReceiver(mRingerReceiver);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800378 }
Jason Monke5b770e2017-03-03 21:49:29 -0500379 }
380
Evan Laird95896952018-01-22 19:30:05 -0500381 @Override
382 public void onClick(View v) {
383 if(v == mDate){
384 Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(new Intent(
385 AlarmClock.ACTION_SHOW_ALARMS),0);
386 }
387 }
388
Rohan Shahd3cf7562018-02-23 11:12:28 -0800389 @Override
390 public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
Amin Shaikh761c5662018-03-27 16:55:43 -0400391 mNextAlarm = nextAlarm;
392 updateStatusText();
393 }
Rohan Shaha160ab12018-03-09 15:47:36 -0800394
Amin Shaikh761c5662018-03-27 16:55:43 -0400395 private void updateTooltipShow() {
396 if (hasStatusText()) {
397 hideLongPressTooltip(true /* shouldShowStatusText */);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800398 } else {
Amin Shaikh761c5662018-03-27 16:55:43 -0400399 hideStatusText();
Rohan Shahd3cf7562018-02-23 11:12:28 -0800400 }
401 updateHeaderTextContainerAlphaAnimator();
402 }
403
Amin Shaikh761c5662018-03-27 16:55:43 -0400404 private boolean hasStatusText() {
405 return mNextAlarmTextView.getVisibility() == View.VISIBLE
406 || mRingerModeTextView.getVisibility() == View.VISIBLE;
407 }
408
Rohan Shahd3cf7562018-02-23 11:12:28 -0800409 /**
410 * Animates in the long press tooltip (as long as the next alarm text isn't currently occupying
411 * the space).
412 */
413 public void showLongPressTooltip() {
Amin Shaikh761c5662018-03-27 16:55:43 -0400414 // If we have status text to show, don't bother fading in the tooltip.
415 if (hasStatusText()) {
Rohan Shahd3cf7562018-02-23 11:12:28 -0800416 return;
417 }
418
419 if (mShownCount < MAX_TOOLTIP_SHOWN_COUNT) {
420 mLongPressTooltipView.animate().cancel();
421 mLongPressTooltipView.setVisibility(View.VISIBLE);
422 mLongPressTooltipView.animate()
423 .alpha(1f)
424 .setDuration(FADE_ANIMATION_DURATION_MS)
425 .setListener(new AnimatorListenerAdapter() {
426 @Override
427 public void onAnimationEnd(Animator animation) {
428 mHandler.postDelayed(
429 mAutoFadeOutTooltipRunnable, AUTO_FADE_OUT_DELAY_MS);
430 }
431 })
432 .start();
433
434 // Increment and drop the shown count in prefs for the next time we're deciding to
435 // fade in the tooltip. We first sanity check that the tooltip count hasn't changed yet
436 // in prefs (say, from a long press).
437 if (getStoredShownCount() <= mShownCount) {
438 Prefs.putInt(mContext, Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT, ++mShownCount);
439 }
440 }
441 }
442
443 /**
444 * Fades out the long press tooltip if it's partially visible - short circuits any running
Amin Shaikh761c5662018-03-27 16:55:43 -0400445 * animation. Additionally has the ability to fade in the status info text.
Rohan Shahd3cf7562018-02-23 11:12:28 -0800446 *
Amin Shaikh761c5662018-03-27 16:55:43 -0400447 * @param shouldShowStatusText whether we should fade in the status text
Rohan Shahd3cf7562018-02-23 11:12:28 -0800448 */
Amin Shaikh761c5662018-03-27 16:55:43 -0400449 private void hideLongPressTooltip(boolean shouldShowStatusText) {
Rohan Shahd3cf7562018-02-23 11:12:28 -0800450 mLongPressTooltipView.animate().cancel();
451 if (mLongPressTooltipView.getVisibility() == View.VISIBLE
452 && mLongPressTooltipView.getAlpha() != 0f) {
453 mHandler.removeCallbacks(mAutoFadeOutTooltipRunnable);
454 mLongPressTooltipView.animate()
455 .alpha(0f)
456 .setDuration(FADE_ANIMATION_DURATION_MS)
457 .setListener(new AnimatorListenerAdapter() {
458 @Override
459 public void onAnimationEnd(Animator animation) {
Rohan Shaha160ab12018-03-09 15:47:36 -0800460 if (DEBUG) Log.d(TAG, "hideLongPressTooltip: Hid long press tip");
Rohan Shahd3cf7562018-02-23 11:12:28 -0800461 mLongPressTooltipView.setVisibility(View.INVISIBLE);
462
Amin Shaikh761c5662018-03-27 16:55:43 -0400463 if (shouldShowStatusText) {
464 showStatus();
Rohan Shahd3cf7562018-02-23 11:12:28 -0800465 }
466 }
467 })
468 .start();
469 } else {
470 mLongPressTooltipView.setVisibility(View.INVISIBLE);
Amin Shaikh761c5662018-03-27 16:55:43 -0400471 if (shouldShowStatusText) {
472 showStatus();
Rohan Shahd3cf7562018-02-23 11:12:28 -0800473 }
474 }
475 }
476
477 /**
Amin Shaikh761c5662018-03-27 16:55:43 -0400478 * Fades in the updated status text. Note that if there's already a status showing, this will
479 * immediately hide it and fade in the updated status.
Rohan Shahd3cf7562018-02-23 11:12:28 -0800480 */
Amin Shaikh761c5662018-03-27 16:55:43 -0400481 private void showStatus() {
482 mStatusContainer.setAlpha(0f);
483 mStatusContainer.setVisibility(View.VISIBLE);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800484
Rohan Shaha160ab12018-03-09 15:47:36 -0800485 // Animate the alarm back in. Make sure to clear the animator listener for the animation!
Amin Shaikh761c5662018-03-27 16:55:43 -0400486 mStatusContainer.animate()
Rohan Shahd3cf7562018-02-23 11:12:28 -0800487 .alpha(1f)
488 .setDuration(FADE_ANIMATION_DURATION_MS)
Rohan Shaha160ab12018-03-09 15:47:36 -0800489 .setListener(null)
Rohan Shahd3cf7562018-02-23 11:12:28 -0800490 .start();
491 }
492
Amin Shaikh761c5662018-03-27 16:55:43 -0400493 /** Fades out and hides the status text. */
494 private void hideStatusText() {
495 if (mStatusContainer.getVisibility() == View.VISIBLE) {
496 mStatusContainer.animate()
Rohan Shahd3cf7562018-02-23 11:12:28 -0800497 .alpha(0f)
498 .setListener(new AnimatorListenerAdapter() {
499 @Override
500 public void onAnimationEnd(Animator animation) {
Rohan Shaha160ab12018-03-09 15:47:36 -0800501 if (DEBUG) Log.d(TAG, "hideAlarmText: Hid alarm text");
502
Rohan Shahd3cf7562018-02-23 11:12:28 -0800503 // Reset the alpha regardless of how the animation ends for the next
504 // time we show this view/want to animate it.
Amin Shaikh761c5662018-03-27 16:55:43 -0400505 mStatusContainer.setVisibility(View.INVISIBLE);
506 mStatusContainer.setAlpha(1f);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800507 }
508 })
509 .start();
Rohan Shahd3cf7562018-02-23 11:12:28 -0800510 }
511 }
512
Jason Monke5b770e2017-03-03 21:49:29 -0500513 public void updateEverything() {
Jason Monk1fdde2d2017-03-08 09:39:21 -0500514 post(() -> setClickable(false));
Jason Monke5b770e2017-03-03 21:49:29 -0500515 }
516
517 public void setQSPanel(final QSPanel qsPanel) {
518 mQsPanel = qsPanel;
519 setupHost(qsPanel.getHost());
520 }
521
522 public void setupHost(final QSTileHost host) {
523 mHost = host;
524 //host.setHeaderView(mExpandIndicator);
525 mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
526 mHeaderQsPanel.setHost(host, null /* No customization in header */);
Evan Lairdef160f22018-01-29 14:08:45 -0500527
528 // Use SystemUI context to get battery meter colors, and let it use the default tint (white)
Rohan Shahbc204ef2018-03-09 15:11:58 -0800529 mBatteryMeterView.setColorsFromContext(mHost.getContext());
530 mBatteryMeterView.onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
Jason Monke5b770e2017-03-03 21:49:29 -0500531 }
532
533 public void setCallback(Callback qsPanelCallback) {
534 mHeaderQsPanel.setCallback(qsPanelCallback);
535 }
Lucas Dupin1f7374a2018-02-26 18:08:33 -0800536
537 private String formatNextAlarm(AlarmManager.AlarmClockInfo info) {
538 if (info == null) {
539 return "";
540 }
541 String skeleton = android.text.format.DateFormat
542 .is24HourFormat(mContext, ActivityManager.getCurrentUser()) ? "EHm" : "Ehma";
543 String pattern = android.text.format.DateFormat
544 .getBestDateTimePattern(Locale.getDefault(), skeleton);
545 return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString();
546 }
Amin Shaikh0e003312018-03-08 11:39:01 -0500547
548 public static float getColorIntensity(@ColorInt int color) {
549 return color == Color.WHITE ? 0 : 1;
550 }
551
Jason Monke5b770e2017-03-03 21:49:29 -0500552}