diff options
author | Jorim Jaggi <jjaggi@google.com> | 2014-05-08 01:13:30 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-05-08 01:13:31 +0000 |
commit | 8a2a5fa0d1e399b45ee45cc754f0680cf51be5a4 (patch) | |
tree | b6fefc8a072d9a31f79a74c5a5b7392aed3c71d2 /packages | |
parent | 607562a7660a9b0eec2a8eb52388bdc7604747d2 (diff) | |
parent | d552d9d8e964c102e6832610be46cf2c041e8829 (diff) | |
download | frameworks_base-8a2a5fa0d1e399b45ee45cc754f0680cf51be5a4.zip frameworks_base-8a2a5fa0d1e399b45ee45cc754f0680cf51be5a4.tar.gz frameworks_base-8a2a5fa0d1e399b45ee45cc754f0680cf51be5a4.tar.bz2 |
Merge "Introduce AmbientState for StackScroller."
Diffstat (limited to 'packages')
18 files changed, 471 insertions, 338 deletions
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 @@ import com.android.internal.R; 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 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mActivated = false; } if (mOnActivatedListener != null) { - mOnActivatedListener.onReset(this); + mOnActivatedListener.onActivationReset(this); } removeCallbacks(mTapTimeoutRunnable); } @@ -189,12 +190,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView && 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 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView } 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 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView } @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 abstract class ActivatableNotificationView extends ExpandableOutlineView 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 @@ public abstract class BaseStatusBar extends SystemUI implements entry.row.setSystemExpanded(top); } } - entry.row.setDimmed(onKeyguard, false /* fade */); boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification); if (onKeyguard && (visibleNotifications >= maxKeyguardNotifications || !showOnKeyguard)) { @@ -1087,48 +1086,11 @@ public abstract class BaseStatusBar extends SystemUI implements 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 @@ public class DragDownHelper implements Gefingerpoken { } else { if (mDraggedFarEnough) { mDraggedFarEnough = false; - mOnDragDownListener.onReset(); + mOnDragDownListener.onDragDownReset(); } } return true; @@ -188,7 +188,7 @@ public class DragDownHelper implements Gefingerpoken { cancelExpansion(mStartingChild); } mDraggingDown = false; - mOnDragDownListener.onReset(); + mOnDragDownListener.onDragDownReset(); } private ExpandableView findView(float x, float y) { @@ -200,7 +200,7 @@ public class DragDownHelper implements Gefingerpoken { 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 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { 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 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { super.onFinishInflate(); mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic); mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded); - - mActivator = new NotificationActivator(this, this); } @Override @@ -208,23 +205,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { 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 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { } @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 @@ public abstract class ExpandableOutlineView extends ExpandableView { } @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 @@ public abstract class ExpandableView extends FrameLayout { /** * 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 @@ public abstract class ExpandableView extends FrameLayout { } /** + * 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 @@ public class NotificationContentView extends ExpandableView { } @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 @@ import com.android.systemui.R; 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 @@ public class NotificationOverflowContainer extends ActivatableNotificationView { 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 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mSettingsContainer.setKeyguardShowing(false); } + updateStackScrollerState(); updatePublicMode(); updateRowStates(); checkBarModes(); @@ -2797,6 +2798,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, 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 class PhoneStatusBar extends BaseStatusBar implements DemoMode, public void onActivated(View view) { userActivity(); mKeyguardIndicationTextView.switchIndication(R.string.notification_tap_again); - super.onActivated(view); + mStackScroller.setActivatedChild(view); } /** @@ -2862,9 +2867,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } @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 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } @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 @@ public class NotificationStackScrollLayout extends ViewGroup 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 @@ public class NotificationStackScrollLayout extends ViewGroup * 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 @@ public class NotificationStackScrollLayout extends ViewGroup 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 @@ public class NotificationStackScrollLayout extends ViewGroup * 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 @@ public class NotificationStackScrollLayout extends ViewGroup 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 class NotificationStackScrollLayout extends ViewGroup public void onBeginDrag(View v) { setSwipingInProgress(true); mDragAnimPendingChildren.add(v); - mStackScrollAlgorithm.onBeginDrag(v); + mAmbientState.onBeginDrag(v); requestChildrenUpdate(); mNeedsAnimation = true; } @@ -965,6 +967,8 @@ public class NotificationStackScrollLayout extends ViewGroup generateSnapBackEvents(); generateDragEvents(); generateTopPaddingEvent(); + generateActivateEvent(); + generateDimmedEvent(); mNeedsAnimation = false; } @@ -1012,6 +1016,22 @@ public class NotificationStackScrollLayout extends ViewGroup 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 @@ public class NotificationStackScrollLayout extends ViewGroup @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 @@ public class NotificationStackScrollLayout extends ViewGroup 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 @@ public class NotificationStackScrollLayout extends ViewGroup 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 @@ public class StackScrollAlgorithm { 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 @@ public class StackScrollAlgorithm { 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 class StackScrollAlgorithm { } - 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 @@ public class StackScrollAlgorithm { 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 @@ public class StackScrollAlgorithm { // 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 class StackScrollAlgorithm { } } - 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 @@ public class StackScrollState { 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 @@ public class StackScrollState { 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 @@ public class StackScrollState { 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 @@ public class StackScrollState { 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 @@ package com.android.systemui.statusbar.stack; 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 @@ public class StackStateAnimator { 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 @@ public class StackStateAnimator { 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 @@ public class StackStateAnimator { 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 @@ public class StackStateAnimator { continue; } - startAnimations(child, viewState, hasNewEvents); + startAnimations(child, viewState); child.setClipBounds(null); } @@ -97,8 +102,7 @@ public class StackStateAnimator { /** * 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 @@ public class StackStateAnimator { } // 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 @@ public class StackStateAnimator { 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 @@ public class StackStateAnimator { } 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 @@ public class StackStateAnimator { } 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 @@ public class StackStateAnimator { } 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 @@ public class StackStateAnimator { 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 @@ public class StackStateAnimator { * 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 @@ public class TvStatusBar extends BaseStatusBar { protected void refreshLayout(int layoutDirection) { } + @Override + public void onActivated(View view) { + } + + @Override + public void onActivationReset(View view) { + } } |