diff --git a/packages/SystemUI/res/layout/quick_settings_header.xml b/packages/SystemUI/res/layout/quick_settings_header.xml
deleted file mode 100644
index 43197c4001399..0000000000000
--- a/packages/SystemUI/res/layout/quick_settings_header.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
diff --git a/packages/SystemUI/res/layout/quick_settings_header_info.xml b/packages/SystemUI/res/layout/quick_settings_header_info.xml
new file mode 100644
index 0000000000000..89d6e99aa4b77
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_header_info.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index cc79d0d9b7dd2..959247ee76e7f 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -32,8 +32,13 @@
android:elevation="4dp" >
+
+
+
+
+
16dp
4dp
0dp
- 32dp
+ 30dp
56dp
0dp
56dp
@@ -345,7 +345,9 @@
32dp
0dp
20dp
- 30dp
+ 18dp
+ 18dp
+ 6dp
16dp
24dp
16dp
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 175cddc557618..2a4bb607673e7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -66,10 +66,6 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
private TouchAnimator mNonfirstPageDelayedAnimator;
private TouchAnimator mBrightnessAnimator;
- /**
- * Whether we're in the middle of animating between the collapsed and expanded states.
- */
- private boolean mIsAnimating;
private boolean mOnKeyguard;
private boolean mAllowFancy;
@@ -94,9 +90,6 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
Log.w(TAG, "QS Not using page layout");
}
panel.setPageListener(this);
-
- // At time of creation, the QS panel is never animating.
- mIsAnimating = false;
}
public void onRtlChanged() {
@@ -251,11 +244,6 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
} else {
mBrightnessAnimator = null;
}
- View headerView = mQsPanel.getHeaderView();
- if (headerView!= null) {
- firstPageBuilder.addFloat(headerView, "translationY", heightDiff, 0);
- mAllViews.add(headerView);
- }
mFirstPageAnimator = firstPageBuilder
.setListener(this)
.build();
@@ -342,21 +330,11 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
@Override
public void onAnimationAtStart() {
- if (mIsAnimating) {
- mQsPanel.onCollapse();
- }
- mIsAnimating = false;
-
mQuickQsPanel.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationAtEnd() {
- if (mIsAnimating) {
- mQsPanel.onExpanded();
- }
- mIsAnimating = false;
-
mQuickQsPanel.setVisibility(View.INVISIBLE);
final int N = mQuickQsViews.size();
for (int i = 0; i < N; i++) {
@@ -366,11 +344,6 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
@Override
public void onAnimationStarted() {
- if (!mIsAnimating) {
- mQsPanel.onAnimating();
- }
- mIsAnimating = true;
-
mQuickQsPanel.setVisibility(mOnKeyguard ? View.INVISIBLE : View.VISIBLE);
if (mOnFirstPage) {
final int N = mQuickQsViews.size();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index d437f49d0e961..5758762b06a03 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -272,21 +272,27 @@ public class QSFragment extends Fragment implements QS {
mContainer.setExpansion(expansion);
final float translationScaleY = expansion - 1;
if (!mHeaderAnimating) {
- int height = mHeader.getHeight();
- getView().setTranslationY(mKeyguardShowing ? (translationScaleY * height)
- : headerTranslation);
+ getView().setTranslationY(
+ mKeyguardShowing
+ ? translationScaleY * mHeader.getHeight()
+ : headerTranslation);
}
if (expansion == mLastQSExpansion) {
return;
}
mLastQSExpansion = expansion;
- mHeader.setExpansion(mKeyguardShowing ? 1 : expansion);
- mFooter.setExpansion(mKeyguardShowing ? 1 : expansion);
+
+ boolean fullyExpanded = expansion == 1;
int heightDiff = mQSPanel.getBottom() - mHeader.getBottom() + mHeader.getPaddingBottom()
+ mFooter.getHeight();
+ float panelTranslationY = translationScaleY * heightDiff;
+
+ // Let the views animate their contents correctly by giving them the necessary context.
+ mHeader.setExpansion(mKeyguardShowing, expansion, panelTranslationY);
+ mFooter.setExpansion(mKeyguardShowing ? 1 : expansion);
mQSPanel.setTranslationY(translationScaleY * heightDiff);
- boolean fullyExpanded = expansion == 1;
mQSDetail.setFullyExpanded(fullyExpanded);
+
if (fullyExpanded) {
// Always draw within the bounds of the view when fully expanded.
mQSPanel.setClipBounds(null);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index a92e3465ff6b2..143ad21c998c0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -29,7 +29,6 @@ import android.os.Message;
import android.service.quicksettings.Tile;
import android.util.AttributeSet;
import android.view.LayoutInflater;
-import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
@@ -54,11 +53,11 @@ import com.android.systemui.tuner.TunerService.Tunable;
import java.util.ArrayList;
import java.util.Collection;
-/** View that represents the quick settings tile panel. **/
+/** View that represents the quick settings tile panel (when expanded/pulled down). **/
public class QSPanel extends LinearLayout implements Tunable, Callback, BrightnessMirrorListener {
public static final String QS_SHOW_BRIGHTNESS = "qs_show_brightness";
- public static final String QS_SHOW_LONG_PRESS_TOOLTIP = "qs_show_long_press";
+ public static final String QS_SHOW_HEADER = "qs_show_header";
protected final Context mContext;
protected final ArrayList mRecords = new ArrayList();
@@ -74,7 +73,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
private BrightnessController mBrightnessController;
protected QSTileHost mHost;
- protected QSTooltipView mTooltipView;
protected QSSecurityFooter mFooter;
private boolean mGridContentVisible = true;
@@ -96,11 +94,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
setOrientation(VERTICAL);
- mTooltipView = (QSTooltipView) LayoutInflater.from(mContext)
- .inflate(R.layout.quick_settings_header, this, false);
-
- addView(mTooltipView);
-
mBrightnessView = LayoutInflater.from(mContext).inflate(
R.layout.quick_settings_brightness_dialog, this, false);
addView(mBrightnessView);
@@ -152,7 +145,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
super.onAttachedToWindow();
final TunerService tunerService = Dependency.get(TunerService.class);
tunerService.addTunable(this, QS_SHOW_BRIGHTNESS);
- tunerService.addTunable(this, QS_SHOW_LONG_PRESS_TOOLTIP);
if (mHost != null) {
setTiles(mHost.getTiles());
@@ -186,8 +178,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
public void onTuningChanged(String key, String newValue) {
if (QS_SHOW_BRIGHTNESS.equals(key)) {
updateViewVisibilityForTuningValue(mBrightnessView, newValue);
- } else if (QS_SHOW_LONG_PRESS_TOOLTIP.equals(key)) {
- updateViewVisibilityForTuningValue(mTooltipView, newValue);
}
}
@@ -229,10 +219,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
return mBrightnessView;
}
- View getHeaderView() {
- return mTooltipView;
- }
-
public void setCallback(QSDetail.Callback callback) {
mCallback = callback;
}
@@ -254,10 +240,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
public void updateResources() {
final Resources res = mContext.getResources();
- setPadding(0, 0, 0, res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom));
- mTooltipView.getLayoutParams().height =
- res.getDimensionPixelSize(R.dimen.qs_header_tooltip_height);
- mTooltipView.setLayoutParams(mTooltipView.getLayoutParams());
+ setPadding(0, res.getDimensionPixelSize(R.dimen.qs_panel_padding_top), 0, res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom));
for (TileRecord r : mRecords) {
r.tile.clearState();
}
@@ -291,21 +274,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
if (mCustomizePanel != null && mCustomizePanel.isShown()) {
mCustomizePanel.hide(mCustomizePanel.getWidth() / 2, mCustomizePanel.getHeight() / 2);
}
-
- // Instantly hide the header here since we don't want it to still be animating.
- mTooltipView.setVisibility(View.INVISIBLE);
- }
-
- /**
- * Called when the panel is fully animated out/expanded. This is different from the state
- * tracked by {@link #mExpanded}, which only checks if the panel is even partially pulled out.
- */
- public void onExpanded() {
- mTooltipView.fadeIn();
- }
-
- public void onAnimating() {
- mTooltipView.fadeOut();
}
public void setExpanded(boolean expanded) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTooltipView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTooltipView.java
deleted file mode 100644
index d1f9741ba6c2d..0000000000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTooltipView.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.qs;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.content.Context;
-import android.os.Handler;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import com.android.systemui.Prefs;
-
-import java.util.concurrent.TimeUnit;
-
-
-/**
- * Tooltip/header view for the Quick Settings panel.
- */
-public class QSTooltipView extends LinearLayout {
-
- private static final int FADE_ANIMATION_DURATION_MS = 300;
- private static final long AUTO_FADE_OUT_DELAY_MS = TimeUnit.SECONDS.toMillis(6);
- private static final int TOOLTIP_NOT_YET_SHOWN_COUNT = 0;
- public static final int MAX_TOOLTIP_SHOWN_COUNT = 3;
-
- private final Handler mHandler = new Handler();
- private final Runnable mAutoFadeOutRunnable = () -> fadeOut();
-
- private int mShownCount;
-
- public QSTooltipView(Context context) {
- this(context, null);
- }
-
- public QSTooltipView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mShownCount = getStoredShownCount();
- }
-
- /** Returns the latest stored tooltip shown count from SharedPreferences. */
- private int getStoredShownCount() {
- return Prefs.getInt(
- mContext,
- Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
- TOOLTIP_NOT_YET_SHOWN_COUNT);
- }
-
- /**
- * Fades in the header view if we can show the tooltip - short circuits any running animation.
- */
- public void fadeIn() {
- if (mShownCount < MAX_TOOLTIP_SHOWN_COUNT) {
- animate().cancel();
- setVisibility(View.VISIBLE);
- animate()
- .alpha(1f)
- .setDuration(FADE_ANIMATION_DURATION_MS)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mHandler.postDelayed(mAutoFadeOutRunnable, AUTO_FADE_OUT_DELAY_MS);
- }
- })
- .start();
-
- // Increment and drop the shown count in prefs for the next time we're deciding to
- // fade in the tooltip. We first sanity check that the tooltip count hasn't changed yet
- // in prefs (say, from a long press).
- if (getStoredShownCount() <= mShownCount) {
- Prefs.putInt(mContext, Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT, ++mShownCount);
- }
- }
- }
-
- /**
- * Fades out the header view if it's partially visible - short circuits any running animation.
- */
- public void fadeOut() {
- animate().cancel();
- if (getVisibility() == View.VISIBLE && getAlpha() != 0f) {
- mHandler.removeCallbacks(mAutoFadeOutRunnable);
- animate()
- .alpha(0f)
- .setDuration(FADE_ANIMATION_DURATION_MS)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- perhapsMakeViewInvisible();
- }
- })
- .start();
- } else {
- perhapsMakeViewInvisible();
- }
- }
-
- /**
- * Only update visibility if the view is currently being shown. Otherwise, it's already been
- * hidden by some other manner.
- */
- private void perhapsMakeViewInvisible() {
- if (getVisibility() == View.VISIBLE) {
- setVisibility(View.INVISIBLE);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index f0684e19cc765..2270b608b07b6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -20,7 +20,6 @@ import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
-import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Space;
@@ -123,7 +122,7 @@ public class QuickQSPanel extends QSPanel {
@Override
public void onTuningChanged(String key, String newValue) {
- if (QS_SHOW_BRIGHTNESS.equals(key) || QS_SHOW_LONG_PRESS_TOOLTIP.equals(key)) {
+ if (QS_SHOW_BRIGHTNESS.equals(key)) {
// No Brightness or Tooltip for you!
super.onTuningChanged(key, "0");
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 4d7333b99eeec..78481d3b07e08 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -15,24 +15,30 @@
package com.android.systemui.qs;
import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
-import static android.app.StatusBarManager.DISABLE_NONE;
+import static com.android.systemui.keyguard.KeyguardSliceProvider.formatNextAlarm;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.AlarmManager;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
+import android.os.Handler;
import android.provider.AlarmClock;
import android.support.annotation.VisibleForTesting;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.RelativeLayout;
-import android.widget.TextClock;
+import android.widget.TextView;
import com.android.settingslib.Utils;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.Dependency;
+import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.R.id;
import com.android.systemui.SysUiServiceProvider;
@@ -43,11 +49,23 @@ import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.statusbar.policy.NextAlarmController;
-public class QuickStatusBarHeader extends RelativeLayout
- implements CommandQueue.Callbacks, View.OnClickListener {
+/**
+ * View that contains the top-most bits of the screen (primarily the status bar with date, time, and
+ * battery) and also contains the {@link QuickQSPanel} along with some of the panel's inner
+ * contents.
+ */
+public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue.Callbacks,
+ View.OnClickListener, NextAlarmController.NextAlarmChangeCallback {
- private ActivityStarter mActivityStarter;
+ /** Delay for auto fading out the long press tooltip after it's fully visible (in ms). */
+ private static final long AUTO_FADE_OUT_DELAY_MS = DateUtils.SECOND_IN_MILLIS * 6;
+ private static final int FADE_ANIMATION_DURATION_MS = 300;
+ private static final int TOOLTIP_NOT_YET_SHOWN_COUNT = 0;
+ public static final int MAX_TOOLTIP_SHOWN_COUNT = 3;
+
+ private final Handler mHandler = new Handler();
private QSPanel mQsPanel;
@@ -58,20 +76,39 @@ public class QuickStatusBarHeader extends RelativeLayout
protected QuickQSPanel mHeaderQsPanel;
protected QSTileHost mHost;
private TintedIconManager mIconManager;
- private TouchAnimator mAlphaAnimator;
+ private TouchAnimator mStatusIconsAlphaAnimator;
+ private TouchAnimator mHeaderTextContainerAlphaAnimator;
private View mQuickQsStatusIcons;
-
private View mDate;
+ private View mHeaderTextContainerView;
+ /** View corresponding to the next alarm info (including the icon). */
+ private View mNextAlarmView;
+ /** Tooltip for educating users that they can long press on icons to see more details. */
+ private View mLongPressTooltipView;
+ /** {@link TextView} containing the actual text indicating when the next alarm will go off. */
+ private TextView mNextAlarmTextView;
+
+ private NextAlarmController mAlarmController;
+ private String mNextAlarmText;
+ /** Counts how many times the long press tooltip has been shown to the user. */
+ private int mShownCount;
+
+ /**
+ * Runnable for automatically fading out the long press tooltip (as if it were animating away).
+ */
+ private final Runnable mAutoFadeOutTooltipRunnable = () -> hideLongPressTooltip(false);
public QuickStatusBarHeader(Context context, AttributeSet attrs) {
super(context, attrs);
+
+ mAlarmController = Dependency.get(NextAlarmController.class);
+ mShownCount = getStoredShownCount();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- Resources res = getResources();
mHeaderQsPanel = findViewById(R.id.quick_qs_panel);
mDate = findViewById(R.id.date);
@@ -79,8 +116,11 @@ public class QuickStatusBarHeader extends RelativeLayout
mQuickQsStatusIcons = findViewById(R.id.quick_qs_status_icons);
mIconManager = new TintedIconManager(findViewById(R.id.statusIcons));
- // RenderThread is doing more harm than good when touching the header (to expand quick
- // settings), so disable it for this view
+ // Views corresponding to the header info section (e.g. tooltip and next alarm).
+ mHeaderTextContainerView = findViewById(R.id.header_text_container);
+ mLongPressTooltipView = findViewById(R.id.long_press_tooltip);
+ mNextAlarmView = findViewById(R.id.next_alarm);
+ mNextAlarmTextView = findViewById(R.id.next_alarm_text);
updateResources();
@@ -98,8 +138,6 @@ public class QuickStatusBarHeader extends RelativeLayout
BatteryMeterView battery = findViewById(R.id.battery);
battery.setForceShowPercent(true);
-
- mActivityStarter = Dependency.get(ActivityStarter.class);
}
private void applyDarkness(int id, Rect tintArea, float intensity, int color) {
@@ -129,21 +167,26 @@ public class QuickStatusBarHeader extends RelativeLayout
}
private void updateResources() {
- updateAlphaAnimator();
+ // Update height, especially due to landscape mode restricting space.
+ mHeaderTextContainerView.getLayoutParams().height =
+ mContext.getResources().getDimensionPixelSize(R.dimen.qs_header_tooltip_height);
+ mHeaderTextContainerView.setLayoutParams(mHeaderTextContainerView.getLayoutParams());
+
+ updateStatusIconAlphaAnimator();
+ updateHeaderTextContainerAlphaAnimator();
}
- private void updateAlphaAnimator() {
- mAlphaAnimator = new TouchAnimator.Builder()
+ private void updateStatusIconAlphaAnimator() {
+ mStatusIconsAlphaAnimator = new TouchAnimator.Builder()
.addFloat(mQuickQsStatusIcons, "alpha", 1, 0)
.build();
}
- public int getCollapsedHeight() {
- return getHeight();
- }
-
- public int getExpandedHeight() {
- return getHeight();
+ private void updateHeaderTextContainerAlphaAnimator() {
+ mHeaderTextContainerAlphaAnimator = new TouchAnimator.Builder()
+ .addFloat(mHeaderTextContainerView, "alpha", 0, 1)
+ .setStartDelay(.5f)
+ .build();
}
public void setExpanded(boolean expanded) {
@@ -153,10 +196,47 @@ public class QuickStatusBarHeader extends RelativeLayout
updateEverything();
}
- public void setExpansion(float headerExpansionFraction) {
- if (mAlphaAnimator != null ) {
- mAlphaAnimator.setPosition(headerExpansionFraction);
+ /**
+ * Animates the inner contents based on the given expansion details.
+ *
+ * @param isKeyguardShowing whether or not we're showing the keyguard (a.k.a. lockscreen)
+ * @param expansionFraction how much the QS panel is expanded/pulled out (up to 1f)
+ * @param panelTranslationY how much the panel has physically moved down vertically (required
+ * for keyguard animations only)
+ */
+ public void setExpansion(boolean isKeyguardShowing, float expansionFraction,
+ float panelTranslationY) {
+ final float keyguardExpansionFraction = isKeyguardShowing ? 1f : expansionFraction;
+ if (mStatusIconsAlphaAnimator != null) {
+ mStatusIconsAlphaAnimator.setPosition(keyguardExpansionFraction);
}
+
+ if (isKeyguardShowing) {
+ // If the keyguard is showing, we want to offset the text so that it comes in at the
+ // same time as the panel as it slides down.
+ mHeaderTextContainerView.setTranslationY(panelTranslationY);
+ } else {
+ mHeaderTextContainerView.setTranslationY(0f);
+ }
+
+ if (mHeaderTextContainerAlphaAnimator != null) {
+ mHeaderTextContainerAlphaAnimator.setPosition(keyguardExpansionFraction);
+ }
+
+ // Check the original expansion fraction - we don't want to show the tooltip until the
+ // panel is pulled all the way out.
+ if (expansionFraction == 1f) {
+ // QS is fully expanded, bring in the tooltip.
+ showLongPressTooltip();
+ }
+ }
+
+ /** Returns the latest stored tooltip shown count from SharedPreferences. */
+ private int getStoredShownCount() {
+ return Prefs.getInt(
+ mContext,
+ Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
+ TOOLTIP_NOT_YET_SHOWN_COUNT);
}
@Override
@@ -191,6 +271,12 @@ public class QuickStatusBarHeader extends RelativeLayout
}
mHeaderQsPanel.setListening(listening);
mListening = listening;
+
+ if (listening) {
+ mAlarmController.addCallback(this);
+ } else {
+ mAlarmController.removeCallback(this);
+ }
}
@Override
@@ -201,6 +287,125 @@ public class QuickStatusBarHeader extends RelativeLayout
}
}
+ @Override
+ public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
+ mNextAlarmText = nextAlarm != null ? formatNextAlarm(mContext, nextAlarm) : null;
+ if (mNextAlarmText != null) {
+ hideLongPressTooltip(true /* shouldFadeInAlarmText */);
+ } else {
+ hideAlarmText();
+ }
+ updateHeaderTextContainerAlphaAnimator();
+ }
+
+ /**
+ * Animates in the long press tooltip (as long as the next alarm text isn't currently occupying
+ * the space).
+ */
+ public void showLongPressTooltip() {
+ // If we have alarm text to show, don't bother fading in the tooltip.
+ if (!TextUtils.isEmpty(mNextAlarmText)) {
+ return;
+ }
+
+ if (mShownCount < MAX_TOOLTIP_SHOWN_COUNT) {
+ mLongPressTooltipView.animate().cancel();
+ mLongPressTooltipView.setVisibility(View.VISIBLE);
+ mLongPressTooltipView.animate()
+ .alpha(1f)
+ .setDuration(FADE_ANIMATION_DURATION_MS)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mHandler.postDelayed(
+ mAutoFadeOutTooltipRunnable, AUTO_FADE_OUT_DELAY_MS);
+ }
+ })
+ .start();
+
+ // Increment and drop the shown count in prefs for the next time we're deciding to
+ // fade in the tooltip. We first sanity check that the tooltip count hasn't changed yet
+ // in prefs (say, from a long press).
+ if (getStoredShownCount() <= mShownCount) {
+ Prefs.putInt(mContext, Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT, ++mShownCount);
+ }
+ }
+ }
+
+ /**
+ * Fades out the long press tooltip if it's partially visible - short circuits any running
+ * animation. Additionally has the ability to fade in the alarm info text.
+ *
+ * @param shouldShowAlarmText whether we should fade in the next alarm text
+ */
+ private void hideLongPressTooltip(boolean shouldShowAlarmText) {
+ mLongPressTooltipView.animate().cancel();
+ if (mLongPressTooltipView.getVisibility() == View.VISIBLE
+ && mLongPressTooltipView.getAlpha() != 0f) {
+ mHandler.removeCallbacks(mAutoFadeOutTooltipRunnable);
+ mLongPressTooltipView.animate()
+ .alpha(0f)
+ .setDuration(FADE_ANIMATION_DURATION_MS)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mLongPressTooltipView.setVisibility(View.INVISIBLE);
+
+ if (shouldShowAlarmText) {
+ showAlarmText();
+ }
+ }
+ })
+ .start();
+ } else {
+ mLongPressTooltipView.setVisibility(View.INVISIBLE);
+
+ if (shouldShowAlarmText) {
+ showAlarmText();
+ }
+ }
+ }
+
+ /**
+ * Fades in the updated alarm text. Note that if there's already an alarm showing, this will
+ * immediately hide it and fade in the updated time.
+ */
+ private void showAlarmText() {
+ mNextAlarmView.setAlpha(0f);
+ mNextAlarmView.setVisibility(View.VISIBLE);
+ mNextAlarmTextView.setText(mNextAlarmText);
+
+ mNextAlarmView.animate()
+ .alpha(1f)
+ .setDuration(FADE_ANIMATION_DURATION_MS)
+ .start();
+ }
+
+ /**
+ * Fades out and hides the next alarm text. This also resets the text contents to null in
+ * preparation for the next alarm update.
+ */
+ private void hideAlarmText() {
+ if (mNextAlarmView.getVisibility() == View.VISIBLE) {
+ mNextAlarmView.animate()
+ .alpha(0f)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Reset the alpha regardless of how the animation ends for the next
+ // time we show this view/want to animate it.
+ mNextAlarmView.setVisibility(View.INVISIBLE);
+ mNextAlarmView.setAlpha(1f);
+ mNextAlarmTextView.setText(null);
+ }
+ })
+ .start();
+ } else {
+ // Next alarm view is already hidden, only need to clear the text.
+ mNextAlarmTextView.setText(null);
+ }
+ }
+
public void updateEverything() {
post(() -> setClickable(false));
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index bf9746eafaf0f..77c3bfab8de94 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -23,7 +23,6 @@ import com.android.systemui.plugins.qs.*;
import com.android.systemui.plugins.qs.QSTileView;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.tiles.AirplaneModeTile;
-import com.android.systemui.qs.tiles.AlarmTile;
import com.android.systemui.qs.tiles.BatterySaverTile;
import com.android.systemui.qs.tiles.BluetoothTile;
import com.android.systemui.qs.tiles.CastTile;
@@ -70,7 +69,6 @@ public class QSFactoryImpl implements QSFactory {
else if (tileSpec.equals("saver")) return new DataSaverTile(mHost);
else if (tileSpec.equals("night")) return new NightDisplayTile(mHost);
else if (tileSpec.equals("nfc")) return new NfcTile(mHost);
- else if (tileSpec.equals("alarm")) return new AlarmTile(mHost);
// Intent tiles.
else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(mHost, tileSpec);
else if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(mHost, tileSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 016cbd6f6675b..04dbb88adde0d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -50,7 +50,7 @@ import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.qs.PagedTileLayout.TilePage;
import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.QSTooltipView;
+import com.android.systemui.qs.QuickStatusBarHeader;
import java.util.ArrayList;
@@ -197,7 +197,7 @@ public abstract class QSTileImpl implements QSTile {
Prefs.putInt(
mContext,
Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
- QSTooltipView.MAX_TOOLTIP_SHOWN_COUNT);
+ QuickStatusBarHeader.MAX_TOOLTIP_SHOWN_COUNT);
}
public LogMaker populate(LogMaker logMaker) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.java
deleted file mode 100644
index ff3fe731ad4f6..0000000000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui.qs.tiles;
-
-import static android.service.quicksettings.Tile.STATE_ACTIVE;
-import static android.service.quicksettings.Tile.STATE_UNAVAILABLE;
-
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.QS_ALARM;
-import static com.android.systemui.keyguard.KeyguardSliceProvider.formatNextAlarm;
-
-import android.app.AlarmManager.AlarmClockInfo;
-import android.app.PendingIntent;
-import android.content.Intent;
-import android.provider.AlarmClock;
-
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.qs.QSTileHost;
-import com.android.systemui.qs.tileimpl.QSTileImpl;
-import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
-
-public class AlarmTile extends QSTileImpl implements NextAlarmChangeCallback {
- private final NextAlarmController mController;
- private String mNextAlarm;
- private PendingIntent mIntent;
-
- public AlarmTile(QSTileHost host) {
- super(host);
- mController = Dependency.get(NextAlarmController.class);
- }
-
- @Override
- public State newTileState() {
- return new BooleanState();
- }
-
- @Override
- protected void handleClick() {
- if (mIntent != null) {
- Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(mIntent);
- }
- }
-
- @Override
- protected void handleUpdateState(State state, Object arg) {
- state.state = mNextAlarm != null ? STATE_ACTIVE : STATE_UNAVAILABLE;
- state.label = getTileLabel();
- state.secondaryLabel = mNextAlarm;
- state.icon = ResourceIcon.get(R.drawable.stat_sys_alarm);
- ((BooleanState) state).value = mNextAlarm != null;
- }
-
- @Override
- public void onNextAlarmChanged(AlarmClockInfo nextAlarm) {
- if (nextAlarm != null) {
- mNextAlarm = formatNextAlarm(mContext, nextAlarm);
- mIntent = nextAlarm.getShowIntent();
- } else {
- mNextAlarm = null;
- mIntent = null;
- }
- refreshState();
- }
-
- @Override
- public int getMetricsCategory() {
- return QS_ALARM;
- }
-
- @Override
- public Intent getLongClickIntent() {
- return new Intent(AlarmClock.ACTION_SET_ALARM);
- }
-
- @Override
- protected void handleSetListening(boolean listening) {
- if (listening) {
- mController.addCallback(this);
- } else {
- mController.removeCallback(this);
- }
- }
-
- @Override
- public CharSequence getTileLabel() {
- return mContext.getString(R.string.status_bar_alarm);
- }
-}
\ No newline at end of file