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