diff options
8 files changed, 297 insertions, 30 deletions
diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml index 79b03ce03fc8..5d2f33095199 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml @@ -14,7 +14,8 @@ ~ limitations under the License --> -<FrameLayout +<!-- Extends FrameLayout --> +<com.android.systemui.statusbar.NotificationOverflowContainer xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -48,4 +49,4 @@ android:layout_height="wrap_content" /> </com.android.systemui.statusbar.LatestItemView> -</FrameLayout> +</com.android.systemui.statusbar.NotificationOverflowContainer> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index a50b40f05288..e7959ab858f1 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -83,7 +83,7 @@ <dimen name="notification_mid_height">128dp</dimen> <!-- Height of a small notification in the status bar plus glow, padding, etc --> - <dimen name="notification_row_min_height">70dp</dimen> + <dimen name="notification_row_min_height">68dp</dimen> <!-- Height of a large notification in the status bar plus glow, padding, etc --> <dimen name="notification_row_max_height">260dp</dimen> @@ -98,7 +98,7 @@ <dimen name="status_bar_icon_padding">0dp</dimen> <!-- half the distance between notifications in the panel --> - <dimen name="notification_divider_height">3dp</dimen> + <dimen name="notification_divider_height">2dp</dimen> <!-- Notification drawer tuning parameters (phone UI) --> <!-- Initial velocity of the shade when expanding on its own --> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index d48637d76a61..2ea5addd2986 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -83,7 +83,7 @@ import java.util.ArrayList; import java.util.Locale; public abstract class BaseStatusBar extends SystemUI implements - CommandQueue.Callbacks { + CommandQueue.Callbacks, LatestItemView.OnActivatedListener { public static final String TAG = "StatusBar"; public static final boolean DEBUG = false; public static final boolean MULTIUSER_DEBUG = false; @@ -169,8 +169,7 @@ public abstract class BaseStatusBar extends SystemUI implements protected int mZenMode; protected boolean mOnKeyguard; - protected View mKeyguardIconOverflowContainer; - protected NotificationOverflowIconsView mOverflowIconsView; + protected NotificationOverflowContainer mKeyguardIconOverflowContainer; public boolean isDeviceProvisioned() { return mDeviceProvisioned; @@ -882,6 +881,7 @@ public abstract class BaseStatusBar extends SystemUI implements } entry.row = row; entry.row.setHeightRange(mRowMinHeight, mRowMaxHeight); + entry.row.setOnActivatedListener(this); entry.content = content; entry.expanded = contentViewLocal; entry.expandedPublic = publicViewLocal; @@ -1067,7 +1067,7 @@ public abstract class BaseStatusBar extends SystemUI implements */ protected void updateRowStates() { int maxKeyguardNotifications = getMaxKeyguardNotifications(); - mOverflowIconsView.removeAllViews(); + mKeyguardIconOverflowContainer.getIconsView().removeAllViews(); int n = mNotificationData.size(); int visibleNotifications = 0; for (int i = n-1; i >= 0; i--) { @@ -1087,7 +1087,7 @@ public abstract class BaseStatusBar extends SystemUI implements || !showOnKeyguard)) { entry.row.setVisibility(View.GONE); if (showOnKeyguard) { - mOverflowIconsView.addNotification(entry); + mKeyguardIconOverflowContainer.getIconsView().addNotification(entry); } } else { entry.row.setVisibility(View.VISIBLE); @@ -1095,13 +1095,49 @@ public abstract class BaseStatusBar extends SystemUI implements } } - if (mOnKeyguard && mOverflowIconsView.getChildCount() > 0) { + if (mOnKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) { mKeyguardIconOverflowContainer.setVisibility(View.VISIBLE); } 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/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index a9fda63d3346..fdf4dbf51fe4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -25,7 +25,8 @@ import android.widget.FrameLayout; import com.android.internal.widget.SizeAdaptiveLayout; import com.android.systemui.R; -public class ExpandableNotificationRow extends FrameLayout { +public class ExpandableNotificationRow extends FrameLayout + implements LatestItemView.OnActivatedListener { private int mRowMinHeight; private int mRowMaxHeight; @@ -51,6 +52,8 @@ public class ExpandableNotificationRow extends FrameLayout { private SizeAdaptiveLayout mPrivateLayout; private int mMaxExpandHeight; private boolean mMaxHeightNeedsUpdate; + private NotificationActivator mActivator; + private LatestItemView.OnActivatedListener mOnActivatedListener; public ExpandableNotificationRow(Context context, AttributeSet attrs) { super(context, attrs); @@ -62,8 +65,10 @@ public class ExpandableNotificationRow extends FrameLayout { mPublicLayout = (SizeAdaptiveLayout) findViewById(R.id.expandedPublic); mPrivateLayout = (SizeAdaptiveLayout) findViewById(R.id.expanded); mLatestItemView = (LatestItemView) findViewById(R.id.container); - } + mActivator = new NotificationActivator(this); + mLatestItemView.setOnActivatedListener(this); + } public void setHeightRange(int rowMinHeight, int rowMaxHeight) { mRowMinHeight = rowMinHeight; @@ -202,6 +207,7 @@ public class ExpandableNotificationRow extends FrameLayout { */ public void setDimmed(boolean dimmed) { mLatestItemView.setDimmed(dimmed); + mActivator.setDimmed(dimmed); } public int getMaxExpandHeight() { @@ -220,6 +226,28 @@ public class ExpandableNotificationRow extends FrameLayout { mLatestItemView.setLocked(locked); } + public void setOnActivatedListener(LatestItemView.OnActivatedListener listener) { + mOnActivatedListener = listener; + } + + public NotificationActivator getActivator() { + return mActivator; + } + + @Override + public void onActivated(View view) { + if (mOnActivatedListener != null) { + mOnActivatedListener.onActivated(this); + } + } + + @Override + public void onReset(View view) { + if (mOnActivatedListener != null) { + mOnActivatedListener.onReset(this); + } + } + /** * Sets the resource id for the background of this notification. * diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java b/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java index 74d837dc2e80..5e900848f2b7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java @@ -17,7 +17,6 @@ package com.android.systemui.statusbar; import android.content.Context; -import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; @@ -46,7 +45,8 @@ public class LatestItemView extends FrameLayout { private float mDownX; private float mDownY; private final float mTouchSlop; - private boolean mHotspotActive; + + private OnActivatedListener mOnActivatedListener; public LatestItemView(Context context, AttributeSet attrs) { super(context, attrs); @@ -90,14 +90,17 @@ public class LatestItemView extends FrameLayout { private boolean handleTouchEventLocked(MotionEvent event) { int action = event.getActionMasked(); - Drawable background = getBackground(); switch (action) { case MotionEvent.ACTION_DOWN: mDownX = event.getX(); mDownY = event.getY(); - if (!mActivated) { - background.setHotspot(0, event.getX(), event.getY()); - mHotspotActive = true; + + // Call the listener tentatively directly, even if we don't know whether the user + // will stay within the touch slop, as the listener is implemented as a scale + // animation, which is cancellable without jarring effects when swiping away + // notifications. + if (mOnActivatedListener != null) { + mOnActivatedListener.onActivated(this); } break; case MotionEvent.ACTION_MOVE: @@ -109,7 +112,7 @@ public class LatestItemView extends FrameLayout { case MotionEvent.ACTION_UP: if (isWithinTouchSlop(event)) { if (!mActivated) { - mActivated = true; + makeActive(event.getX(), event.getY()); postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS); } else { performClick(); @@ -128,17 +131,24 @@ public class LatestItemView extends FrameLayout { return true; } + private void makeActive(float x, float y) { + getBackground().setHotspot(0, x, y); + mActivated = true; + } + /** * Cancels the hotspot and makes the notification inactive. */ private void makeInactive() { - if (mHotspotActive) { + if (mActivated) { // Make sure that we clear the hotspot from the center. - getBackground().setHotspot(0, getWidth()/2, getHeight()/2); + getBackground().setHotspot(0, getWidth() / 2, getHeight() / 2); getBackground().removeHotspot(0); - mHotspotActive = false; + mActivated = false; + } + if (mOnActivatedListener != null) { + mOnActivatedListener.onReset(this); } - mActivated = false; removeCallbacks(mTapTimeoutRunnable); } @@ -180,4 +190,13 @@ public class LatestItemView extends FrameLayout { private void updateBackgroundResource() { setBackgroundResource(mDimmed ? mDimmedBgResId : mBgResId); } + + public void setOnActivatedListener(OnActivatedListener onActivatedListener) { + mOnActivatedListener = onActivatedListener; + } + + public interface OnActivatedListener { + void onActivated(View view); + void onReset(View view); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java new file mode 100644 index 000000000000..620e4573acd1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java @@ -0,0 +1,87 @@ +/* + * 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 { + + private static final int ANIMATION_LENGTH_MS = 220; + private static final float INVERSE_ALPHA = 0.9f; + private static final float DIMMED_SCALE = 0.95f; + + private final View mTargetView; + + private final Interpolator mFastOutSlowInInterpolator; + private final Interpolator mLinearOutSlowInInterpolator; + private final int mTranslationZ; + + public NotificationActivator(View targetView) { + mTargetView = targetView; + 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() { + mTargetView.animate().withLayer().alpha(INVERSE_ALPHA); + } + + public void activate() { + mTargetView.animate() + .setInterpolator(mLinearOutSlowInInterpolator) + .scaleX(1) + .scaleY(1) + .translationZBy(mTranslationZ); + } + + public void reset() { + mTargetView.animate() + .setInterpolator(mFastOutSlowInInterpolator) + .scaleX(DIMMED_SCALE) + .scaleY(DIMMED_SCALE) + .translationZBy(-mTranslationZ); + if (mTargetView.getAlpha() != 1.0f) { + mTargetView.animate().withLayer().alpha(1); + } + } + + public void setDimmed(boolean dimmed) { + if (dimmed) { + mTargetView.setScaleX(DIMMED_SCALE); + mTargetView.setScaleY(DIMMED_SCALE); + } else { + mTargetView.setScaleX(1); + mTargetView.setScaleY(1); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java new file mode 100644 index 000000000000..be58dadec95e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.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; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.TextView; + +import com.android.systemui.R; + +/** + * Container view for overflowing notification icons on Keyguard. + */ +public class NotificationOverflowContainer extends FrameLayout + implements LatestItemView.OnActivatedListener { + + private NotificationOverflowIconsView mIconsView; + private LatestItemView.OnActivatedListener mOnActivatedListener; + private NotificationActivator mActivator; + + public NotificationOverflowContainer(Context context) { + super(context); + } + + public NotificationOverflowContainer(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public NotificationOverflowContainer(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public NotificationOverflowContainer(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mIconsView = (NotificationOverflowIconsView) findViewById(R.id.overflow_icons_view); + mIconsView.setMoreText((TextView) findViewById(R.id.more_text)); + + LatestItemView latestItemView = (LatestItemView) findViewById(R.id.container); + mActivator = new NotificationActivator(this); + mActivator.setDimmed(true); + latestItemView.setOnActivatedListener(this); + latestItemView.setLocked(true); + } + + public NotificationOverflowIconsView getIconsView() { + return mIconsView; + } + + public void setOnActivatedListener(LatestItemView.OnActivatedListener onActivatedListener) { + mOnActivatedListener = onActivatedListener; + } + + @Override + public void onActivated(View view) { + if (mOnActivatedListener != null) { + mOnActivatedListener.onActivated(this); + } + } + + @Override + public void onReset(View view) { + if (mOnActivatedListener != null) { + mOnActivatedListener.onReset(this); + } + } + + 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 ec9f3ab2ba3b..1d01f91f32eb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -99,6 +99,7 @@ import com.android.systemui.statusbar.InterceptedNotifications; import com.android.systemui.statusbar.LatestItemView; import com.android.systemui.statusbar.NotificationData; import com.android.systemui.statusbar.NotificationData.Entry; +import com.android.systemui.statusbar.NotificationOverflowContainer; import com.android.systemui.statusbar.NotificationOverflowIconsView; import com.android.systemui.statusbar.SignalClusterView; import com.android.systemui.statusbar.StatusBarIconView; @@ -519,13 +520,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mStackScroller.setLongPressListener(getNotificationLongClicker()); mStackScroller.setChildLocationsChangedListener(mOnChildLocationsChangedListener); - mKeyguardIconOverflowContainer = LayoutInflater.from(mContext).inflate( - R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false); - ((LatestItemView) mKeyguardIconOverflowContainer.findViewById(R.id.container)).setLocked(true); - mOverflowIconsView = (NotificationOverflowIconsView) mKeyguardIconOverflowContainer.findViewById( - R.id.overflow_icons_view); - mOverflowIconsView.setMoreText( - (TextView) mKeyguardIconOverflowContainer.findViewById(R.id.more_text)); + mKeyguardIconOverflowContainer = + (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate( + R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false); + mKeyguardIconOverflowContainer.setOnActivatedListener(this); mStackScroller.addView(mKeyguardIconOverflowContainer); mExpandedContents = mStackScroller; @@ -2879,6 +2877,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } @Override + public void onActivated(View view) { + userActivity(); + super.onActivated(view); + } + + @Override protected int getMaxKeyguardNotifications() { return mKeyguardMaxNotificationCount; } |