Loading packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java +39 −1 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ package com.android.systemui.plugins.qs; import android.graphics.Rect; import android.view.View; import androidx.annotation.FloatRange; Loading @@ -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"; Loading Loading @@ -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) { } Loading packages/SystemUI/src/com/android/systemui/qs/QSFragmentLegacy.java +48 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -103,6 +105,7 @@ public class QSFragmentLegacy extends LifecycleFragment implements QS { @Override public View getHeader() { QSComposeFragment.assertInLegacyMode(); if (mQsImpl != null) { return mQsImpl.getHeader(); } else { Loading @@ -110,6 +113,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) { Loading packages/SystemUI/src/com/android/systemui/qs/QSImpl.java +27 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -355,9 +356,35 @@ 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) { } Loading packages/SystemUI/src/com/android/systemui/shade/QSHeaderBoundsProvider.kt 0 → 100644 +25 −0 Original line number Diff line number Diff line /* * 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, ) packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java +56 −9 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -110,6 +110,8 @@ import dalvik.annotation.optimization.NeverCompile; import dagger.Lazy; import kotlin.Unit; import java.io.PrintWriter; import javax.inject.Inject; Loading Loading @@ -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() { Loading Loading @@ -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); Loading Loading @@ -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. */ Loading Loading @@ -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); 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(); } Loading @@ -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; } } Loading Loading
packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java +39 −1 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ package com.android.systemui.plugins.qs; import android.graphics.Rect; import android.view.View; import androidx.annotation.FloatRange; Loading @@ -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"; Loading Loading @@ -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) { } Loading
packages/SystemUI/src/com/android/systemui/qs/QSFragmentLegacy.java +48 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -103,6 +105,7 @@ public class QSFragmentLegacy extends LifecycleFragment implements QS { @Override public View getHeader() { QSComposeFragment.assertInLegacyMode(); if (mQsImpl != null) { return mQsImpl.getHeader(); } else { Loading @@ -110,6 +113,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) { Loading
packages/SystemUI/src/com/android/systemui/qs/QSImpl.java +27 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -355,9 +356,35 @@ 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) { } Loading
packages/SystemUI/src/com/android/systemui/shade/QSHeaderBoundsProvider.kt 0 → 100644 +25 −0 Original line number Diff line number Diff line /* * 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, )
packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java +56 −9 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -110,6 +110,8 @@ import dalvik.annotation.optimization.NeverCompile; import dagger.Lazy; import kotlin.Unit; import java.io.PrintWriter; import javax.inject.Inject; Loading Loading @@ -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() { Loading Loading @@ -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); Loading Loading @@ -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. */ Loading Loading @@ -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); 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(); } Loading @@ -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; } } Loading