From 5cf1d0589a0045ee5f01802975f394847e891215 Mon Sep 17 00:00:00 2001 From: Selim Cinek Date: Thu, 1 Jun 2017 17:36:46 -0700 Subject: [PATCH] Fixed an issue where the qs panel wasn't properly placed The QS panel should only be placed below the notifications if it has notifications above the shelf. This ensures that all animations including icons are appearing in the right place. Test: runtest -x packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java Test: runtest -x packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java Fixes: 35305470 Change-Id: I97fb0c76ed69b7638ce83a7c06856d87bf6bf65f --- .../statusbar/ExpandableNotificationRow.java | 26 ++++++ .../systemui/statusbar/NotificationShelf.java | 3 +- .../AboveShelfChangedListener.java | 28 ++++++ .../notification/AboveShelfObserver.java | 73 ++++++++++++++++ .../NotificationsQuickSettingsContainer.java | 28 +++--- .../systemui/statusbar/phone/StatusBar.java | 7 ++ .../statusbar/policy/HeadsUpManager.java | 5 +- .../statusbar/stack/AmbientState.java | 9 ++ .../stack/NotificationStackScrollLayout.java | 12 ++- .../ExpandableNotificationRowTest.java | 37 ++++++++ .../statusbar/NotificationTestHelper.java | 8 ++ .../notification/AboveShelfObserverTest.java | 86 +++++++++++++++++++ 12 files changed, 301 insertions(+), 21 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/AboveShelfChangedListener.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/AboveShelfObserver.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index c445c0dd77877..bf6db23d83661 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -63,6 +63,8 @@ import com.android.systemui.plugins.PluginManager; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem; import com.android.systemui.statusbar.NotificationGuts.GutsContent; +import com.android.systemui.statusbar.notification.AboveShelfChangedListener; +import com.android.systemui.statusbar.notification.AboveShelfObserver; import com.android.systemui.statusbar.notification.HybridNotificationView; import com.android.systemui.statusbar.notification.NotificationInflater; import com.android.systemui.statusbar.notification.NotificationUtils; @@ -162,6 +164,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private boolean mIsSystemChildExpanded; private boolean mIsPinned; private FalsingManager mFalsingManager; + private AboveShelfChangedListener mAboveShelfChangedListener; private HeadsUpManager mHeadsUpManager; private boolean mJustClicked; @@ -388,6 +391,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView expandedIcon.setStaticDrawableColor(color); } + public void setAboveShelfChangedListener(AboveShelfChangedListener aboveShelfChangedListener) { + mAboveShelfChangedListener = aboveShelfChangedListener; + } + @Override public boolean isDimmable() { if (!getShowingLayout().isDimmable()) { @@ -442,6 +449,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } public void setHeadsUp(boolean isHeadsUp) { + boolean wasAboveShelf = isAboveShelf(); int intrinsicBefore = getIntrinsicHeight(); mIsHeadsUp = isHeadsUp; mPrivateLayout.setHeadsUp(isHeadsUp); @@ -454,6 +462,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } if (isHeadsUp) { setAboveShelf(true); + } else if (isAboveShelf() != wasAboveShelf) { + mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf); } } @@ -634,6 +644,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView */ public void setPinned(boolean pinned) { int intrinsicHeight = getIntrinsicHeight(); + boolean wasAboveShelf = isAboveShelf(); mIsPinned = pinned; if (intrinsicHeight != getIntrinsicHeight()) { notifyHeightChanged(false /* needsAnimation */); @@ -645,6 +656,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView setUserExpanded(true); } setChronometerRunning(mLastChronometerRunning); + if (isAboveShelf() != wasAboveShelf) { + mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf); + } } public boolean isPinned() { @@ -993,8 +1007,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) { + boolean wasAboveShelf = isAboveShelf(); mHeadsupDisappearRunning = headsUpAnimatingAway; mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway); + if (isAboveShelf() != wasAboveShelf) { + mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf); + } } /** @@ -1555,6 +1573,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView */ public void setOnKeyguard(boolean onKeyguard) { if (onKeyguard != mOnKeyguard) { + boolean wasAboveShelf = isAboveShelf(); final boolean wasExpanded = isExpanded(); mOnKeyguard = onKeyguard; onExpansionChanged(false /* userAction */, wasExpanded); @@ -1564,6 +1583,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } notifyHeightChanged(false /* needsAnimation */); } + if (isAboveShelf() != wasAboveShelf) { + mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf); + } } } @@ -2214,7 +2236,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } public void setAboveShelf(boolean aboveShelf) { + boolean wasAboveShelf = isAboveShelf(); mAboveShelf = aboveShelf; + if (isAboveShelf() != wasAboveShelf) { + mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf); + } } public static class NotificationViewState extends ExpandableViewState { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 3f1f82c6cd52a..d2c0f64b5c9b5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -179,7 +179,8 @@ public class NotificationShelf extends ActivatableNotificationView implements mShelfState.notGoneIndex = Math.min(mShelfState.notGoneIndex, mNotGoneIndex); } mShelfState.hasItemsInStableShelf = lastViewState.inShelf; - mShelfState.hidden = !mAmbientState.isShadeExpanded(); + mShelfState.hidden = !mAmbientState.isShadeExpanded() + || mAmbientState.isQsCustomizerShowing(); mShelfState.maxShelfEnd = maxShelfEnd; } else { mShelfState.hidden = true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AboveShelfChangedListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AboveShelfChangedListener.java new file mode 100644 index 0000000000000..07baedce02765 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AboveShelfChangedListener.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2017 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.notification; + +/** + * A listener for when the above shelf state of notification changes + */ +public interface AboveShelfChangedListener { + + /** + * Notifies a listener that the above shelf state changed + */ + void onAboveShelfStateChanged(boolean aboveShelf); +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AboveShelfObserver.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AboveShelfObserver.java new file mode 100644 index 0000000000000..f10d2d7f05c20 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AboveShelfObserver.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2017 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.notification; + +import android.view.View; +import android.view.ViewGroup; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.statusbar.ExpandableNotificationRow; + +/** + * An observer that listens to the above shelf state and can notify listeners + */ +public class AboveShelfObserver implements AboveShelfChangedListener { + + private final ViewGroup mHostLayout; + private boolean mHasViewsAboveShelf = false; + private HasViewAboveShelfChangedListener mListener; + + public AboveShelfObserver(ViewGroup hostLayout) { + mHostLayout = hostLayout; + } + + public void setListener(HasViewAboveShelfChangedListener listener) { + mListener = listener; + } + + @Override + public void onAboveShelfStateChanged(boolean aboveShelf) { + boolean hasViewsAboveShelf = aboveShelf; + if (!hasViewsAboveShelf && mHostLayout != null) { + int n = mHostLayout.getChildCount(); + for (int i = 0; i < n; i++) { + View child = mHostLayout.getChildAt(i); + if (child instanceof ExpandableNotificationRow) { + if (((ExpandableNotificationRow) child).isAboveShelf()) { + hasViewsAboveShelf = true; + break; + } + } + } + } + if (mHasViewsAboveShelf != hasViewsAboveShelf) { + mHasViewsAboveShelf = hasViewsAboveShelf; + if (mListener != null) { + mListener.onHasViewsAboveShelfChanged(hasViewsAboveShelf); + } + } + } + + @VisibleForTesting + boolean hasViewsAboveShelf() { + return mHasViewsAboveShelf; + } + + public interface HasViewAboveShelfChangedListener { + void onHasViewsAboveShelfChanged(boolean hasViewsAboveShelf); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java index 1952a21057caf..76cc0ff2a2e1f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java @@ -34,18 +34,19 @@ import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.fragments.FragmentHostManager.FragmentListener; import com.android.systemui.plugins.qs.QS; import com.android.systemui.statusbar.NotificationData.Entry; -import com.android.systemui.statusbar.policy.HeadsUpManager; -import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; +import com.android.systemui.statusbar.notification.AboveShelfObserver; +import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; /** * The container with notification stack scroller and quick settings inside. */ public class NotificationsQuickSettingsContainer extends FrameLayout - implements OnInflateListener, FragmentListener, OnHeadsUpChangedListener { + implements OnInflateListener, FragmentListener, + AboveShelfObserver.HasViewAboveShelfChangedListener { private FrameLayout mQsFrame; private View mUserSwitcher; - private View mStackScroller; + private NotificationStackScrollLayout mStackScroller; private View mKeyguardStatusBar; private boolean mInflated; private boolean mQsExpanded; @@ -53,8 +54,7 @@ public class NotificationsQuickSettingsContainer extends FrameLayout private int mBottomPadding; private int mStackScrollerMargin; - private boolean mHeadsUp; - private HeadsUpManager mHeadsUpManager; + private boolean mHasViewsAboveShelf; public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) { super(context, attrs); @@ -76,16 +76,12 @@ public class NotificationsQuickSettingsContainer extends FrameLayout protected void onAttachedToWindow() { super.onAttachedToWindow(); FragmentHostManager.get(this).addTagListener(QS.TAG, this); - mHeadsUpManager = SysUiServiceProvider.getComponent(getContext(), StatusBar.class) - .mHeadsUpManager; - mHeadsUpManager.addListener(this); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); FragmentHostManager.get(this).removeTagListener(QS.TAG, this); - mHeadsUpManager.removeListener(this); } @Override @@ -116,7 +112,7 @@ public class NotificationsQuickSettingsContainer extends FrameLayout boolean userSwitcherVisible = mInflated && mUserSwitcher.getVisibility() == View.VISIBLE; boolean statusBarVisible = mKeyguardStatusBar.getVisibility() == View.VISIBLE; - final boolean qsBottom = mHeadsUp; + final boolean qsBottom = mHasViewsAboveShelf; View stackQsTop = qsBottom ? mStackScroller : mQsFrame; View stackQsBottom = !qsBottom ? mStackScroller : mQsFrame; // Invert the order of the scroll view and user switcher such that the notifications receive @@ -183,7 +179,7 @@ public class NotificationsQuickSettingsContainer extends FrameLayout setPadding(0, 0, 0, mBottomPadding); setBottomMargin(mStackScroller, mStackScrollerMargin); } - + mStackScroller.setQsCustomizerShowing(isShowing); } private void setBottomMargin(View v, int bottomMargin) { @@ -193,12 +189,8 @@ public class NotificationsQuickSettingsContainer extends FrameLayout } @Override - public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) { - boolean hasHeadsUp = mHeadsUpManager.getAllEntries().size() != 0; - if (mHeadsUp == hasHeadsUp) { - return; - } - mHeadsUp = hasHeadsUp; + public void onHasViewsAboveShelfChanged(boolean hasViewsAboveShelf) { + mHasViewsAboveShelf = hasViewsAboveShelf; invalidate(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 3906e402b0131..4c819c305587a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -209,6 +209,7 @@ import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.ScrimView; import com.android.systemui.statusbar.SignalClusterView; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.notification.AboveShelfObserver; import com.android.systemui.statusbar.notification.InflationException; import com.android.systemui.statusbar.notification.RowInflaterTask; import com.android.systemui.statusbar.notification.VisualStabilityManager; @@ -1000,6 +1001,9 @@ public class StatusBar extends SystemUI implements DemoMode, R.id.notification_stack_scroller); mNotificationPanel.setStatusBar(this); mNotificationPanel.setGroupManager(mGroupManager); + mAboveShelfObserver = new AboveShelfObserver(mStackScroller); + mAboveShelfObserver.setListener(mStatusBarWindow.findViewById( + R.id.notification_container_parent)); mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header); mNotificationIconAreaController = SystemUIFactory.getInstance() @@ -5333,6 +5337,8 @@ public class StatusBar extends SystemUI implements DemoMode, // for heads up notifications protected HeadsUpManager mHeadsUpManager; + private AboveShelfObserver mAboveShelfObserver; + // handling reordering protected VisualStabilityManager mVisualStabilityManager = new VisualStabilityManager(); @@ -6408,6 +6414,7 @@ public class StatusBar extends SystemUI implements DemoMode, row.setExpansionLogger(this, entry.notification.getKey()); row.setGroupManager(mGroupManager); row.setHeadsUpManager(mHeadsUpManager); + row.setAboveShelfChangedListener(mAboveShelfObserver); row.setRemoteInputController(mRemoteInputController); row.setOnExpandClickListener(this); row.setRemoteViewClickHandler(mOnClickHandler); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java index 70f226028e484..53dfb244c776a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.res.Resources; import android.database.ContentObserver; import android.os.Handler; +import android.os.Looper; import android.os.SystemClock; import android.provider.Settings; import android.support.v4.util.ArraySet; @@ -65,7 +66,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL private final ArrayMap mSnoozedPackages; private final HashSet mListeners = new HashSet<>(); private final int mDefaultSnoozeLengthMs; - private final Handler mHandler = new Handler(); + private final Handler mHandler = new Handler(Looper.getMainLooper()); private final Pools.Pool mEntryPool = new Pools.Pool() { private Stack mPoolObjects = new Stack<>(); @@ -624,6 +625,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL @Override public void onReorderingAllowed() { + mBar.getNotificationScrollLayout().setHeadsUpGoingAwayAnimationsAllowed(false); for (NotificationData.Entry entry : mEntriesToRemoveWhenReorderingAllowed) { if (isHeadsUp(entry.key)) { // Maybe the heads-up was removed already @@ -631,6 +633,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL } } mEntriesToRemoveWhenReorderingAllowed.clear(); + mBar.getNotificationScrollLayout().setHeadsUpGoingAwayAnimationsAllowed(true); } public void setVisualStabilityManager(VisualStabilityManager visualStabilityManager) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java index 41ef78121c123..b7b991e36710d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java @@ -61,6 +61,7 @@ public class AmbientState { private boolean mPanelFullWidth; private boolean mHasPulsingNotifications; private boolean mUnlockHintRunning; + private boolean mQsCustomizerShowing; public AmbientState(Context context) { reload(context); @@ -314,4 +315,12 @@ public class AmbientState { public boolean isUnlockHintRunning() { return mUnlockHintRunning; } + + public boolean isQsCustomizerShowing() { + return mQsCustomizerShowing; + } + + public void setQsCustomizerShowing(boolean qsCustomizerShowing) { + mQsCustomizerShowing = qsCustomizerShowing; + } } 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 84acaf1e842b4..a3d812cc0796b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -375,6 +375,7 @@ public class NotificationStackScrollLayout extends ViewGroup private boolean mHeadsUpAnimatingAway; private int mStatusBarState; private int mCachedBackgroundColor; + private boolean mHeadsUpGoingAwayAnimationsAllowed = true; private Runnable mAnimateScroll = this::animateScroll; public NotificationStackScrollLayout(Context context) { @@ -4060,7 +4061,7 @@ public class NotificationStackScrollLayout extends ViewGroup } public void generateHeadsUpAnimation(ExpandableNotificationRow row, boolean isHeadsUp) { - if (mAnimationsEnabled) { + if (mAnimationsEnabled && (isHeadsUp || mHeadsUpGoingAwayAnimationsAllowed)) { mHeadsUpChangeAnimations.add(new Pair<>(row, isHeadsUp)); mNeedsAnimation = true; if (!mIsExpanded && !isHeadsUp) { @@ -4242,6 +4243,15 @@ public class NotificationStackScrollLayout extends ViewGroup mAmbientState.setUnlockHintRunning(running); } + public void setQsCustomizerShowing(boolean isShowing) { + mAmbientState.setQsCustomizerShowing(isShowing); + requestChildrenUpdate(); + } + + public void setHeadsUpGoingAwayAnimationsAllowed(boolean headsUpGoingAwayAnimationsAllowed) { + mHeadsUpGoingAwayAnimationsAllowed = headsUpGoingAwayAnimationsAllowed; + } + /** * A listener that is notified when some child locations might have changed. */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java index 99b664ad9580b..2d4653760b1d9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java @@ -29,6 +29,7 @@ import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.view.View; +import com.android.systemui.statusbar.notification.AboveShelfChangedListener; import com.android.systemui.statusbar.stack.NotificationChildrenContainer; import com.android.systemui.SysuiTestCase; @@ -96,4 +97,40 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { row.setHideSensitive(true, false, 0, 0); verify(row).updateShelfIconColor(); } + + @Test + public void testAboveShelfChangedListenerCalled() throws Exception { + ExpandableNotificationRow row = mNotificationTestHelper.createRow(); + AboveShelfChangedListener listener = mock(AboveShelfChangedListener.class); + row.setAboveShelfChangedListener(listener); + row.setHeadsUp(true); + verify(listener).onAboveShelfStateChanged(true); + } + + @Test + public void testAboveShelfChangedListenerCalledPinned() throws Exception { + ExpandableNotificationRow row = mNotificationTestHelper.createRow(); + AboveShelfChangedListener listener = mock(AboveShelfChangedListener.class); + row.setAboveShelfChangedListener(listener); + row.setPinned(true); + verify(listener).onAboveShelfStateChanged(true); + } + + @Test + public void testAboveShelfChangedListenerCalledHeadsUpGoingAway() throws Exception { + ExpandableNotificationRow row = mNotificationTestHelper.createRow(); + AboveShelfChangedListener listener = mock(AboveShelfChangedListener.class); + row.setAboveShelfChangedListener(listener); + row.setHeadsUpAnimatingAway(true); + verify(listener).onAboveShelfStateChanged(true); + } + @Test + public void testAboveShelfChangedListenerCalledWhenGoingBelow() throws Exception { + ExpandableNotificationRow row = mNotificationTestHelper.createRow(); + row.setHeadsUp(true); + AboveShelfChangedListener listener = mock(AboveShelfChangedListener.class); + row.setAboveShelfChangedListener(listener); + row.setAboveShelf(false); + verify(listener).onAboveShelfStateChanged(false); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java index cb238ddbabaa7..6e7477fbac386 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java @@ -24,12 +24,16 @@ import android.os.UserHandle; import android.service.notification.StatusBarNotification; import android.support.test.InstrumentationRegistry; import android.view.LayoutInflater; +import android.widget.FrameLayout; import android.widget.RemoteViews; import com.android.systemui.R; +import com.android.systemui.statusbar.notification.AboveShelfChangedListener; +import com.android.systemui.statusbar.notification.AboveShelfObserver; import com.android.systemui.statusbar.notification.InflationException; import com.android.systemui.statusbar.notification.NotificationInflaterTest; import com.android.systemui.statusbar.phone.NotificationGroupManager; +import com.android.systemui.statusbar.policy.HeadsUpManager; /** * A helper class to create {@link ExpandableNotificationRow} @@ -42,10 +46,12 @@ public class NotificationTestHelper { private final NotificationGroupManager mGroupManager = new NotificationGroupManager(); private ExpandableNotificationRow mRow; private InflationException mException; + private HeadsUpManager mHeadsUpManager; public NotificationTestHelper(Context context) { mContext = context; mInstrumentation = InstrumentationRegistry.getInstrumentation(); + mHeadsUpManager = new HeadsUpManager(mContext, null, mGroupManager); } public ExpandableNotificationRow createRow() throws Exception { @@ -73,6 +79,8 @@ public class NotificationTestHelper { }); ExpandableNotificationRow row = mRow; row.setGroupManager(mGroupManager); + row.setHeadsUpManager(mHeadsUpManager); + row.setAboveShelfChangedListener(aboveShelf -> {}); UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser()); StatusBarNotification sbn = new StatusBarNotification("com.android.systemui", "com.android.systemui", mId++, null, 1000, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java new file mode 100644 index 0000000000000..1ee9b321cf84e --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2017 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.notification; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.SmallTest; +import android.widget.FrameLayout; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.ExpandableNotificationRow; +import com.android.systemui.statusbar.NotificationTestHelper; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class AboveShelfObserverTest extends SysuiTestCase { + + private AboveShelfObserver mObserver; + private FrameLayout mHostLayout; + private NotificationTestHelper mNotificationTestHelper; + private AboveShelfObserver.HasViewAboveShelfChangedListener mListener; + + @Before + public void setUp() throws Exception { + mNotificationTestHelper = new NotificationTestHelper(getContext()); + mHostLayout = new FrameLayout(getContext()); + mObserver = new AboveShelfObserver(mHostLayout); + ExpandableNotificationRow row = mNotificationTestHelper.createRow(); + row.setAboveShelfChangedListener(mObserver); + mHostLayout.addView(row); + row = mNotificationTestHelper.createRow(); + row.setAboveShelfChangedListener(mObserver); + mHostLayout.addView(row); + mListener = mock(AboveShelfObserver.HasViewAboveShelfChangedListener.class); + } + + @Test + public void testObserverChangesWhenGoingAbove() { + ExpandableNotificationRow row = (ExpandableNotificationRow) mHostLayout.getChildAt(0); + mObserver.setListener(mListener); + row.setHeadsUp(true); + verify(mListener).onHasViewsAboveShelfChanged(true); + } + + @Test + public void testObserverChangesWhenGoingBelow() { + ExpandableNotificationRow row = (ExpandableNotificationRow) mHostLayout.getChildAt(0); + row.setHeadsUp(true); + mObserver.setListener(mListener); + row.setHeadsUp(false); + verify(mListener).onHasViewsAboveShelfChanged(false); + } + + @Test + public void testStaysAboveWhenOneGoesAway() { + ExpandableNotificationRow row = (ExpandableNotificationRow) mHostLayout.getChildAt(0); + row.setHeadsUp(true); + row = (ExpandableNotificationRow) mHostLayout.getChildAt(1); + row.setHeadsUp(true); + row.setHeadsUp(false); + Assert.assertTrue("There are still views above the shelf but removing one cleared it", + mObserver.hasViewsAboveShelf()); + } +} +