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 ed0ca30537734..448f4d8cf408c 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()); + } +} +