blob: b07b1a9561ff261961e258dc9d5e0aa56888f614 [file] [log] [blame]
/*
* Copyright (C) 2017 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 static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
import android.annotation.ColorInt;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.content.Context;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
import android.media.AudioManager;
import android.os.Handler;
import android.provider.AlarmClock;
import android.provider.Settings;
import android.service.notification.ZenModeConfig;
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.MathUtils;
import android.util.Pair;
import android.view.ContextThemeWrapper;
import android.view.DisplayCutout;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
import com.android.settingslib.Utils;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.DualToneHandler;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.qs.QSDetail.Callback;
import com.android.systemui.qs.carrier.QSCarrierGroup;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
import com.android.systemui.statusbar.phone.StatusBarWindowView;
import com.android.systemui.statusbar.phone.StatusIconContainer;
import com.android.systemui.statusbar.policy.Clock;
import com.android.systemui.statusbar.policy.DateView;
import com.android.systemui.statusbar.policy.NextAlarmController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.RingerModeTracker;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import javax.inject.Inject;
import javax.inject.Named;
/**
* 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
View.OnClickListener, NextAlarmController.NextAlarmChangeCallback,
ZenModeController.Callback, LifecycleOwner {
private static final String TAG = "QuickStatusBarHeader";
private static final boolean DEBUG = false;
/** 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 = 2;
private final Handler mHandler = new Handler();
private final NextAlarmController mAlarmController;
private final ZenModeController mZenController;
private final StatusBarIconController mStatusBarIconController;
private final ActivityStarter mActivityStarter;
private QSPanel mQsPanel;
private boolean mExpanded;
private boolean mListening;
private boolean mQsDisabled;
private QSCarrierGroup mCarrierGroup;
protected QuickQSPanel mHeaderQsPanel;
protected QSTileHost mHost;
private TintedIconManager mIconManager;
private TouchAnimator mStatusIconsAlphaAnimator;
private TouchAnimator mHeaderTextContainerAlphaAnimator;
private TouchAnimator mPrivacyChipAlphaAnimator;
private DualToneHandler mDualToneHandler;
private final CommandQueue mCommandQueue;
private View mSystemIconsView;
private View mQuickQsStatusIcons;
private View mHeaderTextContainerView;
private int mRingerMode = AudioManager.RINGER_MODE_NORMAL;
private AlarmManager.AlarmClockInfo mNextAlarm;
private ImageView mNextAlarmIcon;
/** {@link TextView} containing the actual text indicating when the next alarm will go off. */
private TextView mNextAlarmTextView;
private View mNextAlarmContainer;
private View mStatusSeparator;
private ImageView mRingerModeIcon;
private TextView mRingerModeTextView;
private View mRingerContainer;
private Clock mClockView;
private DateView mDateView;
private BatteryMeterView mBatteryRemainingIcon;
private RingerModeTracker mRingerModeTracker;
// Used for RingerModeTracker
private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
private boolean mHasTopCutout = false;
private int mStatusBarPaddingTop = 0;
private int mRoundedCornerPadding = 0;
private int mContentMarginStart;
private int mContentMarginEnd;
private int mWaterfallTopInset;
private int mCutOutPaddingLeft;
private int mCutOutPaddingRight;
private float mExpandedHeaderAlpha = 1.0f;
private float mKeyguardExpansionFraction;
@Inject
public QuickStatusBarHeader(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
NextAlarmController nextAlarmController, ZenModeController zenModeController,
StatusBarIconController statusBarIconController,
ActivityStarter activityStarter,
CommandQueue commandQueue, RingerModeTracker ringerModeTracker) {
super(context, attrs);
mAlarmController = nextAlarmController;
mZenController = zenModeController;
mStatusBarIconController = statusBarIconController;
mActivityStarter = activityStarter;
mDualToneHandler = new DualToneHandler(
new ContextThemeWrapper(context, R.style.QSHeaderTheme));
mCommandQueue = commandQueue;
mRingerModeTracker = ringerModeTracker;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mHeaderQsPanel = findViewById(R.id.quick_qs_panel);
mSystemIconsView = findViewById(R.id.quick_status_bar_system_icons);
mQuickQsStatusIcons = findViewById(R.id.quick_qs_status_icons);
StatusIconContainer iconContainer = findViewById(R.id.statusIcons);
// Ignore privacy icons because they show in the space above QQS
iconContainer.addIgnoredSlots(getIgnoredIconSlots());
iconContainer.setShouldRestrictIcons(false);
mIconManager = new TintedIconManager(iconContainer, mCommandQueue);
// Views corresponding to the header info section (e.g. ringer and next alarm).
mHeaderTextContainerView = findViewById(R.id.header_text_container);
mStatusSeparator = findViewById(R.id.status_separator);
mNextAlarmIcon = findViewById(R.id.next_alarm_icon);
mNextAlarmTextView = findViewById(R.id.next_alarm_text);
mNextAlarmContainer = findViewById(R.id.alarm_container);
mNextAlarmContainer.setOnClickListener(this::onClick);
mRingerModeIcon = findViewById(R.id.ringer_mode_icon);
mRingerModeTextView = findViewById(R.id.ringer_mode_text);
mRingerContainer = findViewById(R.id.ringer_container);
mRingerContainer.setOnClickListener(this::onClick);
mCarrierGroup = findViewById(R.id.carrier_group);
updateResources();
Rect tintArea = new Rect(0, 0, 0, 0);
int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
android.R.attr.colorForeground);
float intensity = getColorIntensity(colorForeground);
int fillColor = mDualToneHandler.getSingleColor(intensity);
// Set light text on the header icons because they will always be on a black background
applyDarkness(R.id.clock, tintArea, 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
// Set the correct tint for the status icons so they contrast
mIconManager.setTint(fillColor);
mNextAlarmIcon.setImageTintList(ColorStateList.valueOf(fillColor));
mRingerModeIcon.setImageTintList(ColorStateList.valueOf(fillColor));
mClockView = findViewById(R.id.clock);
mClockView.setOnClickListener(this);
mDateView = findViewById(R.id.date);
// Tint for the battery icons are handled in setupHost()
mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon);
// Don't need to worry about tuner settings for this icon
mBatteryRemainingIcon.setIgnoreTunerUpdates(true);
// QS will always show the estimate, and BatteryMeterView handles the case where
// it's unavailable or charging
mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
mRingerModeTextView.setSelected(true);
mNextAlarmTextView.setSelected(true);
}
public QuickQSPanel getHeaderQsPanel() {
return mHeaderQsPanel;
}
private List<String> getIgnoredIconSlots() {
ArrayList<String> ignored = new ArrayList<>();
ignored.add(mContext.getResources().getString(
com.android.internal.R.string.status_bar_camera));
ignored.add(mContext.getResources().getString(
com.android.internal.R.string.status_bar_microphone));
return ignored;
}
private void updateStatusText() {
boolean changed = updateRingerStatus() || updateAlarmStatus();
if (changed) {
boolean alarmVisible = mNextAlarmTextView.getVisibility() == View.VISIBLE;
boolean ringerVisible = mRingerModeTextView.getVisibility() == View.VISIBLE;
mStatusSeparator.setVisibility(alarmVisible && ringerVisible ? View.VISIBLE
: View.GONE);
}
}
private boolean updateRingerStatus() {
boolean isOriginalVisible = mRingerModeTextView.getVisibility() == View.VISIBLE;
CharSequence originalRingerText = mRingerModeTextView.getText();
boolean ringerVisible = false;
if (!ZenModeConfig.isZenOverridingRinger(mZenController.getZen(),
mZenController.getConsolidatedPolicy())) {
if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
mRingerModeIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
mRingerModeTextView.setText(R.string.qs_status_phone_vibrate);
ringerVisible = true;
} else if (mRingerMode == AudioManager.RINGER_MODE_SILENT) {
mRingerModeIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
mRingerModeTextView.setText(R.string.qs_status_phone_muted);
ringerVisible = true;
}
}
mRingerModeIcon.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
mRingerModeTextView.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
mRingerContainer.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
return isOriginalVisible != ringerVisible ||
!Objects.equals(originalRingerText, mRingerModeTextView.getText());
}
private boolean updateAlarmStatus() {
boolean isOriginalVisible = mNextAlarmTextView.getVisibility() == View.VISIBLE;
CharSequence originalAlarmText = mNextAlarmTextView.getText();
boolean alarmVisible = false;
if (mNextAlarm != null) {
alarmVisible = true;
mNextAlarmTextView.setText(formatNextAlarm(mNextAlarm));
}
mNextAlarmIcon.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
mNextAlarmTextView.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
mNextAlarmContainer.setVisibility(alarmVisible ? View.VISIBLE : View.GONE);
return isOriginalVisible != alarmVisible ||
!Objects.equals(originalAlarmText, mNextAlarmTextView.getText());
}
private void applyDarkness(int id, Rect tintArea, float intensity, int color) {
View v = findViewById(id);
if (v instanceof DarkReceiver) {
((DarkReceiver) v).onDarkChanged(tintArea, intensity, color);
}
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
updateResources();
// Update color schemes in landscape to use wallpaperTextColor
boolean shouldUseWallpaperTextColor =
newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE;
mClockView.useWallpaperTextColor(shouldUseWallpaperTextColor);
}
@Override
public void onRtlPropertiesChanged(int layoutDirection) {
super.onRtlPropertiesChanged(layoutDirection);
updateResources();
}
/**
* The height of QQS should always be the status bar height + 128dp. This is normally easy, but
* when there is a notch involved the status bar can remain a fixed pixel size.
*/
private void updateMinimumHeight() {
int sbHeight = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height);
int qqsHeight = mContext.getResources().getDimensionPixelSize(
R.dimen.qs_quick_header_panel_height);
setMinimumHeight(sbHeight + qqsHeight);
}
private void updateResources() {
Resources resources = mContext.getResources();
updateMinimumHeight();
mRoundedCornerPadding = resources.getDimensionPixelSize(
R.dimen.rounded_corner_content_padding);
mStatusBarPaddingTop = resources.getDimensionPixelSize(R.dimen.status_bar_padding_top);
// Update height for a few views, especially due to landscape mode restricting space.
mHeaderTextContainerView.getLayoutParams().height =
resources.getDimensionPixelSize(R.dimen.qs_header_tooltip_height);
mHeaderTextContainerView.setLayoutParams(mHeaderTextContainerView.getLayoutParams());
mSystemIconsView.getLayoutParams().height = resources.getDimensionPixelSize(
com.android.internal.R.dimen.quick_qs_offset_height);
mSystemIconsView.setLayoutParams(mSystemIconsView.getLayoutParams());
ViewGroup.LayoutParams lp = getLayoutParams();
if (mQsDisabled) {
lp.height = resources.getDimensionPixelSize(
com.android.internal.R.dimen.quick_qs_offset_height);
} else {
lp.height = WRAP_CONTENT;
}
setLayoutParams(lp);
updateStatusIconAlphaAnimator();
updateHeaderTextContainerAlphaAnimator();
}
private void updateStatusIconAlphaAnimator() {
mStatusIconsAlphaAnimator = new TouchAnimator.Builder()
.addFloat(mQuickQsStatusIcons, "alpha", 1, 0, 0)
.build();
}
private void updateHeaderTextContainerAlphaAnimator() {
mHeaderTextContainerAlphaAnimator = new TouchAnimator.Builder()
.addFloat(mHeaderTextContainerView, "alpha", 0, 0, mExpandedHeaderAlpha)
.build();
}
public void setExpanded(boolean expanded) {
if (mExpanded == expanded) return;
mExpanded = expanded;
mHeaderQsPanel.setExpanded(expanded);
updateEverything();
}
/**
* Animates the inner contents based on the given expansion details.
*
* @param forceExpanded whether we should show the state expanded forcibly
* @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 forceExpanded, float expansionFraction,
float panelTranslationY) {
final float keyguardExpansionFraction = forceExpanded ? 1f : expansionFraction;
if (mStatusIconsAlphaAnimator != null) {
mStatusIconsAlphaAnimator.setPosition(keyguardExpansionFraction);
}
if (forceExpanded) {
// 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);
if (keyguardExpansionFraction > 0) {
mHeaderTextContainerView.setVisibility(VISIBLE);
} else {
mHeaderTextContainerView.setVisibility(INVISIBLE);
}
}
if (expansionFraction < 1 && expansionFraction > 0.99) {
if (mHeaderQsPanel.switchTileLayout()) {
updateResources();
}
}
mKeyguardExpansionFraction = keyguardExpansionFraction;
}
public void disable(int state1, int state2, boolean animate) {
final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
if (disabled == mQsDisabled) return;
mQsDisabled = disabled;
mHeaderQsPanel.setDisabledByPolicy(disabled);
mHeaderTextContainerView.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
mQuickQsStatusIcons.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
updateResources();
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
mRingerModeTracker.getRingerModeInternal().observe(this, ringer -> {
mRingerMode = ringer;
updateStatusText();
});
mStatusBarIconController.addIconGroup(mIconManager);
requestApplyInsets();
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
// Handle padding of the clock
DisplayCutout cutout = insets.getDisplayCutout();
Pair<Integer, Integer> cornerCutoutPadding = StatusBarWindowView.cornerCutoutMargins(
cutout, getDisplay());
Pair<Integer, Integer> padding =
StatusBarWindowView.paddingNeededForCutoutAndRoundedCorner(
cutout, cornerCutoutPadding, -1);
mCutOutPaddingLeft = padding.first;
mCutOutPaddingRight = padding.second;
mWaterfallTopInset = cutout == null ? 0 : cutout.getWaterfallInsets().top;
updateClockPadding();
return super.onApplyWindowInsets(insets);
}
private void updateClockPadding() {
int clockPaddingLeft = 0;
int clockPaddingRight = 0;
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
int leftMargin = lp.leftMargin;
int rightMargin = lp.rightMargin;
// The clock might collide with cutouts, let's shift it out of the way.
// We only do that if the inset is bigger than our own padding, since it's nicer to
// align with
if (mCutOutPaddingLeft > 0) {
// if there's a cutout, let's use at least the rounded corner inset
int cutoutPadding = Math.max(mCutOutPaddingLeft, mRoundedCornerPadding);
int contentMarginLeft = isLayoutRtl() ? mContentMarginEnd : mContentMarginStart;
clockPaddingLeft = Math.max(cutoutPadding - contentMarginLeft - leftMargin, 0);
}
if (mCutOutPaddingRight > 0) {
// if there's a cutout, let's use at least the rounded corner inset
int cutoutPadding = Math.max(mCutOutPaddingRight, mRoundedCornerPadding);
int contentMarginRight = isLayoutRtl() ? mContentMarginStart : mContentMarginEnd;
clockPaddingRight = Math.max(cutoutPadding - contentMarginRight - rightMargin, 0);
}
mSystemIconsView.setPadding(clockPaddingLeft,
mWaterfallTopInset + mStatusBarPaddingTop,
clockPaddingRight,
0);
}
@Override
@VisibleForTesting
public void onDetachedFromWindow() {
setListening(false);
mRingerModeTracker.getRingerModeInternal().removeObservers(this);
mStatusBarIconController.removeIconGroup(mIconManager);
super.onDetachedFromWindow();
}
public void setListening(boolean listening) {
if (listening == mListening) {
return;
}
mHeaderQsPanel.setListening(listening);
if (mHeaderQsPanel.switchTileLayout()) {
updateResources();
}
mListening = listening;
if (listening) {
mZenController.addCallback(this);
mAlarmController.addCallback(this);
mLifecycle.setCurrentState(Lifecycle.State.RESUMED);
} else {
mZenController.removeCallback(this);
mAlarmController.removeCallback(this);
mLifecycle.setCurrentState(Lifecycle.State.CREATED);
}
}
@Override
public void onClick(View v) {
if (v == mClockView) {
mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
AlarmClock.ACTION_SHOW_ALARMS), 0);
} else if (v == mNextAlarmContainer && mNextAlarmContainer.isVisibleToUser()) {
if (mNextAlarm.getShowIntent() != null) {
mActivityStarter.postStartActivityDismissingKeyguard(
mNextAlarm.getShowIntent());
} else {
Log.d(TAG, "No PendingIntent for next alarm. Using default intent");
mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
AlarmClock.ACTION_SHOW_ALARMS), 0);
}
} else if (v == mRingerContainer && mRingerContainer.isVisibleToUser()) {
mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
Settings.ACTION_SOUND_SETTINGS), 0);
}
}
@Override
public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
mNextAlarm = nextAlarm;
updateStatusText();
}
@Override
public void onZenChanged(int zen) {
updateStatusText();
}
@Override
public void onConfigChanged(ZenModeConfig config) {
updateStatusText();
}
public void updateEverything() {
post(() -> setClickable(!mExpanded));
}
public void setQSPanel(final QSPanel qsPanel) {
mQsPanel = qsPanel;
setupHost(qsPanel.getHost());
}
public void setupHost(final QSTileHost host) {
mHost = host;
//host.setHeaderView(mExpandIndicator);
mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
mHeaderQsPanel.setHost(host, null /* No customization in header */);
Rect tintArea = new Rect(0, 0, 0, 0);
int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
android.R.attr.colorForeground);
float intensity = getColorIntensity(colorForeground);
int fillColor = mDualToneHandler.getSingleColor(intensity);
mBatteryRemainingIcon.onDarkChanged(tintArea, intensity, fillColor);
}
public void setCallback(Callback qsPanelCallback) {
mHeaderQsPanel.setCallback(qsPanelCallback);
}
private String formatNextAlarm(AlarmManager.AlarmClockInfo info) {
if (info == null) {
return "";
}
String skeleton = android.text.format.DateFormat
.is24HourFormat(mContext, ActivityManager.getCurrentUser()) ? "EHm" : "Ehma";
String pattern = android.text.format.DateFormat
.getBestDateTimePattern(Locale.getDefault(), skeleton);
return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString();
}
public static float getColorIntensity(@ColorInt int color) {
return color == Color.WHITE ? 0 : 1;
}
@NonNull
@Override
public Lifecycle getLifecycle() {
return mLifecycle;
}
public void setContentMargins(int marginStart, int marginEnd) {
mContentMarginStart = marginStart;
mContentMarginEnd = marginEnd;
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
if (view == mHeaderQsPanel) {
// QS panel doesn't lays out some of its content full width
mHeaderQsPanel.setContentMargins(marginStart, marginEnd);
} else {
MarginLayoutParams lp = (MarginLayoutParams) view.getLayoutParams();
lp.setMarginStart(marginStart);
lp.setMarginEnd(marginEnd);
view.setLayoutParams(lp);
}
}
updateClockPadding();
}
public void setExpandedScrollAmount(int scrollY) {
// The scrolling of the expanded qs has changed. Since the header text isn't part of it,
// but would overlap content, we're fading it out.
float newAlpha = 1.0f;
if (mHeaderTextContainerView.getHeight() > 0) {
newAlpha = MathUtils.map(0, mHeaderTextContainerView.getHeight() / 2.0f, 1.0f, 0.0f,
scrollY);
newAlpha = Interpolators.ALPHA_OUT.getInterpolation(newAlpha);
}
mHeaderTextContainerView.setScrollY(scrollY);
if (newAlpha != mExpandedHeaderAlpha) {
mExpandedHeaderAlpha = newAlpha;
mHeaderTextContainerView.setAlpha(MathUtils.lerp(0.0f, mExpandedHeaderAlpha,
mKeyguardExpansionFraction));
updateHeaderTextContainerAlphaAnimator();
}
}
}