summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Fabian Kozynski <kozynski@google.com> 2024-07-31 16:13:01 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-07-31 16:13:01 +0000
commit83c474c00a314aa0fdec8859f707fdfb9eb627d0 (patch)
tree6295834b2684808031c135c91f3ca63204c60c0e
parent00dfebf2843449705d72cf1f6aed07f7ea2718f4 (diff)
parent1d13c765fcf62f18b7753624b2cff680a91fe7de (diff)
Merge "Creates API for QS that avoids getHeader" into main
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragmentLegacy.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSImpl.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/QSHeaderBoundsProvider.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java65
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java50
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java39
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java64
11 files changed, 372 insertions, 16 deletions
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index bf58eee9a9ce..d3218ad8c9fb 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -14,6 +14,7 @@
package com.android.systemui.plugins.qs;
+import android.graphics.Rect;
import android.view.View;
import androidx.annotation.FloatRange;
@@ -35,7 +36,7 @@ public interface QS extends FragmentBase {
String ACTION = "com.android.systemui.action.PLUGIN_QS";
- int VERSION = 15;
+ int VERSION = 16;
String TAG = "QS";
@@ -89,8 +90,45 @@ public interface QS extends FragmentBase {
*/
int getHeightDiff();
+ /**
+ * Returns the header view that contains QQS. This might return null (or throw) if there's no
+ * actual header view.
+ */
View getHeader();
+ /**
+ * Returns the top of the header view that contains QQS wrt to the container view
+ */
+ int getHeaderTop();
+
+ /**
+ * Returns the bottom of the header view that contains QQS wrt to the container view
+ */
+ int getHeaderBottom();
+
+ /**
+ * Returns the left bound of the header view that contains QQS wrt to the container view
+ */
+ int getHeaderLeft();
+
+ /**
+ * Fills outBounds with the bounds of the header view (container of QQS) on the screen
+ */
+ void getHeaderBoundsOnScreen(Rect outBounds);
+
+ /**
+ * Returns the height of the header view that contains QQS. It defaults to bottom - top.
+ */
+ default int getHeaderHeight() {
+ return getHeaderBottom() - getHeaderTop();
+ }
+
+ /**
+ * Returns whether the header view that contains QQS is shown on screen (similar semantics to
+ * View.isShown).
+ */
+ boolean isHeaderShown();
+
default void setHasNotifications(boolean hasNotifications) {
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentLegacy.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentLegacy.java
index 38d7290fc3bc..37002ca99233 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentLegacy.java
@@ -17,6 +17,7 @@
package com.android.systemui.qs;
import android.content.res.Configuration;
+import android.graphics.Rect;
import android.os.Bundle;
import android.os.Trace;
import android.view.ContextThemeWrapper;
@@ -30,6 +31,7 @@ import androidx.annotation.Nullable;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.qs.QSContainerController;
import com.android.systemui.qs.dagger.QSFragmentComponent;
+import com.android.systemui.qs.flags.QSComposeFragment;
import com.android.systemui.res.R;
import com.android.systemui.settings.brightness.MirrorController;
import com.android.systemui.util.LifecycleFragment;
@@ -103,6 +105,7 @@ public class QSFragmentLegacy extends LifecycleFragment implements QS {
@Override
public View getHeader() {
+ QSComposeFragment.assertInLegacyMode();
if (mQsImpl != null) {
return mQsImpl.getHeader();
} else {
@@ -111,6 +114,51 @@ public class QSFragmentLegacy extends LifecycleFragment implements QS {
}
@Override
+ public int getHeaderTop() {
+ if (mQsImpl != null) {
+ return mQsImpl.getHeaderTop();
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public int getHeaderBottom() {
+ if (mQsImpl != null) {
+ return mQsImpl.getHeaderBottom();
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public int getHeaderLeft() {
+ if (mQsImpl != null) {
+ return mQsImpl.getHeaderLeft();
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public void getHeaderBoundsOnScreen(Rect outBounds) {
+ if (mQsImpl != null) {
+ mQsImpl.getHeaderBoundsOnScreen(outBounds);
+ } else {
+ outBounds.setEmpty();
+ }
+ }
+
+ @Override
+ public boolean isHeaderShown() {
+ if (mQsImpl != null) {
+ return mQsImpl.isHeaderShown();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
public void setHasNotifications(boolean hasNotifications) {
if (mQsImpl != null) {
mQsImpl.setHasNotifications(hasNotifications);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
index 8c0d122e5c00..a6fd35a9ee37 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
@@ -54,6 +54,7 @@ import com.android.systemui.plugins.qs.QSContainerController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSComponent;
+import com.android.systemui.qs.flags.QSComposeFragment;
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.res.R;
@@ -355,10 +356,36 @@ public class QSImpl implements QS, CommandQueue.Callbacks, StatusBarStateControl
@Override
public View getHeader() {
+ QSComposeFragment.assertInLegacyMode();
return mHeader;
}
@Override
+ public int getHeaderTop() {
+ return mHeader.getTop();
+ }
+
+ @Override
+ public int getHeaderBottom() {
+ return mHeader.getBottom();
+ }
+
+ @Override
+ public int getHeaderLeft() {
+ return mHeader.getLeft();
+ }
+
+ @Override
+ public void getHeaderBoundsOnScreen(Rect outBounds) {
+ mHeader.getBoundsOnScreen(outBounds);
+ }
+
+ @Override
+ public boolean isHeaderShown() {
+ return mHeader.isShown();
+ }
+
+ @Override
public void setHasNotifications(boolean hasNotifications) {
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QSHeaderBoundsProvider.kt b/packages/SystemUI/src/com/android/systemui/shade/QSHeaderBoundsProvider.kt
new file mode 100644
index 000000000000..a447e550bf44
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/QSHeaderBoundsProvider.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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.shade
+
+import android.graphics.Rect
+
+class QSHeaderBoundsProvider(
+ val leftProvider: () -> Int,
+ val heightProvider: () -> Int,
+ val boundsOnScreenProvider: (Rect) -> Unit,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
index 67032f7c097d..9f61d4e5d949 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
@@ -43,7 +43,6 @@ import android.util.Log;
import android.util.MathUtils;
import android.view.MotionEvent;
import android.view.VelocityTracker;
-import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowInsets;
@@ -75,6 +74,7 @@ import com.android.systemui.media.controls.domain.pipeline.MediaDataManager;
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QS;
+import com.android.systemui.qs.flags.QSComposeFragment;
import com.android.systemui.res.R;
import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.screenrecord.RecordingController;
@@ -110,6 +110,8 @@ import dalvik.annotation.optimization.NeverCompile;
import dagger.Lazy;
+import kotlin.Unit;
+
import java.io.PrintWriter;
import javax.inject.Inject;
@@ -494,7 +496,15 @@ public class QuickSettingsControllerImpl implements QuickSettingsController, Dum
}
int getHeaderHeight() {
- return isQsFragmentCreated() ? mQs.getHeader().getHeight() : 0;
+ if (isQsFragmentCreated()) {
+ if (QSComposeFragment.isEnabled()) {
+ return mQs.getHeaderHeight();
+ } else {
+ return mQs.getHeader().getHeight();
+ }
+ } else {
+ return 0;
+ }
}
private boolean isRemoteInputActiveWithKeyboardUp() {
@@ -664,14 +674,26 @@ public class QuickSettingsControllerImpl implements QuickSettingsController, Dum
&& mKeyguardBypassController.getBypassEnabled()) || mSplitShadeEnabled) {
return false;
}
- View header = keyguardShowing || mQs == null ? mKeyguardStatusBar : mQs.getHeader();
+ int headerTop, headerBottom;
+ if (keyguardShowing || mQs == null) {
+ headerTop = mKeyguardStatusBar.getTop();
+ headerBottom = mKeyguardStatusBar.getBottom();
+ } else {
+ if (QSComposeFragment.isEnabled()) {
+ headerTop = mQs.getHeaderTop();
+ headerBottom = mQs.getHeaderBottom();
+ } else {
+ headerTop = mQs.getHeader().getTop();
+ headerBottom = mQs.getHeader().getBottom();
+ }
+ }
int frameTop = keyguardShowing
|| mQs == null ? 0 : mQsFrame.getTop();
mInterceptRegion.set(
/* left= */ (int) mQsFrame.getX(),
- /* top= */ header.getTop() + frameTop,
+ /* top= */ headerTop + frameTop,
/* right= */ (int) mQsFrame.getX() + mQsFrame.getWidth(),
- /* bottom= */ header.getBottom() + frameTop);
+ /* bottom= */ headerBottom + frameTop);
// Also allow QS to intercept if the touch is near the notch.
mStatusBarTouchableRegionManager.updateRegionForNotch(mInterceptRegion);
final boolean onHeader = mInterceptRegion.contains((int) x, (int) y);
@@ -718,9 +740,18 @@ public class QuickSettingsControllerImpl implements QuickSettingsController, Dum
if (mCollapsedOnDown || mBarState == KEYGUARD || getExpanded()) {
return false;
}
- View header = mQs == null ? mKeyguardStatusBar : mQs.getHeader();
+ int headerBottom;
+ if (mQs == null) {
+ headerBottom = mKeyguardStatusBar.getBottom();
+ } else {
+ if (QSComposeFragment.isEnabled()) {
+ headerBottom = mQs.getHeaderBottom();
+ } else {
+ headerBottom = mQs.getHeader().getBottom();
+ }
+ }
return downX >= mQsFrame.getX() && downX <= mQsFrame.getX() + mQsFrame.getWidth()
- && downY <= header.getBottom();
+ && downY <= headerBottom;
}
/** Closes the Qs customizer. */
@@ -2192,14 +2223,27 @@ public class QuickSettingsControllerImpl implements QuickSettingsController, Dum
}
});
mQs.setCollapsedMediaVisibilityChangedListener((visible) -> {
- if (mQs.getHeader().isShown()) {
+ if (mQs.isHeaderShown()) {
setAnimateNextNotificationBounds(
StackStateAnimator.ANIMATION_DURATION_STANDARD, 0);
mNotificationStackScrollLayoutController.animateNextTopPaddingChange();
}
});
mLockscreenShadeTransitionController.setQS(mQs);
- mNotificationStackScrollLayoutController.setQsHeader((ViewGroup) mQs.getHeader());
+ if (QSComposeFragment.isEnabled()) {
+ QSHeaderBoundsProvider provider = new QSHeaderBoundsProvider(
+ mQs::getHeaderLeft,
+ mQs::getHeaderHeight,
+ rect -> {
+ mQs.getHeaderBoundsOnScreen(rect);
+ return Unit.INSTANCE;
+ }
+ );
+
+ mNotificationStackScrollLayoutController.setQsHeaderBoundsProvider(provider);
+ } else {
+ mNotificationStackScrollLayoutController.setQsHeader((ViewGroup) mQs.getHeader());
+ }
mQs.setScrollListener(mQsScrollListener);
updateExpansion();
}
@@ -2211,6 +2255,9 @@ public class QuickSettingsControllerImpl implements QuickSettingsController, Dum
// non-fragment and fragment code. Once we are using a fragment for the notification
// panel, mQs will not need to be null cause it will be tied to the same lifecycle.
if (fragment == mQs) {
+ // Clear it to remove bindings to mQs from the provider.
+ mNotificationStackScrollLayoutController.setQsHeaderBoundsProvider(null);
+ mNotificationStackScrollLayoutController.setQsHeader(null);
mQs = null;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 2f3b3a0fc2de..489bb958718b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -89,8 +89,10 @@ import com.android.systemui.ExpandHelper;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.qs.flags.QSComposeFragment;
import com.android.systemui.res.R;
import com.android.systemui.scene.shared.flag.SceneContainerFlag;
+import com.android.systemui.shade.QSHeaderBoundsProvider;
import com.android.systemui.shade.TouchLogger;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.NotificationShelf;
@@ -351,6 +353,10 @@ public class NotificationStackScrollLayout
private final NotificationSection[] mSections;
private final ArrayList<ExpandableView> mTmpSortedChildren = new ArrayList<>();
protected ViewGroup mQsHeader;
+
+ @Nullable
+ private QSHeaderBoundsProvider mQSHeaderBoundsProvider;
+
// Rect of QsHeader. Kept as a field just to avoid creating a new one each time.
private final Rect mQsHeaderBound = new Rect();
private boolean mContinuousShadowUpdate;
@@ -1179,7 +1185,21 @@ public class NotificationStackScrollLayout
if (!SceneContainerFlag.isEnabled()) {
// Give The Algorithm information regarding the QS height so it can layout notifications
// properly. Needed for some devices that grows notifications down-to-top
- mStackScrollAlgorithm.updateQSFrameTop(mQsHeader == null ? 0 : mQsHeader.getHeight());
+ int height;
+ if (QSComposeFragment.isEnabled()) {
+ if (mQSHeaderBoundsProvider != null) {
+ height = mQSHeaderBoundsProvider.getHeightProvider().invoke();
+ } else {
+ height = 0;
+ }
+ } else {
+ if (mQsHeader != null) {
+ height = mQsHeader.getHeight();
+ } else {
+ height = 0;
+ }
+ }
+ mStackScrollAlgorithm.updateQSFrameTop(height);
}
// Once the layout has finished, we don't need to animate any scrolling clampings anymore.
@@ -1824,10 +1844,16 @@ public class NotificationStackScrollLayout
}
public void setQsHeader(ViewGroup qsHeader) {
- SceneContainerFlag.assertInLegacyMode();
+ QSComposeFragment.assertInLegacyMode();
mQsHeader = qsHeader;
}
+ public void setQsHeaderBoundsProvider(QSHeaderBoundsProvider qsHeaderBoundsProvider) {
+ SceneContainerFlag.assertInLegacyMode();
+ QSComposeFragment.isUnexpectedlyInLegacyMode();
+ mQSHeaderBoundsProvider = qsHeaderBoundsProvider;
+ }
+
public static boolean isPinnedHeadsUp(View v) {
if (v instanceof ExpandableNotificationRow row) {
return row.isHeadsUp() && row.isPinned();
@@ -3745,7 +3771,20 @@ public class NotificationStackScrollLayout
return ev.getY() < mAmbientState.getStackTop();
}
- mQsHeader.getBoundsOnScreen(mQsHeaderBound);
+ if (QSComposeFragment.isEnabled()) {
+ if (mQSHeaderBoundsProvider == null) {
+ return false;
+ } else {
+ mQSHeaderBoundsProvider.getBoundsOnScreenProvider().invoke(mQsHeaderBound);
+ }
+ } else {
+ if (mQsHeader == null) {
+ return false;
+ } else {
+ mQsHeader.getBoundsOnScreen(mQsHeaderBound);
+ }
+ }
+
/**
* One-handed mode defines a feature FEATURE_ONE_HANDED of DisplayArea {@link DisplayArea}
* that will translate down the Y-coordinate whole window screen type except for
@@ -3755,7 +3794,10 @@ public class NotificationStackScrollLayout
* of DisplayArea into relative coordinates for all windows, we need to correct the
* QS Head bounds here.
*/
- final int xOffset = Math.round(ev.getRawX() - ev.getX() + mQsHeader.getLeft());
+ int left =
+ QSComposeFragment.isEnabled() ? mQSHeaderBoundsProvider.getLeftProvider().invoke()
+ : mQsHeader.getLeft();
+ final int xOffset = Math.round(ev.getRawX() - ev.getX() + left);
final int yOffset = Math.round(ev.getRawY() - ev.getY());
mQsHeaderBound.offsetTo(xOffset, yOffset);
return mQsHeaderBound.contains((int) ev.getRawX(), (int) ev.getRawY());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index fb1c5254cc5c..e8ccef63fc6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -80,9 +80,11 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEv
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.domain.interactor.PowerInteractor;
+import com.android.systemui.qs.flags.QSComposeFragment;
import com.android.systemui.res.R;
import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.scene.ui.view.WindowRootView;
+import com.android.systemui.shade.QSHeaderBoundsProvider;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.CommandQueue;
@@ -1522,9 +1524,15 @@ public class NotificationStackScrollLayoutController implements Dumpable {
* Sets the QS header. Used to check if a touch is within its bounds.
*/
public void setQsHeader(ViewGroup view) {
+ QSComposeFragment.assertInLegacyMode();
mView.setQsHeader(view);
}
+ public void setQsHeaderBoundsProvider(QSHeaderBoundsProvider qsHeaderBoundsProvider) {
+ QSComposeFragment.isUnexpectedlyInLegacyMode();
+ mView.setQsHeaderBoundsProvider(qsHeaderBoundsProvider);
+ }
+
public void setAnimationsEnabled(boolean enabled) {
mView.setAnimationsEnabled(enabled);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java
index c0d390a99712..206bbbfba753 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java
@@ -554,6 +554,30 @@ public class QSImplTest extends SysuiTestCase {
assertThat(mUnderTest.isKeyguardState()).isFalse();
}
+ @Test
+ public void testHeaderBounds() {
+ int left = 20;
+ int top = 30;
+ int right = 200;
+ int bottom = 100;
+ setHeaderBounds(left, top, right, bottom);
+
+ assertThat(mUnderTest.getHeaderLeft()).isEqualTo(left);
+ assertThat(mUnderTest.getHeaderTop()).isEqualTo(top);
+ assertThat(mUnderTest.getHeaderBottom()).isEqualTo(bottom);
+ assertThat(mUnderTest.getHeaderHeight()).isEqualTo(bottom - top);
+ }
+
+ @Test
+ public void testHeaderBoundsOnScreen() {
+ Rect bounds = new Rect(0, 10, 100, 200);
+ setHeaderBoundsOnScreen(bounds);
+
+ Rect out = new Rect();
+ mUnderTest.getHeaderBoundsOnScreen(out);
+ assertThat(out).isEqualTo(bounds);
+ }
+
private QSImpl instantiate() {
setupQsComponent();
setUpViews();
@@ -672,4 +696,19 @@ public class QSImplTest extends SysuiTestCase {
private void setIsSmallScreen() {
mUnderTest.setIsNotificationPanelFullWidth(true);
}
+
+ private void setHeaderBounds(int left, int top, int right, int bottom) {
+ when(mHeader.getLeft()).thenReturn(left);
+ when(mHeader.getTop()).thenReturn(top);
+ when(mHeader.getRight()).thenReturn(right);
+ when(mHeader.getBottom()).thenReturn(bottom);
+ }
+
+ private void setHeaderBoundsOnScreen(Rect rect) {
+ doAnswer(invocation -> {
+ Rect bounds = invocation.getArgument(/* index= */ 0);
+ bounds.set(rect);
+ return null;
+ }).when(mHeader).getBoundsOnScreen(any(Rect.class));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
index b7ce33671492..e57382de2edd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
@@ -252,6 +252,8 @@ public class QuickSettingsControllerImplBaseTest extends SysuiTestCase {
when(mQsFrame.getWidth()).thenReturn(QS_FRAME_WIDTH);
when(mQsHeader.getTop()).thenReturn(QS_FRAME_TOP);
when(mQsHeader.getBottom()).thenReturn(QS_FRAME_BOTTOM);
+ when(mQs.getHeaderTop()).thenReturn(QS_FRAME_TOP);
+ when(mQs.getHeaderBottom()).thenReturn(QS_FRAME_BOTTOM);
when(mPanelView.getY()).thenReturn((float) QS_FRAME_TOP);
when(mPanelView.getHeight()).thenReturn(QS_FRAME_BOTTOM);
when(mPanelView.findViewById(R.id.keyguard_status_view))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java
index 7ab3e292d7b1..e7db4690c2c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.shade;
+import static android.platform.test.flag.junit.FlagsParameterization.progressionOf;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_POINTER_DOWN;
@@ -23,6 +24,8 @@ import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.BUTTON_SECONDARY;
import static android.view.MotionEvent.BUTTON_STYLUS_PRIMARY;
+import static com.android.systemui.Flags.FLAG_QS_UI_REFACTOR;
+import static com.android.systemui.Flags.FLAG_QS_UI_REFACTOR_COMPOSE_FRAGMENT;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
@@ -36,10 +39,10 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.FlagsParameterization;
import android.testing.TestableLooper;
import android.view.MotionEvent;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.systemui.plugins.qs.QS;
@@ -52,11 +55,24 @@ import org.mockito.ArgumentCaptor;
import java.util.List;
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(ParameterizedAndroidJunit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class QuickSettingsControllerImplTest extends QuickSettingsControllerImplBaseTest {
+ @Parameters(name = "{0}")
+ public static List<FlagsParameterization> getParams() {
+ return progressionOf(FLAG_QS_UI_REFACTOR, FLAG_QS_UI_REFACTOR_COMPOSE_FRAGMENT);
+ }
+
+ public QuickSettingsControllerImplTest(FlagsParameterization flags) {
+ super();
+ mSetFlagsRule.setFlagsParameterization(flags);
+ }
+
@Test
public void testCloseQsSideEffects() {
enableSplitShade(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index b7995953b327..22b98874c7ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -77,7 +77,10 @@ import com.android.systemui.flags.EnableSceneContainer;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.qs.flags.NewQsUI;
+import com.android.systemui.qs.flags.QSComposeFragment;
import com.android.systemui.res.R;
+import com.android.systemui.shade.QSHeaderBoundsProvider;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
import com.android.systemui.statusbar.EmptyShadeView;
@@ -99,6 +102,8 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.AvalancheController;
import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
+import kotlin.Unit;
+
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
@@ -807,6 +812,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
}
@Test
+ @DisableFlags({QSComposeFragment.FLAG_NAME, NewQsUI.FLAG_NAME})
@DisableSceneContainer // TODO(b/312473478): address lack of QS Header
public void testInsideQSHeader_noOffset() {
ViewGroup qsHeader = mock(ViewGroup.class);
@@ -824,6 +830,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
}
@Test
+ @DisableFlags({QSComposeFragment.FLAG_NAME, NewQsUI.FLAG_NAME})
@DisableSceneContainer // TODO(b/312473478): address lack of QS Header
public void testInsideQSHeader_Offset() {
ViewGroup qsHeader = mock(ViewGroup.class);
@@ -844,6 +851,63 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
}
@Test
+ @EnableFlags({QSComposeFragment.FLAG_NAME, NewQsUI.FLAG_NAME})
+ @DisableSceneContainer // TODO(b/312473478): address lack of QS Header
+ public void testInsideQSHeader_noOffset_qsCompose() {
+ ViewGroup qsHeader = mock(ViewGroup.class);
+ Rect boundsOnScreen = new Rect(0, 0, 1000, 1000);
+ mockBoundsOnScreen(qsHeader, boundsOnScreen);
+
+ QSHeaderBoundsProvider provider = new QSHeaderBoundsProvider(
+ () -> 0,
+ boundsOnScreen::height,
+ rect -> {
+ qsHeader.getBoundsOnScreen(rect);
+ return Unit.INSTANCE;
+ }
+ );
+
+ mStackScroller.setQsHeaderBoundsProvider(provider);
+ mStackScroller.setLeftTopRightBottom(0, 0, 2000, 2000);
+
+ MotionEvent event1 = transformEventForView(createMotionEvent(100f, 100f), mStackScroller);
+ assertTrue(mStackScroller.isInsideQsHeader(event1));
+
+ MotionEvent event2 = transformEventForView(createMotionEvent(1100f, 100f), mStackScroller);
+ assertFalse(mStackScroller.isInsideQsHeader(event2));
+ }
+
+ @Test
+ @EnableFlags({QSComposeFragment.FLAG_NAME, NewQsUI.FLAG_NAME})
+ @DisableSceneContainer // TODO(b/312473478): address lack of QS Header
+ public void testInsideQSHeader_Offset_qsCompose() {
+ ViewGroup qsHeader = mock(ViewGroup.class);
+ Rect boundsOnScreen = new Rect(100, 100, 1000, 1000);
+ mockBoundsOnScreen(qsHeader, boundsOnScreen);
+
+ QSHeaderBoundsProvider provider = new QSHeaderBoundsProvider(
+ () -> 0,
+ boundsOnScreen::height,
+ rect -> {
+ qsHeader.getBoundsOnScreen(rect);
+ return Unit.INSTANCE;
+ }
+ );
+
+ mStackScroller.setQsHeaderBoundsProvider(provider);
+ mStackScroller.setLeftTopRightBottom(200, 200, 2000, 2000);
+
+ MotionEvent event1 = transformEventForView(createMotionEvent(50f, 50f), mStackScroller);
+ assertFalse(mStackScroller.isInsideQsHeader(event1));
+
+ MotionEvent event2 = transformEventForView(createMotionEvent(150f, 150f), mStackScroller);
+ assertFalse(mStackScroller.isInsideQsHeader(event2));
+
+ MotionEvent event3 = transformEventForView(createMotionEvent(250f, 250f), mStackScroller);
+ assertTrue(mStackScroller.isInsideQsHeader(event3));
+ }
+
+ @Test
@DisableSceneContainer // TODO(b/312473478): address disabled test
public void setFractionToShade_recomputesStackHeight() {
mStackScroller.setFractionToShade(1f);