OSDN Git Service

AOD: Move clock to prevent burn in
authorAdrian Roos <roosa@google.com>
Thu, 1 Jun 2017 23:09:15 +0000 (16:09 -0700)
committerAdrian Roos <roosa@google.com>
Thu, 8 Jun 2017 00:13:01 +0000 (17:13 -0700)
Change-Id: I4d14aac0a379266b3bdef0a588575017ad345c4d
Merged-In: I4d14aac0a379266b3bdef0a588575017ad345c4d
Fixes: 35850027
Test: Enable AOD, observe that clock slightly moves every minute

packages/SystemUI/res/values/dimens.xml
packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java

index fe422db..fc9e585 100644 (file)
 
     <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>
index d2c0f64..67ea258 100644 (file)
@@ -650,6 +650,10 @@ public class NotificationShelf extends ActivatableNotificationView implements
         updateRelativeOffset();
     }
 
+    public void setDarkOffsetX(int offsetX) {
+        mShelfIcons.setDarkOffsetX(offsetX);
+    }
+
     private class ShelfState extends ExpandableViewState {
         private float openedAmount;
         private boolean hasItemsInStableShelf;
index 7370c03..652288d 100644 (file)
 
 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.
@@ -40,6 +41,10 @@ public class KeyguardClockPositionAlgorithm {
     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;
@@ -52,6 +57,8 @@ public class KeyguardClockPositionAlgorithm {
     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
@@ -86,6 +93,10 @@ public class KeyguardClockPositionAlgorithm {
                 (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,
@@ -122,10 +133,12 @@ public class KeyguardClockPositionAlgorithm {
                 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) {
@@ -154,9 +167,39 @@ public class KeyguardClockPositionAlgorithm {
     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() {
@@ -230,5 +273,8 @@ public class KeyguardClockPositionAlgorithm {
          * the padding, but not the overall panel size.
          */
         public int stackScrollerPaddingAdjustment;
+
+        /** The x translation of the clock. */
+        public int clockX;
     }
 }
index a4fadc4..021e11a 100644 (file)
@@ -123,6 +123,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
     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);
@@ -389,6 +390,14 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
                 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() {
@@ -512,6 +521,10 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
         mReplacingIcons = replacingIcons;
     }
 
+    public void setDarkOffsetX(int offsetX) {
+        mDarkOffsetX = offsetX;
+    }
+
     public class IconState extends ViewState {
         public float iconAppearAmount = 1.0f;
         public float clampedAppearAmount = 1.0f;
index e2b9da0..4701f85 100644 (file)
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.app.ActivityManager;
@@ -43,15 +44,13 @@ import android.view.ViewTreeObserver;
 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;
@@ -69,7 +68,6 @@ import com.android.systemui.statusbar.notification.NotificationUtils;
 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;
 
@@ -168,8 +166,9 @@ public class NotificationPanelView extends PanelView implements
     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();
@@ -459,8 +458,9 @@ public class NotificationPanelView extends PanelView implements
                     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);
@@ -468,6 +468,7 @@ public class NotificationPanelView extends PanelView implements
             mTopPaddingAdjustment = mClockPositionResult.stackScrollerPaddingAdjustment;
         }
         mNotificationStackScroller.setIntrinsicPadding(stackScrollerPadding);
+        mNotificationStackScroller.setDarkShelfOffsetX(mClockPositionResult.clockX);
         requestScrollerTopPaddingUpdate(animate);
     }
 
@@ -523,11 +524,12 @@ public class NotificationPanelView extends PanelView implements
         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() {
@@ -536,15 +538,20 @@ public class NotificationPanelView extends PanelView implements
                     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();
@@ -2613,6 +2620,9 @@ public class NotificationPanelView extends PanelView implements
 
     public void refreshTime() {
         mKeyguardStatusView.refreshTime();
+        if (mDarkAmount > 0) {
+            positionClockAndNotifications();
+        }
     }
 
     public void setStatusAccessibilityImportance(int mode) {
index a3d812c..cbd315b 100644 (file)
@@ -4252,6 +4252,10 @@ public class NotificationStackScrollLayout extends ViewGroup
         mHeadsUpGoingAwayAnimationsAllowed = headsUpGoingAwayAnimationsAllowed;
     }
 
+    public void setDarkShelfOffsetX(int shelfOffsetX) {
+        mShelf.setDarkOffsetX(shelfOffsetX);
+    }
+
     /**
      * A listener that is notified when some child locations might have changed.
      */