blob: 70880d3e12a298edec78b42f42a7d60f0a707f33 [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;
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;
Charles Hece2a7c02017-10-11 20:25:20 +010051import com.android.systemui.SysUiServiceProvider;
Jason Monke5b770e2017-03-03 21:49:29 -050052import com.android.systemui.plugins.ActivityStarter;
53import com.android.systemui.qs.QSDetail.Callback;
Charles Hece2a7c02017-10-11 20:25:20 +010054import com.android.systemui.statusbar.CommandQueue;
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;
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 */
Amin Shaikhf09450b2018-04-06 17:32:45 -040072public class QuickStatusBarHeader extends RelativeLayout implements
Rohan Shahd3cf7562018-02-23 11:12:28 -080073 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 Shahcc3d1d82018-03-30 21:24:17 +000097 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 Shahcc3d1d82018-03-30 21:24:17 +0000115 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 Shahcc3d1d82018-03-30 21:24:17 +0000149 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);
Evan Laird20b87bf2018-04-12 09:54:11 -0400151 StatusIconContainer iconContainer = findViewById(R.id.statusIcons);
152 iconContainer.setShouldRestrictIcons(false);
153 mIconManager = new TintedIconManager(iconContainer);
Jason Monke5b770e2017-03-03 21:49:29 -0500154
Rohan Shahd3cf7562018-02-23 11:12:28 -0800155 // Views corresponding to the header info section (e.g. tooltip and next alarm).
156 mHeaderTextContainerView = findViewById(R.id.header_text_container);
157 mLongPressTooltipView = findViewById(R.id.long_press_tooltip);
Amin Shaikh761c5662018-03-27 16:55:43 -0400158 mStatusContainer = findViewById(R.id.status_container);
159 mStatusSeparator = findViewById(R.id.status_separator);
160 mNextAlarmIcon = findViewById(R.id.next_alarm_icon);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800161 mNextAlarmTextView = findViewById(R.id.next_alarm_text);
Amin Shaikh761c5662018-03-27 16:55:43 -0400162 mRingerModeIcon = findViewById(R.id.ringer_mode_icon);
163 mRingerModeTextView = findViewById(R.id.ringer_mode_text);
Jason Monke5b770e2017-03-03 21:49:29 -0500164
165 updateResources();
166
Jason Monk824ffff2017-04-11 15:49:06 -0400167 Rect tintArea = new Rect(0, 0, 0, 0);
Evan Laird95896952018-01-22 19:30:05 -0500168 int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground);
Amin Shaikh0e003312018-03-08 11:39:01 -0500169 float intensity = getColorIntensity(colorForeground);
Evan Laird95896952018-01-22 19:30:05 -0500170 int fillColor = fillColorForIntensity(intensity, getContext());
171
172 // Set light text on the header icons because they will always be on a black background
Evan Laird39254d42018-01-18 16:05:30 -0500173 applyDarkness(R.id.clock, tintArea, 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
Evan Laird95896952018-01-22 19:30:05 -0500174
175 // Set the correct tint for the status icons so they contrast
176 mIconManager.setTint(fillColor);
Jason Monke5b770e2017-03-03 21:49:29 -0500177
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000178 mBatteryMeterView = findViewById(R.id.battery);
179 mBatteryMeterView.setForceShowPercent(true);
180 mClockView = findViewById(R.id.clock);
181 mDateView = findViewById(R.id.date);
Jason Monke5b770e2017-03-03 21:49:29 -0500182 }
183
Amin Shaikh761c5662018-03-27 16:55:43 -0400184 private void updateStatusText() {
185 boolean ringerVisible = false;
186 if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
187 mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_vibrate);
Amin Shaikhe4d25a92018-03-30 15:30:29 -0400188 mRingerModeTextView.setText(R.string.qs_status_phone_vibrate);
Amin Shaikh761c5662018-03-27 16:55:43 -0400189 ringerVisible = true;
190 } else if (mRingerMode == AudioManager.RINGER_MODE_SILENT) {
191 mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_silent);
Amin Shaikhe4d25a92018-03-30 15:30:29 -0400192 mRingerModeTextView.setText(R.string.qs_status_phone_muted);
Amin Shaikh761c5662018-03-27 16:55:43 -0400193 ringerVisible = true;
194 }
195 mRingerModeIcon.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
196 mRingerModeTextView.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
197
198 boolean alarmVisible = false;
199 if (mNextAlarm != null) {
200 alarmVisible = true;
201 mNextAlarmTextView.setText(formatNextAlarm(mNextAlarm));
202 }
203 mNextAlarmIcon.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
204 mNextAlarmTextView.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
205 mStatusSeparator.setVisibility(alarmVisible && ringerVisible ? View.VISIBLE : View.GONE);
206 updateTooltipShow();
207 }
208
209
Jason Monk824ffff2017-04-11 15:49:06 -0400210 private void applyDarkness(int id, Rect tintArea, float intensity, int color) {
211 View v = findViewById(id);
212 if (v instanceof DarkReceiver) {
213 ((DarkReceiver) v).onDarkChanged(tintArea, intensity, color);
214 }
215 }
216
Evan Laird95896952018-01-22 19:30:05 -0500217 private int fillColorForIntensity(float intensity, Context context) {
218 if (intensity == 0) {
Amin Shaikh9cac3382018-04-11 17:10:07 -0400219 return context.getColor(R.color.light_mode_icon_color_single_tone);
Evan Laird95896952018-01-22 19:30:05 -0500220 }
Amin Shaikh9cac3382018-04-11 17:10:07 -0400221 return context.getColor(R.color.dark_mode_icon_color_single_tone);
Evan Laird95896952018-01-22 19:30:05 -0500222 }
223
Jason Monke5b770e2017-03-03 21:49:29 -0500224 @Override
225 protected void onConfigurationChanged(Configuration newConfig) {
226 super.onConfigurationChanged(newConfig);
227 updateResources();
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000228
229 // Update color schemes in landscape to use wallpaperTextColor
230 boolean shouldUseWallpaperTextColor =
231 newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE;
232 mBatteryMeterView.useWallpaperTextColor(shouldUseWallpaperTextColor);
233 mClockView.useWallpaperTextColor(shouldUseWallpaperTextColor);
234 mDateView.useWallpaperTextColor(shouldUseWallpaperTextColor);
Jason Monke5b770e2017-03-03 21:49:29 -0500235 }
236
237 @Override
238 public void onRtlPropertiesChanged(int layoutDirection) {
239 super.onRtlPropertiesChanged(layoutDirection);
240 updateResources();
241 }
242
243 private void updateResources() {
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000244 Resources resources = mContext.getResources();
245
246 // Update height for a few views, especially due to landscape mode restricting space.
Rohan Shahd3cf7562018-02-23 11:12:28 -0800247 mHeaderTextContainerView.getLayoutParams().height =
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000248 resources.getDimensionPixelSize(R.dimen.qs_header_tooltip_height);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800249 mHeaderTextContainerView.setLayoutParams(mHeaderTextContainerView.getLayoutParams());
250
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000251 mSystemIconsView.getLayoutParams().height = resources.getDimensionPixelSize(
252 com.android.internal.R.dimen.quick_qs_offset_height);
253 mSystemIconsView.setLayoutParams(mSystemIconsView.getLayoutParams());
254
Amin Shaikhf09450b2018-04-06 17:32:45 -0400255 getLayoutParams().height = resources.getDimensionPixelSize(mQsDisabled
256 ? com.android.internal.R.dimen.quick_qs_offset_height
257 : com.android.internal.R.dimen.quick_qs_total_height);
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000258 setLayoutParams(getLayoutParams());
259
Rohan Shahd3cf7562018-02-23 11:12:28 -0800260 updateStatusIconAlphaAnimator();
261 updateHeaderTextContainerAlphaAnimator();
Evan Laird95896952018-01-22 19:30:05 -0500262 }
263
Rohan Shahd3cf7562018-02-23 11:12:28 -0800264 private void updateStatusIconAlphaAnimator() {
265 mStatusIconsAlphaAnimator = new TouchAnimator.Builder()
Evan Laird95896952018-01-22 19:30:05 -0500266 .addFloat(mQuickQsStatusIcons, "alpha", 1, 0)
267 .build();
Jason Monke5b770e2017-03-03 21:49:29 -0500268 }
269
Rohan Shahd3cf7562018-02-23 11:12:28 -0800270 private void updateHeaderTextContainerAlphaAnimator() {
271 mHeaderTextContainerAlphaAnimator = new TouchAnimator.Builder()
272 .addFloat(mHeaderTextContainerView, "alpha", 0, 1)
273 .setStartDelay(.5f)
274 .build();
Jason Monke5b770e2017-03-03 21:49:29 -0500275 }
276
277 public void setExpanded(boolean expanded) {
278 if (mExpanded == expanded) return;
279 mExpanded = expanded;
280 mHeaderQsPanel.setExpanded(expanded);
281 updateEverything();
282 }
283
Rohan Shahd3cf7562018-02-23 11:12:28 -0800284 /**
285 * Animates the inner contents based on the given expansion details.
286 *
287 * @param isKeyguardShowing whether or not we're showing the keyguard (a.k.a. lockscreen)
288 * @param expansionFraction how much the QS panel is expanded/pulled out (up to 1f)
289 * @param panelTranslationY how much the panel has physically moved down vertically (required
290 * for keyguard animations only)
291 */
292 public void setExpansion(boolean isKeyguardShowing, float expansionFraction,
293 float panelTranslationY) {
294 final float keyguardExpansionFraction = isKeyguardShowing ? 1f : expansionFraction;
295 if (mStatusIconsAlphaAnimator != null) {
296 mStatusIconsAlphaAnimator.setPosition(keyguardExpansionFraction);
Evan Laird95896952018-01-22 19:30:05 -0500297 }
Rohan Shahd3cf7562018-02-23 11:12:28 -0800298
299 if (isKeyguardShowing) {
300 // If the keyguard is showing, we want to offset the text so that it comes in at the
301 // same time as the panel as it slides down.
302 mHeaderTextContainerView.setTranslationY(panelTranslationY);
303 } else {
304 mHeaderTextContainerView.setTranslationY(0f);
305 }
306
307 if (mHeaderTextContainerAlphaAnimator != null) {
308 mHeaderTextContainerAlphaAnimator.setPosition(keyguardExpansionFraction);
309 }
310
311 // Check the original expansion fraction - we don't want to show the tooltip until the
312 // panel is pulled all the way out.
313 if (expansionFraction == 1f) {
314 // QS is fully expanded, bring in the tooltip.
315 showLongPressTooltip();
316 }
317 }
318
319 /** Returns the latest stored tooltip shown count from SharedPreferences. */
320 private int getStoredShownCount() {
321 return Prefs.getInt(
322 mContext,
323 Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
324 TOOLTIP_NOT_YET_SHOWN_COUNT);
Jason Monke5b770e2017-03-03 21:49:29 -0500325 }
326
Charles Hece2a7c02017-10-11 20:25:20 +0100327 public void disable(int state1, int state2, boolean animate) {
328 final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
329 if (disabled == mQsDisabled) return;
330 mQsDisabled = disabled;
331 mHeaderQsPanel.setDisabledByPolicy(disabled);
Amin Shaikhf09450b2018-04-06 17:32:45 -0400332 mHeaderTextContainerView.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
333 mQuickQsStatusIcons.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
334 updateResources();
Charles Hece2a7c02017-10-11 20:25:20 +0100335 }
336
337 @Override
338 public void onAttachedToWindow() {
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);
Evan Laird95896952018-01-22 19:30:05 -0500359 Dependency.get(StatusBarIconController.class).removeIconGroup(mIconManager);
Jason Monke5b770e2017-03-03 21:49:29 -0500360 super.onDetachedFromWindow();
361 }
362
363 public void setListening(boolean listening) {
364 if (listening == mListening) {
365 return;
366 }
367 mHeaderQsPanel.setListening(listening);
368 mListening = listening;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800369
370 if (listening) {
371 mAlarmController.addCallback(this);
Amin Shaikh761c5662018-03-27 16:55:43 -0400372 mContext.registerReceiver(mRingerReceiver,
373 new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
Rohan Shahd3cf7562018-02-23 11:12:28 -0800374 } else {
375 mAlarmController.removeCallback(this);
Amin Shaikh761c5662018-03-27 16:55:43 -0400376 mContext.unregisterReceiver(mRingerReceiver);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800377 }
Jason Monke5b770e2017-03-03 21:49:29 -0500378 }
379
Evan Laird95896952018-01-22 19:30:05 -0500380 @Override
381 public void onClick(View v) {
382 if(v == mDate){
383 Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(new Intent(
384 AlarmClock.ACTION_SHOW_ALARMS),0);
385 }
386 }
387
Rohan Shahd3cf7562018-02-23 11:12:28 -0800388 @Override
389 public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
Amin Shaikh761c5662018-03-27 16:55:43 -0400390 mNextAlarm = nextAlarm;
391 updateStatusText();
392 }
Rohan Shaha160ab12018-03-09 15:47:36 -0800393
Amin Shaikh761c5662018-03-27 16:55:43 -0400394 private void updateTooltipShow() {
395 if (hasStatusText()) {
396 hideLongPressTooltip(true /* shouldShowStatusText */);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800397 } else {
Amin Shaikh761c5662018-03-27 16:55:43 -0400398 hideStatusText();
Rohan Shahd3cf7562018-02-23 11:12:28 -0800399 }
400 updateHeaderTextContainerAlphaAnimator();
401 }
402
Amin Shaikh761c5662018-03-27 16:55:43 -0400403 private boolean hasStatusText() {
404 return mNextAlarmTextView.getVisibility() == View.VISIBLE
405 || mRingerModeTextView.getVisibility() == View.VISIBLE;
406 }
407
Rohan Shahd3cf7562018-02-23 11:12:28 -0800408 /**
409 * Animates in the long press tooltip (as long as the next alarm text isn't currently occupying
410 * the space).
411 */
412 public void showLongPressTooltip() {
Amin Shaikh761c5662018-03-27 16:55:43 -0400413 // If we have status text to show, don't bother fading in the tooltip.
414 if (hasStatusText()) {
Rohan Shahd3cf7562018-02-23 11:12:28 -0800415 return;
416 }
417
418 if (mShownCount < MAX_TOOLTIP_SHOWN_COUNT) {
419 mLongPressTooltipView.animate().cancel();
420 mLongPressTooltipView.setVisibility(View.VISIBLE);
421 mLongPressTooltipView.animate()
422 .alpha(1f)
423 .setDuration(FADE_ANIMATION_DURATION_MS)
424 .setListener(new AnimatorListenerAdapter() {
425 @Override
426 public void onAnimationEnd(Animator animation) {
427 mHandler.postDelayed(
428 mAutoFadeOutTooltipRunnable, AUTO_FADE_OUT_DELAY_MS);
429 }
430 })
431 .start();
432
433 // Increment and drop the shown count in prefs for the next time we're deciding to
434 // fade in the tooltip. We first sanity check that the tooltip count hasn't changed yet
435 // in prefs (say, from a long press).
436 if (getStoredShownCount() <= mShownCount) {
437 Prefs.putInt(mContext, Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT, ++mShownCount);
438 }
439 }
440 }
441
442 /**
443 * Fades out the long press tooltip if it's partially visible - short circuits any running
Amin Shaikh761c5662018-03-27 16:55:43 -0400444 * animation. Additionally has the ability to fade in the status info text.
Rohan Shahd3cf7562018-02-23 11:12:28 -0800445 *
Amin Shaikh761c5662018-03-27 16:55:43 -0400446 * @param shouldShowStatusText whether we should fade in the status text
Rohan Shahd3cf7562018-02-23 11:12:28 -0800447 */
Amin Shaikh761c5662018-03-27 16:55:43 -0400448 private void hideLongPressTooltip(boolean shouldShowStatusText) {
Rohan Shahd3cf7562018-02-23 11:12:28 -0800449 mLongPressTooltipView.animate().cancel();
450 if (mLongPressTooltipView.getVisibility() == View.VISIBLE
451 && mLongPressTooltipView.getAlpha() != 0f) {
452 mHandler.removeCallbacks(mAutoFadeOutTooltipRunnable);
453 mLongPressTooltipView.animate()
454 .alpha(0f)
455 .setDuration(FADE_ANIMATION_DURATION_MS)
456 .setListener(new AnimatorListenerAdapter() {
457 @Override
458 public void onAnimationEnd(Animator animation) {
Rohan Shaha160ab12018-03-09 15:47:36 -0800459 if (DEBUG) Log.d(TAG, "hideLongPressTooltip: Hid long press tip");
Rohan Shahd3cf7562018-02-23 11:12:28 -0800460 mLongPressTooltipView.setVisibility(View.INVISIBLE);
461
Amin Shaikh761c5662018-03-27 16:55:43 -0400462 if (shouldShowStatusText) {
463 showStatus();
Rohan Shahd3cf7562018-02-23 11:12:28 -0800464 }
465 }
466 })
467 .start();
468 } else {
469 mLongPressTooltipView.setVisibility(View.INVISIBLE);
Amin Shaikh761c5662018-03-27 16:55:43 -0400470 if (shouldShowStatusText) {
471 showStatus();
Rohan Shahd3cf7562018-02-23 11:12:28 -0800472 }
473 }
474 }
475
476 /**
Amin Shaikh761c5662018-03-27 16:55:43 -0400477 * Fades in the updated status text. Note that if there's already a status showing, this will
478 * immediately hide it and fade in the updated status.
Rohan Shahd3cf7562018-02-23 11:12:28 -0800479 */
Amin Shaikh761c5662018-03-27 16:55:43 -0400480 private void showStatus() {
481 mStatusContainer.setAlpha(0f);
482 mStatusContainer.setVisibility(View.VISIBLE);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800483
Rohan Shaha160ab12018-03-09 15:47:36 -0800484 // Animate the alarm back in. Make sure to clear the animator listener for the animation!
Amin Shaikh761c5662018-03-27 16:55:43 -0400485 mStatusContainer.animate()
Rohan Shahd3cf7562018-02-23 11:12:28 -0800486 .alpha(1f)
487 .setDuration(FADE_ANIMATION_DURATION_MS)
Rohan Shaha160ab12018-03-09 15:47:36 -0800488 .setListener(null)
Rohan Shahd3cf7562018-02-23 11:12:28 -0800489 .start();
490 }
491
Amin Shaikh761c5662018-03-27 16:55:43 -0400492 /** Fades out and hides the status text. */
493 private void hideStatusText() {
494 if (mStatusContainer.getVisibility() == View.VISIBLE) {
495 mStatusContainer.animate()
Rohan Shahd3cf7562018-02-23 11:12:28 -0800496 .alpha(0f)
497 .setListener(new AnimatorListenerAdapter() {
498 @Override
499 public void onAnimationEnd(Animator animation) {
Rohan Shaha160ab12018-03-09 15:47:36 -0800500 if (DEBUG) Log.d(TAG, "hideAlarmText: Hid alarm text");
501
Rohan Shahd3cf7562018-02-23 11:12:28 -0800502 // Reset the alpha regardless of how the animation ends for the next
503 // time we show this view/want to animate it.
Amin Shaikh761c5662018-03-27 16:55:43 -0400504 mStatusContainer.setVisibility(View.INVISIBLE);
505 mStatusContainer.setAlpha(1f);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800506 }
507 })
508 .start();
Rohan Shahd3cf7562018-02-23 11:12:28 -0800509 }
510 }
511
Jason Monke5b770e2017-03-03 21:49:29 -0500512 public void updateEverything() {
Jason Monk1fdde2d2017-03-08 09:39:21 -0500513 post(() -> setClickable(false));
Jason Monke5b770e2017-03-03 21:49:29 -0500514 }
515
516 public void setQSPanel(final QSPanel qsPanel) {
517 mQsPanel = qsPanel;
518 setupHost(qsPanel.getHost());
519 }
520
521 public void setupHost(final QSTileHost host) {
522 mHost = host;
523 //host.setHeaderView(mExpandIndicator);
524 mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
525 mHeaderQsPanel.setHost(host, null /* No customization in header */);
Evan Lairdef160f22018-01-29 14:08:45 -0500526
527 // Use SystemUI context to get battery meter colors, and let it use the default tint (white)
Rohan Shahcc3d1d82018-03-30 21:24:17 +0000528 mBatteryMeterView.setColorsFromContext(mHost.getContext());
529 mBatteryMeterView.onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
Jason Monke5b770e2017-03-03 21:49:29 -0500530 }
531
532 public void setCallback(Callback qsPanelCallback) {
533 mHeaderQsPanel.setCallback(qsPanelCallback);
534 }
Lucas Dupin1f7374a2018-02-26 18:08:33 -0800535
536 private String formatNextAlarm(AlarmManager.AlarmClockInfo info) {
537 if (info == null) {
538 return "";
539 }
540 String skeleton = android.text.format.DateFormat
541 .is24HourFormat(mContext, ActivityManager.getCurrentUser()) ? "EHm" : "Ehma";
542 String pattern = android.text.format.DateFormat
543 .getBestDateTimePattern(Locale.getDefault(), skeleton);
544 return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString();
545 }
Amin Shaikh0e003312018-03-08 11:39:01 -0500546
547 public static float getColorIntensity(@ColorInt int color) {
548 return color == Color.WHITE ? 0 : 1;
549 }
550
Jason Monke5b770e2017-03-03 21:49:29 -0500551}