Merge "Introduce AmbientState for StackScroller."
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index e5168c4..4369741 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -18,11 +18,13 @@
<resources>
<item type="id" name="translation_y_animator_tag"/>
<item type="id" name="translation_z_animator_tag"/>
+ <item type="id" name="scale_animator_tag"/>
<item type="id" name="alpha_animator_tag"/>
<item type="id" name="top_inset_animator_tag"/>
<item type="id" name="height_animator_tag"/>
<item type="id" name="translation_y_animator_end_value_tag"/>
<item type="id" name="translation_z_animator_end_value_tag"/>
+ <item type="id" name="scale_animator_end_value_tag"/>
<item type="id" name="alpha_animator_end_value_tag"/>
<item type="id" name="top_inset_animator_end_value_tag"/>
<item type="id" name="height_animator_end_value_tag"/>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 1c88ea7..c81a3c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -38,6 +38,7 @@
public abstract class ActivatableNotificationView extends ExpandableOutlineView {
private static final long DOUBLETAP_TIMEOUT_MS = 1000;
+ private static final int BACKGROUND_ANIMATION_LENGTH_MS = 220;
private boolean mDimmed;
@@ -179,7 +180,7 @@
mActivated = false;
}
if (mOnActivatedListener != null) {
- mOnActivatedListener.onReset(this);
+ mOnActivatedListener.onActivationReset(this);
}
removeCallbacks(mTapTimeoutRunnable);
}
@@ -189,12 +190,6 @@
&& Math.abs(event.getY() - mDownY) < mTouchSlop;
}
- /**
- * Sets the notification as dimmed, meaning that it will appear in a more gray variant.
- *
- * @param dimmed Whether the notification should be dimmed.
- * @param fade Whether an animation should be played to change the state.
- */
public void setDimmed(boolean dimmed, boolean fade) {
if (mDimmed != dimmed) {
mDimmed = dimmed;
@@ -226,7 +221,7 @@
}
int startAlpha = mDimmed ? 255 : 0;
int endAlpha = mDimmed ? 0 : 255;
- int duration = NotificationActivator.ANIMATION_LENGTH_MS;
+ int duration = BACKGROUND_ANIMATION_LENGTH_MS;
// Check whether there is already a background animation running.
if (mBackgroundAnimator != null) {
startAlpha = (Integer) mBackgroundAnimator.getAnimatedValue();
@@ -313,8 +308,8 @@
}
@Override
- public void setActualHeight(int actualHeight) {
- super.setActualHeight(actualHeight);
+ public void setActualHeight(int actualHeight, boolean notifyListeners) {
+ super.setActualHeight(actualHeight, notifyListeners);
invalidate();
setPivotY(actualHeight / 2);
}
@@ -331,6 +326,6 @@
public interface OnActivatedListener {
void onActivated(View view);
- void onReset(View view);
+ void onActivationReset(View view);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index a325186..3b53667 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1067,7 +1067,6 @@
entry.row.setSystemExpanded(top);
}
}
- entry.row.setDimmed(onKeyguard, false /* fade */);
boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
if (onKeyguard && (visibleNotifications >= maxKeyguardNotifications
|| !showOnKeyguard)) {
@@ -1087,48 +1086,11 @@
if (onKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) {
mKeyguardIconOverflowContainer.setVisibility(View.VISIBLE);
- mKeyguardIconOverflowContainer.setDimmed(true /* dimmed */, false /* fade */);
} else {
mKeyguardIconOverflowContainer.setVisibility(View.GONE);
}
}
- @Override
- public void onActivated(View view) {
- int n = mNotificationData.size();
- for (int i = 0; i < n; i++) {
- NotificationData.Entry entry = mNotificationData.get(i);
- if (entry.row.getVisibility() != View.GONE) {
- if (view == entry.row) {
- entry.row.getActivator().activate();
- } else {
- entry.row.getActivator().activateInverse();
- }
- }
- }
- if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) {
- if (view == mKeyguardIconOverflowContainer) {
- mKeyguardIconOverflowContainer.getActivator().activate();
- } else {
- mKeyguardIconOverflowContainer.getActivator().activateInverse();
- }
- }
- }
-
- @Override
- public void onReset(View view) {
- int n = mNotificationData.size();
- for (int i = 0; i < n; i++) {
- NotificationData.Entry entry = mNotificationData.get(i);
- if (entry.row.getVisibility() != View.GONE) {
- entry.row.getActivator().reset();
- }
- }
- if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) {
- mKeyguardIconOverflowContainer.getActivator().reset();
- }
- }
-
private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
return sbn.getNotification().priority >= Notification.PRIORITY_LOW;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index e471754..5b2ea0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -117,7 +117,7 @@
} else {
if (mDraggedFarEnough) {
mDraggedFarEnough = false;
- mOnDragDownListener.onReset();
+ mOnDragDownListener.onDragDownReset();
}
}
return true;
@@ -188,7 +188,7 @@
cancelExpansion(mStartingChild);
}
mDraggingDown = false;
- mOnDragDownListener.onReset();
+ mOnDragDownListener.onDragDownReset();
}
private ExpandableView findView(float x, float y) {
@@ -200,7 +200,7 @@
public interface OnDragDownListener {
void onDraggedDown(View startingChild);
- void onReset();
+ void onDragDownReset();
void onThresholdReached();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index e5512a3..39f2bb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -52,7 +52,6 @@
private NotificationContentView mPublicLayout;
private NotificationContentView mPrivateLayout;
private int mMaxExpandHeight;
- private NotificationActivator mActivator;
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -63,8 +62,6 @@
super.onFinishInflate();
mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
-
- mActivator = new NotificationActivator(this, this);
}
@Override
@@ -208,23 +205,10 @@
mPrivateLayout.setVisibility(show ? View.GONE : View.VISIBLE);
}
- /**
- * Sets the notification as dimmed, meaning that it will appear in a more gray variant.
- */
- @Override
- public void setDimmed(boolean dimmed, boolean fade) {
- super.setDimmed(dimmed, fade);
- mActivator.setDimmed(dimmed, fade);
- }
-
public int getMaxExpandHeight() {
return mMaxExpandHeight;
}
- public NotificationActivator getActivator() {
- return mActivator;
- }
-
/**
* @return the potential height this view could expand in addition.
*/
@@ -238,10 +222,10 @@
}
@Override
- public void setActualHeight(int height) {
- mPrivateLayout.setActualHeight(height);
+ public void setActualHeight(int height, boolean notifyListeners) {
+ mPrivateLayout.setActualHeight(height, notifyListeners);
invalidate();
- super.setActualHeight(height);
+ super.setActualHeight(height, notifyListeners);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index 43eb5b5..a42c194 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -33,8 +33,8 @@
}
@Override
- public void setActualHeight(int actualHeight) {
- super.setActualHeight(actualHeight);
+ public void setActualHeight(int actualHeight, boolean notifyListeners) {
+ super.setActualHeight(actualHeight, notifyListeners);
updateOutline();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 169521d..281bd2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -61,10 +61,19 @@
/**
* Sets the actual height of this notification. This is different than the laid out
* {@link View#getHeight()}, as we want to avoid layouting during scrolling and expanding.
+ *
+ * @param actualHeight The height of this notification.
+ * @param notifyListeners Whether the listener should be informed about the change.
*/
- public void setActualHeight(int actualHeight) {
+ public void setActualHeight(int actualHeight, boolean notifyListeners) {
mActualHeight = actualHeight;
- notifyHeightChanged();
+ if (notifyListeners) {
+ notifyHeightChanged();
+ }
+ }
+
+ public void setActualHeight(int actualHeight) {
+ setActualHeight(actualHeight, true);
}
/**
@@ -91,6 +100,15 @@
}
/**
+ * Sets the notification as dimmed. The default implementation does nothing.
+ *
+ * @param dimmed Whether the notification should be dimmed.
+ * @param fade Whether an animation should be played to change the state.
+ */
+ public void setDimmed(boolean dimmed, boolean fade) {
+ }
+
+ /**
* @return The desired notification height.
*/
public int getIntrinsicHeight() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java
deleted file mode 100644
index a03aeec..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2014 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.statusbar;
-
-import android.content.Context;
-import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-import com.android.systemui.R;
-
-/**
- * A helper class used by both {@link com.android.systemui.statusbar.ExpandableNotificationRow} and
- * {@link com.android.systemui.statusbar.NotificationOverflowIconsView} to make a notification look
- * active after tapping it once on the Keyguard.
- */
-public class NotificationActivator {
-
- public static final int ANIMATION_LENGTH_MS = 220;
- private static final float INVERSE_ALPHA = 0.9f;
- private static final float DIMMED_SCALE = 0.95f;
-
- /**
- * Normal state. Notification is fully interactable.
- */
- private static final int STATE_NORMAL = 0;
-
- /**
- * Dimmed state. Neutral state when on the lockscreen, with slight transparency and scaled down
- * a bit.
- */
- private static final int STATE_DIMMED = 1;
-
- /**
- * Activated state. Used after tapping a notification on the lockscreen. Normal transparency and
- * normal scale.
- */
- private static final int STATE_ACTIVATED = 2;
-
- /**
- * Inverse activated state. Used for the other notifications on the lockscreen when tapping on
- * one.
- */
- private static final int STATE_ACTIVATED_INVERSE = 3;
-
- private final View mTargetView;
- private final View mHotspotView;
- private final Interpolator mFastOutSlowInInterpolator;
- private final Interpolator mLinearOutSlowInInterpolator;
- private final int mTranslationZ;
-
- private int mState;
-
- public NotificationActivator(View targetView, View hotspotView) {
- mTargetView = targetView;
- mHotspotView = hotspotView;
- Context ctx = targetView.getContext();
- mFastOutSlowInInterpolator =
- AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_slow_in);
- mLinearOutSlowInInterpolator =
- AnimationUtils.loadInterpolator(ctx, android.R.interpolator.linear_out_slow_in);
- mTranslationZ =
- ctx.getResources().getDimensionPixelSize(R.dimen.z_distance_between_notifications);
- mTargetView.animate().setDuration(ANIMATION_LENGTH_MS);
- }
-
- public void activateInverse() {
- if (mState == STATE_ACTIVATED_INVERSE) {
- return;
- }
- mTargetView.animate().cancel();
- mTargetView.animate().withLayer().alpha(INVERSE_ALPHA);
- mState = STATE_ACTIVATED_INVERSE;
- }
-
- public void addHotspot() {
- mHotspotView.getBackground().setHotspot(
- 0, mHotspotView.getWidth()/2, mHotspotView.getHeight()/2);
- }
-
- public void activate() {
- if (mState == STATE_ACTIVATED) {
- return;
- }
- mTargetView.animate().cancel();
- mTargetView.animate()
- .setInterpolator(mLinearOutSlowInInterpolator)
- .scaleX(1)
- .scaleY(1)
- .translationZBy(mTranslationZ);
- mState = STATE_ACTIVATED;
- }
-
- public void reset() {
- if (mState == STATE_DIMMED) {
- return;
- }
- mTargetView.animate().cancel();
- mTargetView.animate()
- .setInterpolator(mFastOutSlowInInterpolator)
- .scaleX(DIMMED_SCALE)
- .scaleY(DIMMED_SCALE)
- .translationZBy(-mTranslationZ);
- if (mTargetView.getAlpha() != 1.0f) {
- mTargetView.animate().withLayer().alpha(1);
- }
- mState = STATE_DIMMED;
- }
-
- public void setDimmed(boolean dimmed, boolean fade) {
- if (dimmed) {
- mTargetView.animate().cancel();
- if (fade) {
- mTargetView.animate()
- .setInterpolator(mFastOutSlowInInterpolator)
- .scaleX(DIMMED_SCALE)
- .scaleY(DIMMED_SCALE);
- } else {
- mTargetView.setScaleX(DIMMED_SCALE);
- mTargetView.setScaleY(DIMMED_SCALE);
- }
- mState = STATE_DIMMED;
- } else {
- mTargetView.animate().cancel();
- if (fade) {
- mTargetView.animate()
- .setInterpolator(mFastOutSlowInInterpolator)
- .scaleX(1)
- .scaleY(1);
- } else {
- mTargetView.animate().cancel();
- mTargetView.setScaleX(1);
- mTargetView.setScaleY(1);
- }
- mState = STATE_NORMAL;
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 379bd05..9df2701 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -70,8 +70,8 @@
}
@Override
- public void setActualHeight(int actualHeight) {
- super.setActualHeight(actualHeight);
+ public void setActualHeight(int actualHeight, boolean notifyListeners) {
+ super.setActualHeight(actualHeight, notifyListeners);
selectLayout();
updateClipping();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
index e6b5600..864c597 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
@@ -28,14 +28,13 @@
public class NotificationOverflowContainer extends ActivatableNotificationView {
private NotificationOverflowIconsView mIconsView;
- private NotificationActivator mActivator;
public NotificationOverflowContainer(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
- public void setActualHeight(int currentHeight) {
+ public void setActualHeight(int currentHeight, boolean notifyListeners) {
// noop
}
@@ -54,22 +53,9 @@
super.onFinishInflate();
mIconsView = (NotificationOverflowIconsView) findViewById(R.id.overflow_icons_view);
mIconsView.setMoreText((TextView) findViewById(R.id.more_text));
-
- mActivator = new NotificationActivator(this, this);
- setDimmed(true, false);
- }
-
- @Override
- public void setDimmed(boolean dimmed, boolean fade) {
- super.setDimmed(dimmed, fade);
- mActivator.setDimmed(dimmed, fade);
}
public NotificationOverflowIconsView getIconsView() {
return mIconsView;
}
-
- public NotificationActivator getActivator() {
- return mActivator;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index c4ee6ff..304430a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -2790,6 +2790,7 @@
mSettingsContainer.setKeyguardShowing(false);
}
+ updateStackScrollerState();
updatePublicMode();
updateRowStates();
checkBarModes();
@@ -2797,6 +2798,10 @@
updateCarrierLabelVisibility(false);
}
+ public void updateStackScrollerState() {
+ mStackScroller.setDimmed(mState == StatusBarState.KEYGUARD, false /* animate */);
+ }
+
public void userActivity() {
if (mState == StatusBarState.KEYGUARD) {
mKeyguardViewMediatorCallback.userActivity();
@@ -2850,7 +2855,7 @@
public void onActivated(View view) {
userActivity();
mKeyguardIndicationTextView.switchIndication(R.string.notification_tap_again);
- super.onActivated(view);
+ mStackScroller.setActivatedChild(view);
}
/**
@@ -2862,9 +2867,11 @@
}
@Override
- public void onReset(View view) {
- super.onReset(view);
- mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
+ public void onActivationReset(View view) {
+ if (view == mStackScroller.getActivatedChild()) {
+ mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
+ mStackScroller.setActivatedChild(null);
+ }
}
public void onTrackingStarted() {
@@ -2896,30 +2903,12 @@
}
@Override
- public void onReset() {
- int n = mNotificationData.size();
- for (int i = 0; i < n; i++) {
- NotificationData.Entry entry = mNotificationData.get(i);
- if (entry.row.getVisibility() != View.GONE) {
- entry.row.setDimmed(true /* dimmed */, true /* fade */);
- }
- }
- if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) {
- mKeyguardIconOverflowContainer.setDimmed(true /* dimmed */, true /* fade */);
- }
+ public void onDragDownReset() {
+ mStackScroller.setDimmed(true /* dimmed */, true /* animated */);
}
public void onThresholdReached() {
- int n = mNotificationData.size();
- for (int i = 0; i < n; i++) {
- NotificationData.Entry entry = mNotificationData.get(i);
- if (entry.row.getVisibility() != View.GONE) {
- entry.row.setDimmed(false /* dimmed */, true /* fade */);
- }
- }
- if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) {
- mKeyguardIconOverflowContainer.setDimmed(false /* dimmed */, true /* fade */);
- }
+ mStackScroller.setDimmed(false /* dimmed */, true /* animate */);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
new file mode 100644
index 0000000..4121a40
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 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.statusbar.stack;
+
+import android.view.View;
+
+import java.util.ArrayList;
+
+/**
+ * A global state to track all input states for the algorithm.
+ */
+public class AmbientState {
+ private ArrayList<View> mDraggedViews = new ArrayList<View>();
+ private int mScrollY;
+ private boolean mDimmed;
+ private View mActivatedChild;
+
+ public int getScrollY() {
+ return mScrollY;
+ }
+
+ public void setScrollY(int scrollY) {
+ this.mScrollY = scrollY;
+ }
+
+ public void onBeginDrag(View view) {
+ mDraggedViews.add(view);
+ }
+
+ public void onDragFinished(View view) {
+ mDraggedViews.remove(view);
+ }
+
+ public ArrayList<View> getDraggedViews() {
+ return mDraggedViews;
+ }
+
+ /**
+ * @param dimmed Whether we are in a dimmed state (on the lockscreen), where the backgrounds are
+ * translucent and everything is scaled back a bit.
+ */
+ public void setDimmed(boolean dimmed) {
+ mDimmed = dimmed;
+ }
+
+ /**
+ * In dimmed mode, a child can be activated, which happens on the first tap of the double-tap
+ * interaction. This child is then scaled normally and its background is fully opaque.
+ */
+ public void setActivatedChild(View activatedChild) {
+ mActivatedChild = activatedChild;
+ }
+
+ public boolean isDimmed() {
+ return mDimmed;
+ }
+
+ public View getActivatedChild() {
+ return mActivatedChild;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
new file mode 100644
index 0000000..41914ed
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2014 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.statusbar.stack;
+
+import java.util.ArrayList;
+
+/**
+ * Filters the animations for only a certain type of properties.
+ */
+public class AnimationFilter {
+ boolean animateAlpha;
+ boolean animateY;
+ boolean animateZ;
+ boolean animateScale;
+ boolean animateHeight;
+ boolean animateDimmed;
+
+ public AnimationFilter animateAlpha() {
+ animateAlpha = true;
+ return this;
+ }
+
+ public AnimationFilter animateY() {
+ animateY = true;
+ return this;
+ }
+
+ public AnimationFilter animateZ() {
+ animateZ = true;
+ return this;
+ }
+
+ public AnimationFilter animateScale() {
+ animateScale = true;
+ return this;
+ }
+
+ public AnimationFilter animateHeight() {
+ animateHeight = true;
+ return this;
+ }
+
+ public AnimationFilter animateDimmed() {
+ animateDimmed = true;
+ return this;
+ }
+
+ /**
+ * Combines multiple filters into {@code this} filter, using or as the operand .
+ *
+ * @param events The animation events from the filters to combine.
+ */
+ public void applyCombination(ArrayList<NotificationStackScrollLayout.AnimationEvent> events) {
+ reset();
+ int size = events.size();
+ for (int i = 0; i < size; i++) {
+ combineFilter(events.get(i).filter);
+ }
+ }
+
+ private void combineFilter(AnimationFilter filter) {
+ animateAlpha |= filter.animateAlpha;
+ animateY |= filter.animateY;
+ animateZ |= filter.animateZ;
+ animateScale |= filter.animateScale;
+ animateHeight |= filter.animateHeight;
+ animateDimmed |= filter.animateDimmed;
+ }
+
+ private void reset() {
+ animateAlpha = false;
+ animateY = false;
+ animateZ = false;
+ animateScale = false;
+ animateHeight = false;
+ animateDimmed = false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 59d717c..7398035 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -84,7 +84,6 @@
private int mEmptyMarginBottom;
private int mPaddingBetweenElements;
private int mTopPadding;
- private boolean mListenForHeightChanges = true;
/**
* The algorithm which calculates the properties for our children
@@ -95,6 +94,7 @@
* The current State this Layout is in
*/
private StackScrollState mCurrentStackScrollState = new StackScrollState(this);
+ private AmbientState mAmbientState = new AmbientState();
private ArrayList<View> mChildrenToAddAnimated = new ArrayList<View>();
private ArrayList<View> mChildrenToRemoveAnimated = new ArrayList<View>();
private ArrayList<View> mSnappedBackChildren = new ArrayList<View>();
@@ -108,6 +108,8 @@
private ExpandableView.OnHeightChangedListener mOnHeightChangedListener;
private boolean mNeedsAnimation;
private boolean mTopPaddingNeedsAnimation;
+ private boolean mDimmedNeedsAnimation;
+ private boolean mActivateNeedsAnimation;
private boolean mIsExpanded = true;
private boolean mChildrenUpdateRequested;
private ViewTreeObserver.OnPreDrawListener mChildrenUpdater
@@ -267,8 +269,8 @@
* modifications to {@link #mOwnScrollY} are performed to reflect it in the view layout.
*/
private void updateChildren() {
- mCurrentStackScrollState.setScrollY(mOwnScrollY);
- mStackScrollAlgorithm.getStackScrollState(mCurrentStackScrollState);
+ mAmbientState.setScrollY(mOwnScrollY);
+ mStackScrollAlgorithm.getStackScrollState(mAmbientState, mCurrentStackScrollState);
if (!isCurrentlyAnimating() && !mNeedsAnimation) {
applyCurrentState();
} else {
@@ -385,12 +387,12 @@
mDragAnimPendingChildren.remove(v);
}
mSwipedOutViews.add(v);
- mStackScrollAlgorithm.onDragFinished(v);
+ mAmbientState.onDragFinished(v);
}
@Override
public void onChildSnappedBack(View animView) {
- mStackScrollAlgorithm.onDragFinished(animView);
+ mAmbientState.onDragFinished(animView);
if (!mDragAnimPendingChildren.contains(animView)) {
mSnappedBackChildren.add(animView);
requestChildrenUpdate();
@@ -404,7 +406,7 @@
public void onBeginDrag(View v) {
setSwipingInProgress(true);
mDragAnimPendingChildren.add(v);
- mStackScrollAlgorithm.onBeginDrag(v);
+ mAmbientState.onBeginDrag(v);
requestChildrenUpdate();
mNeedsAnimation = true;
}
@@ -965,6 +967,8 @@
generateSnapBackEvents();
generateDragEvents();
generateTopPaddingEvent();
+ generateActivateEvent();
+ generateDimmedEvent();
mNeedsAnimation = false;
}
@@ -1012,6 +1016,22 @@
mTopPaddingNeedsAnimation = false;
}
+ private void generateActivateEvent() {
+ if (mActivateNeedsAnimation) {
+ mAnimationEvents.add(
+ new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_ACTIVATED_CHILD));
+ }
+ mActivateNeedsAnimation = false;
+ }
+
+ private void generateDimmedEvent() {
+ if (mDimmedNeedsAnimation) {
+ mAnimationEvents.add(
+ new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_DIMMED));
+ }
+ mDimmedNeedsAnimation = false;
+ }
+
private boolean onInterceptTouchEventScroll(MotionEvent ev) {
/*
* This method JUST determines whether we want to intercept the motion.
@@ -1177,14 +1197,12 @@
@Override
public void onHeightChanged(ExpandableView view) {
- if (mListenForHeightChanges && !isCurrentlyAnimating()) {
- updateContentHeight();
- updateScrollPositionIfNecessary();
- if (mOnHeightChangedListener != null) {
- mOnHeightChangedListener.onHeightChanged(view);
- }
- requestChildrenUpdate();
+ updateContentHeight();
+ updateScrollPositionIfNecessary();
+ if (mOnHeightChangedListener != null) {
+ mOnHeightChangedListener.onHeightChanged(view);
}
+ requestChildrenUpdate();
}
public void setOnHeightChangedListener(
@@ -1197,10 +1215,34 @@
mAnimationEvents.clear();
}
+ /**
+ * See {@link AmbientState#setDimmed}.
+ */
+ public void setDimmed(boolean dimmed, boolean animate) {
+ mAmbientState.setDimmed(dimmed);
+ if (animate) {
+ mDimmedNeedsAnimation = true;
+ mNeedsAnimation = true;
+ }
+ requestChildrenUpdate();
+ }
+
+ /**
+ * See {@link AmbientState#setActivatedChild}.
+ */
+ public void setActivatedChild(View activatedChild) {
+ mAmbientState.setActivatedChild(activatedChild);
+ mActivateNeedsAnimation = true;
+ mNeedsAnimation = true;
+ requestChildrenUpdate();
+ }
+
+ public View getActivatedChild() {
+ return mAmbientState.getActivatedChild();
+ }
+
private void applyCurrentState() {
- mListenForHeightChanges = false;
mCurrentStackScrollState.apply();
- mListenForHeightChanges = true;
if (mListener != null) {
mListener.onChildLocationsChanged(this);
}
@@ -1215,21 +1257,76 @@
static class AnimationEvent {
- static int ANIMATION_TYPE_ADD = 1;
- static int ANIMATION_TYPE_REMOVE = 2;
- static int ANIMATION_TYPE_REMOVE_SWIPED_OUT = 3;
- static int ANIMATION_TYPE_TOP_PADDING_CHANGED = 4;
- static int ANIMATION_TYPE_START_DRAG = 5;
- static int ANIMATION_TYPE_SNAP_BACK = 6;
+ static AnimationFilter[] FILTERS = new AnimationFilter[] {
+
+ // ANIMATION_TYPE_ADD
+ new AnimationFilter()
+ .animateAlpha()
+ .animateHeight()
+ .animateY()
+ .animateZ(),
+
+ // ANIMATION_TYPE_REMOVE
+ new AnimationFilter()
+ .animateAlpha()
+ .animateHeight()
+ .animateY()
+ .animateZ(),
+
+ // ANIMATION_TYPE_REMOVE_SWIPED_OUT
+ new AnimationFilter()
+ .animateAlpha()
+ .animateHeight()
+ .animateY()
+ .animateZ(),
+
+ // ANIMATION_TYPE_TOP_PADDING_CHANGED
+ new AnimationFilter()
+ .animateAlpha()
+ .animateHeight()
+ .animateY()
+ .animateDimmed()
+ .animateScale()
+ .animateZ(),
+
+ // ANIMATION_TYPE_START_DRAG
+ new AnimationFilter()
+ .animateAlpha(),
+
+ // ANIMATION_TYPE_SNAP_BACK
+ new AnimationFilter()
+ .animateAlpha(),
+
+ // ANIMATION_TYPE_ACTIVATED_CHILD
+ new AnimationFilter()
+ .animateScale()
+ .animateAlpha(),
+
+ // ANIMATION_TYPE_DIMMED
+ new AnimationFilter()
+ .animateScale()
+ .animateDimmed()
+ };
+
+ static int ANIMATION_TYPE_ADD = 0;
+ static int ANIMATION_TYPE_REMOVE = 1;
+ static int ANIMATION_TYPE_REMOVE_SWIPED_OUT = 2;
+ static int ANIMATION_TYPE_TOP_PADDING_CHANGED = 3;
+ static int ANIMATION_TYPE_START_DRAG = 4;
+ static int ANIMATION_TYPE_SNAP_BACK = 5;
+ static int ANIMATION_TYPE_ACTIVATED_CHILD = 6;
+ static int ANIMATION_TYPE_DIMMED = 7;
final long eventStartTime;
final View changingView;
final int animationType;
+ final AnimationFilter filter;
AnimationEvent(View view, int type) {
eventStartTime = AnimationUtils.currentAnimationTimeMillis();
changingView = view;
animationType = type;
+ filter = FILTERS[type];
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index f7818c0..5e4d496 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -39,6 +39,10 @@
private static final int MAX_ITEMS_IN_BOTTOM_STACK = 3;
private static final int MAX_ITEMS_IN_TOP_STACK = 3;
+ /** When a child is activated, the other cards' alpha fade to this value. */
+ private static final float ACTIVATED_INVERSE_ALPHA = 0.9f;
+ private static final float DIMMED_SCALE = 0.95f;
+
private int mPaddingBetweenElements;
private int mCollapsedSize;
private int mTopStackPeekSize;
@@ -61,7 +65,6 @@
private ExpandableView mFirstChildWhileExpanding;
private boolean mExpandedOnStart;
private int mTopStackTotalSize;
- private ArrayList<View> mDraggedViews = new ArrayList<View>();
public StackScrollAlgorithm(Context context) {
initConstants(context);
@@ -93,7 +96,7 @@
}
- public void getStackScrollState(StackScrollState resultState) {
+ public void getStackScrollState(AmbientState ambientState, StackScrollState resultState) {
// The state of the local variables are saved in an algorithmState to easily subdivide it
// into multiple phases.
StackScrollAlgorithmState algorithmState = mTempAlgorithmState;
@@ -107,7 +110,7 @@
algorithmState.scrolledPixelsTop = 0;
algorithmState.itemsInBottomStack = 0.0f;
algorithmState.partialInBottom = 0.0f;
- algorithmState.scrollY = resultState.getScrollY() + mCollapsedSize;
+ algorithmState.scrollY = ambientState.getScrollY() + mCollapsedSize;
updateVisibleChildren(resultState, algorithmState);
@@ -120,19 +123,42 @@
// Phase 3:
updateZValuesForState(resultState, algorithmState);
- handleDraggedViews(resultState, algorithmState);
+ handleDraggedViews(ambientState, resultState, algorithmState);
+ updateDimmedActivated(ambientState, resultState, algorithmState);
+ }
+
+ /**
+ * Updates the dimmed and activated states of the children.
+ */
+ private void updateDimmedActivated(AmbientState ambientState, StackScrollState resultState,
+ StackScrollAlgorithmState algorithmState) {
+ boolean dimmed = ambientState.isDimmed();
+ View activatedChild = ambientState.getActivatedChild();
+ int childCount = algorithmState.visibleChildren.size();
+ for (int i = 0; i < childCount; i++) {
+ View child = algorithmState.visibleChildren.get(i);
+ StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
+ childViewState.dimmed = dimmed;
+ childViewState.scale = !dimmed || activatedChild == child
+ ? 1.0f
+ : DIMMED_SCALE;
+ if (dimmed && activatedChild != null && child != activatedChild) {
+ childViewState.alpha *= ACTIVATED_INVERSE_ALPHA;
+ }
+ }
}
/**
* Handle the special state when views are being dragged
*/
- private void handleDraggedViews(StackScrollState resultState,
+ private void handleDraggedViews(AmbientState ambientState, StackScrollState resultState,
StackScrollAlgorithmState algorithmState) {
- for (View draggedView : mDraggedViews) {
+ ArrayList<View> draggedViews = ambientState.getDraggedViews();
+ for (View draggedView : draggedViews) {
int childIndex = algorithmState.visibleChildren.indexOf(draggedView);
if (childIndex >= 0 && childIndex < algorithmState.visibleChildren.size() - 1) {
View nextChild = algorithmState.visibleChildren.get(childIndex + 1);
- if (!mDraggedViews.contains(nextChild)) {
+ if (!draggedViews.contains(nextChild)) {
// only if the view is not dragged itself we modify its state to be fully
// visible
StackScrollState.ViewState viewState = resultState.getViewStateForView(
@@ -595,14 +621,6 @@
}
}
- public void onBeginDrag(View view) {
- mDraggedViews.add(view);
- }
-
- public void onDragFinished(View view) {
- mDraggedViews.remove(view);
- }
-
class StackScrollAlgorithmState {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 70126f5..8fc26d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -37,19 +37,10 @@
private final ViewGroup mHostView;
private Map<ExpandableView, ViewState> mStateMap;
- private int mScrollY;
private final Rect mClipRect = new Rect();
private int mBackgroundRoundedRectCornerRadius;
private final Outline mChildOutline = new Outline();
- public int getScrollY() {
- return mScrollY;
- }
-
- public void setScrollY(int scrollY) {
- this.mScrollY = scrollY;
- }
-
public StackScrollState(ViewGroup hostView) {
mHostView = hostView;
mStateMap = new HashMap<ExpandableView, ViewState>();
@@ -106,10 +97,12 @@
float alpha = child.getAlpha();
float yTranslation = child.getTranslationY();
float zTranslation = child.getTranslationZ();
+ float scale = child.getScaleX();
int height = child.getActualHeight();
float newAlpha = state.alpha;
float newYTranslation = state.yTranslation;
float newZTranslation = state.zTranslation;
+ float newScale = state.scale;
int newHeight = state.height;
boolean becomesInvisible = newAlpha == 0.0f;
if (alpha != newAlpha) {
@@ -147,11 +140,20 @@
child.setTranslationZ(newZTranslation);
}
+ // apply scale
+ if (scale != newScale) {
+ child.setScaleX(newScale);
+ child.setScaleY(newScale);
+ }
+
// apply height
if (height != newHeight) {
- child.setActualHeight(newHeight);
+ child.setActualHeight(newHeight, false /* notifyListeners */);
}
+ // apply dimming
+ child.setDimmed(state.dimmed, false /* animate */);
+
// apply clipping and shadow
float newNotificationEnd = newYTranslation + newHeight;
@@ -228,6 +230,8 @@
float zTranslation;
int height;
boolean gone;
+ float scale;
+ boolean dimmed;
/**
* The location this view is currently rendered at.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 2e700aa..695a0db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -18,7 +18,9 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.view.View;
import android.view.animation.AnimationUtils;
@@ -40,11 +42,13 @@
private static final int ANIMATION_DURATION = 360;
private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
+ private static final int TAG_ANIMATOR_SCALE = R.id.scale_animator_tag;
private static final int TAG_ANIMATOR_ALPHA = R.id.alpha_animator_tag;
private static final int TAG_ANIMATOR_HEIGHT = R.id.height_animator_tag;
private static final int TAG_ANIMATOR_TOP_INSET = R.id.top_inset_animator_tag;
private static final int TAG_END_TRANSLATION_Y = R.id.translation_y_animator_end_value_tag;
private static final int TAG_END_TRANSLATION_Z = R.id.translation_z_animator_end_value_tag;
+ private static final int TAG_END_SCALE = R.id.scale_animator_end_value_tag;
private static final int TAG_END_ALPHA = R.id.alpha_animator_end_value_tag;
private static final int TAG_END_HEIGHT = R.id.height_animator_end_value_tag;
private static final int TAG_END_TOP_INSET = R.id.top_inset_animator_end_value_tag;
@@ -58,6 +62,7 @@
private Set<Animator> mAnimatorSet = new HashSet<Animator>();
private Stack<AnimatorListenerAdapter> mAnimationListenerPool
= new Stack<AnimatorListenerAdapter>();
+ private AnimationFilter mAnimationFilter = new AnimationFilter();
public StackStateAnimator(NotificationStackScrollLayout hostLayout) {
mHostLayout = hostLayout;
@@ -75,8 +80,8 @@
processAnimationEvents(mAnimationEvents, finalState);
- boolean hasNewEvents = !mNewEvents.isEmpty();
int childCount = mHostLayout.getChildCount();
+ mAnimationFilter.applyCombination(mNewEvents);
for (int i = 0; i < childCount; i++) {
final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
StackScrollState.ViewState viewState = finalState.getViewStateForView(child);
@@ -84,7 +89,7 @@
continue;
}
- startAnimations(child, viewState, hasNewEvents);
+ startAnimations(child, viewState);
child.setClipBounds(null);
}
@@ -97,8 +102,7 @@
/**
* Start an animation to the given viewState
*/
- private void startAnimations(final ExpandableView child, StackScrollState.ViewState viewState,
- boolean hasNewEvents) {
+ private void startAnimations(final ExpandableView child, StackScrollState.ViewState viewState) {
int childVisibility = child.getVisibility();
boolean wasVisible = childVisibility == View.VISIBLE;
final float alpha = viewState.alpha;
@@ -107,33 +111,40 @@
}
// start translationY animation
if (child.getTranslationY() != viewState.yTranslation) {
- startYTranslationAnimation(child, viewState, hasNewEvents);
+ startYTranslationAnimation(child, viewState);
}
// start translationZ animation
if (child.getTranslationZ() != viewState.zTranslation) {
- startZTranslationAnimation(child, viewState, hasNewEvents);
+ startZTranslationAnimation(child, viewState);
+ }
+ // start scale animation
+ if (child.getScaleX() != viewState.scale) {
+ startScaleAnimation(child, viewState);
}
// start alpha animation
if (alpha != child.getAlpha()) {
- startAlphaAnimation(child, viewState, hasNewEvents);
+ startAlphaAnimation(child, viewState);
}
// start height animation
if (viewState.height != child.getActualHeight()) {
- startHeightAnimation(child, viewState, hasNewEvents);
+ startHeightAnimation(child, viewState);
}
+ // start dimmed animation
+ child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed);
}
private void startHeightAnimation(final ExpandableView child,
- StackScrollState.ViewState viewState, boolean hasNewEvents) {
- Integer previousEndValue = getChildTag(child,TAG_END_HEIGHT);
+ StackScrollState.ViewState viewState) {
+ Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT);
if (previousEndValue != null && previousEndValue == viewState.height) {
return;
}
ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_HEIGHT);
- long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator, hasNewEvents);
+ long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator,
+ mAnimationFilter.animateHeight);
if (newDuration <= 0) {
// no new animation needed, let's just apply the value
- child.setActualHeight(viewState.height);
+ child.setActualHeight(viewState.height, false /* notifyListeners */);
if (previousAnimator != null && !isRunning()) {
onAnimationFinished();
}
@@ -144,7 +155,8 @@
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
- child.setActualHeight((int) animation.getAnimatedValue());
+ child.setActualHeight((int) animation.getAnimatedValue(),
+ false /* notifyListeners */);
}
});
animator.setInterpolator(mFastOutSlowInInterpolator);
@@ -164,14 +176,15 @@
}
private void startAlphaAnimation(final ExpandableView child,
- final StackScrollState.ViewState viewState, boolean hasNewEvents) {
+ final StackScrollState.ViewState viewState) {
final float endAlpha = viewState.alpha;
Float previousEndValue = getChildTag(child,TAG_END_ALPHA);
if (previousEndValue != null && previousEndValue == endAlpha) {
return;
}
ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_ALPHA);
- long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator, hasNewEvents);
+ long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator,
+ mAnimationFilter.animateAlpha);
if (newDuration <= 0) {
// no new animation needed, let's just apply the value
child.setAlpha(endAlpha);
@@ -228,13 +241,14 @@
}
private void startZTranslationAnimation(final ExpandableView child,
- final StackScrollState.ViewState viewState, boolean hasNewEvents) {
+ final StackScrollState.ViewState viewState) {
Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z);
if (previousEndValue != null && previousEndValue == viewState.zTranslation) {
return;
}
ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Z);
- long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator, hasNewEvents);
+ long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator,
+ mAnimationFilter.animateZ);
if (newDuration <= 0) {
// no new animation needed, let's just apply the value
child.setTranslationZ(viewState.zTranslation);
@@ -264,13 +278,14 @@
}
private void startYTranslationAnimation(final ExpandableView child,
- StackScrollState.ViewState viewState, boolean hasNewEvents) {
+ StackScrollState.ViewState viewState) {
Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y);
if (previousEndValue != null && previousEndValue == viewState.yTranslation) {
return;
}
ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y);
- long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator, hasNewEvents);
+ long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator,
+ mAnimationFilter.animateY);
if (newDuration <= 0) {
// no new animation needed, let's just apply the value
child.setTranslationY(viewState.yTranslation);
@@ -298,6 +313,46 @@
child.setTag(TAG_END_TRANSLATION_Y, viewState.yTranslation);
}
+ private void startScaleAnimation(final ExpandableView child,
+ StackScrollState.ViewState viewState) {
+ Float previousEndValue = getChildTag(child, TAG_END_SCALE);
+ if (previousEndValue != null && previousEndValue == viewState.scale) {
+ return;
+ }
+ ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_SCALE);
+ long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator,
+ mAnimationFilter.animateScale);
+ if (newDuration <= 0) {
+ // no new animation needed, let's just apply the value
+ child.setScaleX(viewState.scale);
+ child.setScaleY(viewState.scale);
+ if (previousAnimator != null && !isRunning()) {
+ onAnimationFinished();
+ }
+ return;
+ }
+
+ PropertyValuesHolder holderX =
+ PropertyValuesHolder.ofFloat(View.SCALE_X, child.getScaleX(), viewState.scale);
+ PropertyValuesHolder holderY =
+ PropertyValuesHolder.ofFloat(View.SCALE_Y, child.getScaleY(), viewState.scale);
+ ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(child, holderX, holderY);
+ animator.setInterpolator(mFastOutSlowInInterpolator);
+ animator.setDuration(newDuration);
+ animator.addListener(getGlobalAnimationFinishedListener());
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_SCALE, null);
+ child.setTag(TAG_END_SCALE, null);
+ }
+ });
+ startInstantly(animator);
+ child.setTag(TAG_ANIMATOR_SCALE, animator);
+ child.setTag(TAG_END_SCALE, viewState.scale);
+ }
+
/**
* Start an animator instantly instead of waiting on the next synchronization frame
*/
@@ -349,21 +404,22 @@
* Cancel the previous animator and get the duration of the new animation.
*
* @param previousAnimator the animator which was running before
- * @param hasNewEvents indicating whether new events came in in this animation
+ * @param newAnimationNeeded indicating whether a new animation should be started for this
+ * property
* @return the new duration
*/
private long cancelAnimatorAndGetNewDuration(ValueAnimator previousAnimator,
- boolean hasNewEvents) {
+ boolean newAnimationNeeded) {
long newDuration = ANIMATION_DURATION;
if (previousAnimator != null) {
- if (!hasNewEvents) {
+ if (!newAnimationNeeded) {
// This is only an update, no new event came in. lets just take the remaining
// duration as the new duration
newDuration = previousAnimator.getDuration()
- previousAnimator.getCurrentPlayTime();
}
previousAnimator.cancel();
- } else if (!hasNewEvents){
+ } else if (!newAnimationNeeded){
newDuration = 0;
}
return newDuration;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index d6a8885..9006c9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -150,4 +150,11 @@
protected void refreshLayout(int layoutDirection) {
}
+ @Override
+ public void onActivated(View view) {
+ }
+
+ @Override
+ public void onActivationReset(View view) {
+ }
}