<dimen name="global_actions_top_padding">100dp</dimen>
+ <!-- the maximum offset in either direction that elements are moved horizontally to prevent
+ burn-in on AOD -->
+ <dimen name="burn_in_prevention_offset_x">8dp</dimen>
+
+ <!-- the maximum offset in either direction that elements are moved vertically to prevent
+ burn-in on AOD -->
+ <dimen name="burn_in_prevention_offset_y">50dp</dimen>
+
<dimen name="corner_size">16dp</dimen>
<dimen name="top_padding">0dp</dimen>
<dimen name="bottom_padding">48dp</dimen>
updateRelativeOffset();
}
+ public void setDarkOffsetX(int offsetX) {
+ mShelfIcons.setDarkOffsetX(offsetX);
+ }
+
private class ShelfState extends ExpandableViewState {
private float openedAmount;
private boolean hasItemsInStableShelf;
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.statusbar.notification.NotificationUtils.interpolate;
+
import android.content.res.Resources;
import android.graphics.Path;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.PathInterpolator;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationUtils;
/**
* Utility class to calculate the clock position and top padding of notifications on Keyguard.
private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MIN = 1.4f;
private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MAX = 3.2f;
+ private static final long MILLIS_PER_MINUTES = 1000 * 60;
+ private static final float BURN_IN_PREVENTION_PERIOD_Y = 521;
+ private static final float BURN_IN_PREVENTION_PERIOD_X = 83;
+
private int mClockNotificationsMarginMin;
private int mClockNotificationsMarginMax;
private float mClockYFractionMin;
private int mKeyguardStatusHeight;
private float mEmptyDragAmount;
private float mDensity;
+ private int mBurnInPreventionOffsetX;
+ private int mBurnInPreventionOffsetY;
/**
* The number (fractional) of notifications the "more" card counts when calculating how many
(float) res.getDimensionPixelSize(R.dimen.notification_shelf_height) /
res.getDimensionPixelSize(R.dimen.notification_min_height);
mDensity = res.getDisplayMetrics().density;
+ mBurnInPreventionOffsetX = res.getDimensionPixelSize(
+ R.dimen.burn_in_prevention_offset_x);
+ mBurnInPreventionOffsetY = res.getDimensionPixelSize(
+ R.dimen.burn_in_prevention_offset_y);
}
public void setup(int maxKeyguardNotifications, int maxPanelHeight, float expandedHeight,
y + getClockNotificationsPadding() + mKeyguardStatusHeight);
result.clockAlpha = getClockAlpha(result.clockScale);
- result.stackScrollerPadding = (int) NotificationUtils.interpolate(
+ result.stackScrollerPadding = (int) interpolate(
result.stackScrollerPadding,
mClockBottom + y,
mDarkAmount);
+
+ result.clockX = (int) interpolate(0, burnInPreventionOffsetX(), mDarkAmount);
}
private float getClockScale(int notificationPadding, int clockY, int startPadding) {
private int getClockY() {
// Dark: Align the bottom edge of the clock at one third:
// clockBottomEdge = result - mKeyguardStatusHeight / 2 + mClockBottom
- float clockYDark = (0.33f * mHeight + (float) mKeyguardStatusHeight / 2 - mClockBottom);
+ float clockYDark = (0.33f * mHeight + (float) mKeyguardStatusHeight / 2 - mClockBottom)
+ + burnInPreventionOffsetY();
float clockYRegular = getClockYFraction() * mHeight;
- return (int) NotificationUtils.interpolate(clockYRegular, clockYDark, mDarkAmount);
+ return (int) interpolate(clockYRegular, clockYDark, mDarkAmount);
+ }
+
+ private float burnInPreventionOffsetY() {
+ return zigzag(System.currentTimeMillis() / MILLIS_PER_MINUTES,
+ mBurnInPreventionOffsetY * 2,
+ BURN_IN_PREVENTION_PERIOD_Y)
+ - mBurnInPreventionOffsetY;
+ }
+
+ private float burnInPreventionOffsetX() {
+ return zigzag(System.currentTimeMillis() / MILLIS_PER_MINUTES,
+ mBurnInPreventionOffsetX * 2,
+ BURN_IN_PREVENTION_PERIOD_X)
+ - mBurnInPreventionOffsetX;
+ }
+
+ /**
+ * Implements a continuous, piecewise linear, periodic zig-zag function
+ *
+ * Can be thought of as a linear approximation of abs(sin(x)))
+ *
+ * @param period period of the function, ie. zigzag(x + period) == zigzag(x)
+ * @param amplitude maximum value of the function
+ * @return a value between 0 and amplitude
+ */
+ private float zigzag(float x, float amplitude, float period) {
+ float xprime = (x % period) / (period / 2);
+ float interpolationAmount = (xprime <= 1) ? xprime : (2 - xprime);
+ return interpolate(0, amplitude, interpolationAmount);
}
private float getClockYExpansionAdjustment() {
* the padding, but not the overall panel size.
*/
public int stackScrollerPaddingAdjustment;
+
+ /** The x translation of the clock. */
+ public int clockX;
}
}
private boolean mDisallowNextAnimation;
private boolean mAnimationsEnabled = true;
private ArrayMap<String, ArrayList<StatusBarIcon>> mReplacingIcons;
+ private int mDarkOffsetX;
public NotificationIconContainer(Context context, AttributeSet attrs) {
super(context, attrs);
iconState.xTranslation = getWidth() - iconState.xTranslation - view.getWidth();
}
}
+
+ if (mDark && mDarkOffsetX != 0) {
+ for (int i = 0; i < childCount; i++) {
+ View view = getChildAt(i);
+ IconState iconState = mIconStates.get(view);
+ iconState.xTranslation += mDarkOffsetX;
+ }
+ }
}
private float getLayoutEnd() {
mReplacingIcons = replacingIcons;
}
+ public void setDarkOffsetX(int offsetX) {
+ mDarkOffsetX = offsetX;
+ }
+
public class IconState extends ViewState {
public float iconAppearAmount = 1.0f;
public float clampedAppearAmount = 1.0f;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
import android.view.WindowInsets;
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
-import android.widget.TextView;
+
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.DejankUtils;
-import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.SystemUIFactory;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
-import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackStateAnimator;
private int mUnlockMoveDistance;
private float mEmptyDragAmount;
- private ObjectAnimator mClockAnimator;
- private int mClockAnimationTarget = -1;
+ private Animator mClockAnimator;
+ private int mClockAnimationTargetX = Integer.MIN_VALUE;
+ private int mClockAnimationTargetY = Integer.MIN_VALUE;
private int mTopPaddingAdjustment;
private KeyguardClockPositionAlgorithm mClockPositionAlgorithm =
new KeyguardClockPositionAlgorithm();
mDarkAmount);
mClockPositionAlgorithm.run(mClockPositionResult);
if (animate || mClockAnimator != null) {
- startClockAnimation(mClockPositionResult.clockY);
+ startClockAnimation(mClockPositionResult.clockX, mClockPositionResult.clockY);
} else {
+ mKeyguardStatusView.setX(mClockPositionResult.clockX);
mKeyguardStatusView.setY(mClockPositionResult.clockY);
}
updateClock(mClockPositionResult.clockAlpha, mClockPositionResult.clockScale);
mTopPaddingAdjustment = mClockPositionResult.stackScrollerPaddingAdjustment;
}
mNotificationStackScroller.setIntrinsicPadding(stackScrollerPadding);
+ mNotificationStackScroller.setDarkShelfOffsetX(mClockPositionResult.clockX);
requestScrollerTopPaddingUpdate(animate);
}
return count;
}
- private void startClockAnimation(int y) {
- if (mClockAnimationTarget == y) {
+ private void startClockAnimation(int x, int y) {
+ if (mClockAnimationTargetX == x && mClockAnimationTargetY == y) {
return;
}
- mClockAnimationTarget = y;
+ mClockAnimationTargetX = x;
+ mClockAnimationTargetY = y;
getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
mClockAnimator.removeAllListeners();
mClockAnimator.cancel();
}
- mClockAnimator = ObjectAnimator
- .ofFloat(mKeyguardStatusView, View.Y, mClockAnimationTarget);
+ AnimatorSet set = new AnimatorSet();
+ set.play(ObjectAnimator.ofFloat(
+ mKeyguardStatusView, View.Y, mClockAnimationTargetY))
+ .with(ObjectAnimator.ofFloat(
+ mKeyguardStatusView, View.X, mClockAnimationTargetX));
+ mClockAnimator = set;
mClockAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mClockAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
mClockAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mClockAnimator = null;
- mClockAnimationTarget = -1;
+ mClockAnimationTargetX = Integer.MIN_VALUE;
+ mClockAnimationTargetY = Integer.MIN_VALUE;
}
});
mClockAnimator.start();
public void refreshTime() {
mKeyguardStatusView.refreshTime();
+ if (mDarkAmount > 0) {
+ positionClockAndNotifications();
+ }
}
public void setStatusAccessibilityImportance(int mode) {
mHeadsUpGoingAwayAnimationsAllowed = headsUpGoingAwayAnimationsAllowed;
}
+ public void setDarkShelfOffsetX(int shelfOffsetX) {
+ mShelf.setDarkOffsetX(shelfOffsetX);
+ }
+
/**
* A listener that is notified when some child locations might have changed.
*/