diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java index 70bc56bd1425b..94743407f03dc 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java @@ -63,13 +63,13 @@ abstract class UdfpsAnimationViewController @Override protected void onViewAttached() { - mPanelExpansionStateManager.addListener(mPanelExpansionListener); + mPanelExpansionStateManager.addExpansionListener(mPanelExpansionListener); mDumpManger.registerDumpable(getDumpTag(), this); } @Override protected void onViewDetached() { - mPanelExpansionStateManager.removeListener(mPanelExpansionListener); + mPanelExpansionStateManager.removeExpansionListener(mPanelExpansionListener); mDumpManger.unregisterDumpable(getDumpTag()); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java index 495366c8f69f3..d1ea45cac0810 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java @@ -126,7 +126,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController mBlockedIcons = new ArrayList<>(); @@ -126,6 +128,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue SystemStatusAnimationScheduler animationScheduler, StatusBarLocationPublisher locationPublisher, NotificationIconAreaController notificationIconAreaController, + PanelExpansionStateManager panelExpansionStateManager, FeatureFlags featureFlags, Lazy> statusBarOptionalLazy, StatusBarIconController statusBarIconController, @@ -140,6 +143,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue mAnimationScheduler = animationScheduler; mLocationPublisher = locationPublisher; mNotificationIconAreaController = notificationIconAreaController; + mPanelExpansionStateManager = panelExpansionStateManager; mFeatureFlags = featureFlags; mStatusBarOptionalLazy = statusBarOptionalLazy; mStatusBarIconController = statusBarIconController; @@ -363,7 +367,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue private boolean shouldHideNotificationIcons() { final Optional statusBarOptional = mStatusBarOptionalLazy.get(); - if (!mStatusBar.isClosed() + if (!mPanelExpansionStateManager.isClosed() && statusBarOptional.map( StatusBar::hideStatusBarIconsWhenExpanded).orElse(false)) { return true; @@ -409,7 +413,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue * don't set the clock GONE otherwise it'll mess up the animation. */ private int clockHiddenMode() { - if (!mStatusBar.isClosed() && !mKeyguardStateController.isShowing() + if (!mPanelExpansionStateManager.isClosed() && !mKeyguardStateController.isShowing() && !mStatusBarStateController.isDozing()) { return View.INVISIBLE; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index df0f872d979c8..568e2ff459313 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -35,9 +35,9 @@ import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; import static com.android.systemui.statusbar.StatusBarState.SHADE; import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL; -import static com.android.systemui.statusbar.phone.PanelBar.STATE_CLOSED; -import static com.android.systemui.statusbar.phone.PanelBar.STATE_OPEN; -import static com.android.systemui.statusbar.phone.PanelBar.STATE_OPENING; +import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_CLOSED; +import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_OPEN; +import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_OPENING; import static java.lang.Float.isNaN; @@ -173,6 +173,7 @@ import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent; import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; +import com.android.systemui.statusbar.phone.panelstate.PanelState; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -782,6 +783,8 @@ public class NotificationPanelViewController extends PanelViewController { new DynamicPrivacyControlListener(); dynamicPrivacyController.addListener(dynamicPrivacyControlListener); + panelExpansionStateManager.addStateListener(this::onPanelStateChanged); + mBottomAreaShadeAlphaAnimator = ValueAnimator.ofFloat(1f, 0); mBottomAreaShadeAlphaAnimator.addUpdateListener(animation -> { mBottomAreaShadeAlpha = (float) animation.getAnimatedValue(); @@ -1561,7 +1564,7 @@ public class NotificationPanelViewController extends PanelViewController { // it's possible that nothing animated, so we replicate the termination // conditions of panelExpansionChanged here // TODO(b/200063118): This can likely go away in a future refactor CL. - mBar.updateState(STATE_CLOSED); + getPanelExpansionStateManager().updateState(STATE_CLOSED); } } @@ -1646,7 +1649,7 @@ public class NotificationPanelViewController extends PanelViewController { @Override public void fling(float vel, boolean expand) { - GestureRecorder gr = ((PhoneStatusBarView) mBar).mBar.getGestureRecorder(); + GestureRecorder gr = mStatusBar.getGestureRecorder(); if (gr != null) { gr.tag("fling " + ((vel > 0) ? "open" : "closed"), "notifications,v=" + vel); } @@ -4672,37 +4675,27 @@ public class NotificationPanelViewController extends PanelViewController { mView.removeCallbacks(mMaybeHideExpandedRunnable); } - private final PanelBar.PanelStateChangeListener mPanelStateChangeListener = - new PanelBar.PanelStateChangeListener() { + @PanelState + private int mCurrentPanelState = STATE_CLOSED; - @PanelBar.PanelState - private int mCurrentState = STATE_CLOSED; + private void onPanelStateChanged(@PanelState int state) { + mAmbientState.setIsShadeOpening(state == STATE_OPENING); + updateQSExpansionEnabledAmbient(); - @Override - public void onStateChanged(@PanelBar.PanelState int state) { - mAmbientState.setIsShadeOpening(state == STATE_OPENING); - updateQSExpansionEnabledAmbient(); - - if (state == STATE_OPEN && mCurrentState != state) { - mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); - } - if (state == STATE_OPENING) { - mStatusBar.makeExpandedVisible(false); - } - if (state == STATE_CLOSED) { - // Close the status bar in the next frame so we can show the end of the - // animation. - mView.post(mMaybeHideExpandedRunnable); - } - mCurrentState = state; - } - }; - - public PanelBar.PanelStateChangeListener getPanelStateChangeListener() { - return mPanelStateChangeListener; + if (state == STATE_OPEN && mCurrentPanelState != state) { + mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); + } + if (state == STATE_OPENING) { + mStatusBar.makeExpandedVisible(false); + } + if (state == STATE_CLOSED) { + // Close the status bar in the next frame so we can show the end of the + // animation. + mView.post(mMaybeHideExpandedRunnable); + } + mCurrentPanelState = state; } - /** Returns the handler that the status bar should forward touches to. */ public PhoneStatusBarView.TouchEventHandler getStatusBarTouchEventHandler() { return getTouchHandler()::onTouchForwardedFromStatusBar; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java index 0b3e040bd321b..01587f7fe98c7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java @@ -447,7 +447,7 @@ public class NotificationShadeWindowViewController { setDragDownHelper(mLockscreenShadeTransitionController.getTouchHelper()); mDepthController.setRoot(mView); - mPanelExpansionStateManager.addListener(mDepthController); + mPanelExpansionStateManager.addExpansionListener(mDepthController); } public NotificationShadeWindowView getView() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java deleted file mode 100644 index e90258db85718..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2012 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.phone; - -import static java.lang.Float.isNaN; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.annotation.IntDef; -import android.content.Context; -import android.os.Bundle; -import android.os.Parcelable; -import android.util.AttributeSet; -import android.util.Log; -import android.widget.FrameLayout; - -import androidx.annotation.Nullable; - -import java.lang.annotation.Retention; - -public abstract class PanelBar extends FrameLayout { - public static final boolean DEBUG = false; - public static final String TAG = PanelBar.class.getSimpleName(); - private static final boolean SPEW = false; - private static final String PANEL_BAR_SUPER_PARCELABLE = "panel_bar_super_parcelable"; - private static final String STATE = "state"; - protected float mPanelFraction; - - public static final void LOG(String fmt, Object... args) { - if (!DEBUG) return; - Log.v(TAG, String.format(fmt, args)); - } - - /** Enum for the current state of the panel. */ - @Retention(SOURCE) - @IntDef({STATE_CLOSED, STATE_OPENING, STATE_OPEN}) - @interface PanelState {} - public static final int STATE_CLOSED = 0; - public static final int STATE_OPENING = 1; - public static final int STATE_OPEN = 2; - - @Nullable private PanelStateChangeListener mPanelStateChangeListener; - private int mState = STATE_CLOSED; - private boolean mTracking; - - /** Updates the panel state if necessary. */ - public void updateState(@PanelState int state) { - if (DEBUG) LOG("update state: %d -> %d", mState, state); - if (mState != state) { - go(state); - } - } - - private void go(@PanelState int state) { - if (DEBUG) LOG("go state: %d -> %d", mState, state); - mState = state; - if (mPanelStateChangeListener != null) { - mPanelStateChangeListener.onStateChanged(state); - } - } - - @Override - protected Parcelable onSaveInstanceState() { - Bundle bundle = new Bundle(); - bundle.putParcelable(PANEL_BAR_SUPER_PARCELABLE, super.onSaveInstanceState()); - bundle.putInt(STATE, mState); - return bundle; - } - - @Override - protected void onRestoreInstanceState(Parcelable state) { - if (state == null || !(state instanceof Bundle)) { - super.onRestoreInstanceState(state); - return; - } - - Bundle bundle = (Bundle) state; - super.onRestoreInstanceState(bundle.getParcelable(PANEL_BAR_SUPER_PARCELABLE)); - if (((Bundle) state).containsKey(STATE)) { - go(bundle.getInt(STATE, STATE_CLOSED)); - } - } - - public PanelBar(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - } - - /** Sets the listener that will be notified of panel state changes. */ - public void setPanelStateChangeListener(PanelStateChangeListener listener) { - mPanelStateChangeListener = listener; - } - - /** - * @param frac the fraction from the expansion in [0, 1] - * @param expanded whether the panel is currently expanded; this is independent from the - * fraction as the panel also might be expanded if the fraction is 0 - */ - public void panelExpansionChanged(float frac, boolean expanded) { - if (isNaN(frac)) { - throw new IllegalArgumentException("frac cannot be NaN"); - } - boolean fullyClosed = true; - boolean fullyOpened = false; - if (SPEW) LOG("panelExpansionChanged: start state=%d, f=%.1f", mState, frac); - mPanelFraction = frac; - // adjust any other panels that may be partially visible - if (expanded) { - if (mState == STATE_CLOSED) { - go(STATE_OPENING); - } - fullyClosed = false; - fullyOpened = frac >= 1f; - } - if (fullyOpened && !mTracking) { - go(STATE_OPEN); - } else if (fullyClosed && !mTracking && mState != STATE_CLOSED) { - go(STATE_CLOSED); - } - - if (SPEW) LOG("panelExpansionChanged: end state=%d [%s%s ]", mState, - fullyOpened?" fullyOpened":"", fullyClosed?" fullyClosed":""); - } - - public boolean isClosed() { - return mState == STATE_CLOSED; - } - - public void onTrackingStarted() { - mTracking = true; - } - - public void onTrackingStopped(boolean expand) { - mTracking = false; - } - - /** An interface that will be notified of panel state changes. */ - public interface PanelStateChangeListener { - /** Called when the state changes. */ - void onStateChanged(@PanelState int state); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 481401b3eb7bb..249f9886253c5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -23,7 +23,7 @@ import android.view.MotionEvent; import android.widget.FrameLayout; public abstract class PanelView extends FrameLayout { - public static final boolean DEBUG = PanelBar.DEBUG; + public static final boolean DEBUG = false; public static final String TAG = PanelView.class.getSimpleName(); private PanelViewController.TouchHandler mTouchHandler; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java index b508ddfdafba3..38cf78734f2c7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -67,7 +67,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; public abstract class PanelViewController { - public static final boolean DEBUG = PanelBar.DEBUG; + public static final boolean DEBUG = PanelView.DEBUG; public static final String TAG = PanelView.class.getSimpleName(); private static final int NO_FIXED_DURATION = -1; private static final long SHADE_OPEN_SPRING_OUT_DURATION = 350L; @@ -153,8 +153,6 @@ public abstract class PanelViewController { private boolean mAnimateAfterExpanding; private boolean mIsFlinging; - PanelBar mBar; - private String mViewName; private float mInitialTouchY; private float mInitialTouchX; @@ -462,7 +460,6 @@ public abstract class PanelViewController { protected void onTrackingStopped(boolean expand) { mTracking = false; - mBar.onTrackingStopped(expand); mStatusBar.onTrackingStopped(expand); updatePanelExpansionAndVisibility(); } @@ -470,7 +467,6 @@ public abstract class PanelViewController { protected void onTrackingStarted() { endClosing(); mTracking = true; - mBar.onTrackingStarted(); mStatusBar.onTrackingStarted(); notifyExpandingStarted(); updatePanelExpansionAndVisibility(); @@ -848,10 +844,6 @@ public abstract class PanelViewController { return mTracking; } - public void setBar(PanelBar panelBar) { - mBar = panelBar; - } - public void collapse(boolean delayed, float speedUpFactor) { if (DEBUG) logf("collapse: " + this); if (canPanelBeCollapsed()) { @@ -1089,12 +1081,9 @@ public abstract class PanelViewController { * {@link #updateVisibility()}? That would allow us to make this method private. */ public void updatePanelExpansionAndVisibility() { - if (mBar != null) { - mBar.panelExpansionChanged(mExpandedFraction, isExpanded()); - } - updateVisibility(); mPanelExpansionStateManager.onPanelExpansionChanged( mExpandedFraction, isExpanded(), mTracking); + updateVisibility(); } public boolean isExpanded() { @@ -1453,4 +1442,8 @@ public abstract class PanelViewController { protected float getExpansionFraction() { return mExpandedFraction; } + + protected PanelExpansionStateManager getPanelExpansionStateManager() { + return mPanelExpansionStateManager; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index 41312243be348..e9227bea864f1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -33,6 +33,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; import android.view.accessibility.AccessibilityEvent; +import android.widget.FrameLayout; import android.widget.LinearLayout; import com.android.internal.policy.SystemBarUtils; @@ -45,10 +46,8 @@ import com.android.systemui.util.leak.RotationUtils; import java.util.Objects; -public class PhoneStatusBarView extends PanelBar { +public class PhoneStatusBarView extends FrameLayout { private static final String TAG = "PhoneStatusBarView"; - private static final boolean DEBUG = StatusBar.DEBUG; - private static final boolean DEBUG_GESTURES = false; private final StatusBarContentInsetsProvider mContentInsetsProvider; StatusBar mBar; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index cef0613c3f9ab..1077347eab0a0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -271,7 +271,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump ScrimController.this.onThemeChanged(); } }); - panelExpansionStateManager.addListener( + panelExpansionStateManager.addExpansionListener( (fraction, expanded, tracking) -> setRawPanelExpansionFraction(fraction) ); 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 5850e05f078d2..3bfb88e4717bc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -887,7 +887,7 @@ public class StatusBar extends SystemUI implements mStartingSurfaceOptional = startingSurfaceOptional; lockscreenShadeTransitionController.setStatusbar(this); - mPanelExpansionStateManager.addListener(this::onPanelExpansionChanged); + mPanelExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged); mBubbleExpandListener = (isExpanding, key) -> mContext.getMainExecutor().execute(() -> { @@ -1128,7 +1128,7 @@ public class StatusBar extends SystemUI implements mNotificationLogger.setUpWithContainer(notifListContainer); mNotificationIconAreaController.setupShelf(mNotificationShelfController); - mPanelExpansionStateManager.addListener(mWakeUpCoordinator); + mPanelExpansionStateManager.addExpansionListener(mWakeUpCoordinator); mUserSwitcherController.init(mNotificationShadeWindowView); @@ -1143,12 +1143,8 @@ public class StatusBar extends SystemUI implements PhoneStatusBarView oldStatusBarView = mStatusBarView; mStatusBarView = (PhoneStatusBarView) statusBarFragment.getView(); mStatusBarView.setBar(this); - mStatusBarView.setPanelStateChangeListener( - mNotificationPanelViewController.getPanelStateChangeListener()); mStatusBarView.setScrimController(mScrimController); - mNotificationPanelViewController.setBar(mStatusBarView); - mPhoneStatusBarViewController = mPhoneStatusBarViewControllerFactory .create(mStatusBarView, mNotificationPanelViewController .getStatusBarTouchEventHandler()); @@ -1200,6 +1196,7 @@ public class StatusBar extends SystemUI implements mAnimationScheduler, mStatusBarLocationPublisher, mNotificationIconAreaController, + mPanelExpansionStateManager, mFeatureFlags, () -> Optional.of(this), diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 30e668ac44314..58d28813df0c5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -279,7 +279,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mBouncer = mKeyguardBouncerFactory.create(container, mExpansionCallback); mNotificationPanelViewController = notificationPanelViewController; if (panelExpansionStateManager != null) { - panelExpansionStateManager.addListener(this); + panelExpansionStateManager.addExpansionListener(this); } mBypassController = bypassController; mNotificationContainer = notificationContainer; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt index aa748b00d570c..2c7c8e113fc50 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.phone.panelstate +import android.annotation.IntDef +import android.util.Log import androidx.annotation.FloatRange import com.android.systemui.dagger.SysUISingleton import javax.inject.Inject @@ -23,42 +25,136 @@ import javax.inject.Inject /** * A class responsible for managing the notification panel's current state. * - * TODO(b/200063118): Move [PanelBar.panelExpansionChanged] logic to this class and make this class - * the one source of truth for the state of panel expansion. + * TODO(b/200063118): Make this class the one source of truth for the state of panel expansion. */ @SysUISingleton class PanelExpansionStateManager @Inject constructor() { - private val listeners: MutableList = mutableListOf() + private val expansionListeners = mutableListOf() + private val stateListeners = mutableListOf() + @PanelState private var state: Int = STATE_CLOSED @FloatRange(from = 0.0, to = 1.0) private var fraction: Float = 0f private var expanded: Boolean = false private var tracking: Boolean = false /** - * Adds a listener that will be notified when the panel expansion has changed. + * Adds a listener that will be notified when the panel expansion fraction has changed. * * Listener will also be immediately notified with the current values. */ - fun addListener(listener: PanelExpansionListener) { - listeners.add(listener) + fun addExpansionListener(listener: PanelExpansionListener) { + expansionListeners.add(listener) listener.onPanelExpansionChanged(fraction, expanded, tracking) } - /** Removes a listener. */ - fun removeListener(listener: PanelExpansionListener) { - listeners.remove(listener) + /** Removes an expansion listener. */ + fun removeExpansionListener(listener: PanelExpansionListener) { + expansionListeners.remove(listener) } - /** Called when the panel expansion has changed. Notifies all listeners of change. */ + /** Adds a listener that will be notified when the panel state has changed. */ + fun addStateListener(listener: PanelStateListener) { + stateListeners.add(listener) + } + + /** Removes a state listener. */ + fun removeStateListener(listener: PanelStateListener) { + stateListeners.remove(listener) + } + + /** Returns true if the panel is currently closed and false otherwise. */ + fun isClosed(): Boolean = state == STATE_CLOSED + + /** + * Called when the panel expansion has changed. + * + * @param fraction the fraction from the expansion in [0, 1] + * @param expanded whether the panel is currently expanded; this is independent from the + * fraction as the panel also might be expanded if the fraction is 0. + * @param tracking whether we're currently tracking the user's gesture. + */ fun onPanelExpansionChanged( @FloatRange(from = 0.0, to = 1.0) fraction: Float, expanded: Boolean, tracking: Boolean ) { + require(!fraction.isNaN()) { "fraction cannot be NaN" } + val oldState = state + this.fraction = fraction this.expanded = expanded this.tracking = tracking - listeners.forEach { it.onPanelExpansionChanged(fraction, expanded, tracking) } + + var fullyClosed = true + var fullyOpened = false + + if (expanded) { + if (this.state == STATE_CLOSED) { + updateStateInternal(STATE_OPENING) + } + fullyClosed = false + fullyOpened = fraction >= 1f + } + + if (fullyOpened && !tracking) { + updateStateInternal(STATE_OPEN) + } else if (fullyClosed && !tracking && this.state != STATE_CLOSED) { + updateStateInternal(STATE_CLOSED) + } + + debugLog( + "panelExpansionChanged:" + + "start state=${oldState.stateToString()} " + + "end state=${state.stateToString()} " + + "f=$fraction " + + "expanded=$expanded " + + "tracking=$tracking" + + "${if (fullyOpened) " fullyOpened" else ""} " + + if (fullyClosed) " fullyClosed" else "" + ) + + expansionListeners.forEach { it.onPanelExpansionChanged(fraction, expanded, tracking) } + } + + /** Updates the panel state if necessary. */ + fun updateState(@PanelState state: Int) { + debugLog("update state: ${this.state.stateToString()} -> ${state.stateToString()}") + if (this.state != state) { + updateStateInternal(state) + } + } + + private fun updateStateInternal(@PanelState state: Int) { + debugLog("go state: ${this.state.stateToString()} -> ${state.stateToString()}") + this.state = state + stateListeners.forEach { it.onPanelStateChanged(state) } + } + + private fun debugLog(msg: String) { + if (!DEBUG) return + Log.v(TAG, msg) } } + +/** Enum for the current state of the panel. */ +@Retention(AnnotationRetention.SOURCE) +@IntDef(value = [STATE_CLOSED, STATE_OPENING, STATE_OPEN]) +internal annotation class PanelState + +const val STATE_CLOSED = 0 +const val STATE_OPENING = 1 +const val STATE_OPEN = 2 + +@PanelState +private fun Int.stateToString(): String { + return when (this) { + STATE_CLOSED -> "CLOSED" + STATE_OPENING -> "OPENING" + STATE_OPEN -> "OPEN" + else -> this.toString() + } +} + +private const val DEBUG = false +private val TAG = PanelExpansionStateManager::class.simpleName diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelStateListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelStateListener.kt new file mode 100644 index 0000000000000..e299592903555 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelStateListener.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2021 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.phone.panelstate + +/** A listener interface to be notified of state change events for the notification panel. */ +interface PanelStateListener { + /** Called when the panel's expansion state has changed. */ + fun onPanelStateChanged(@PanelState state: Int) +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java index 6f0456ef8f5b4..0e86964147d75 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java @@ -171,7 +171,7 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase { verify(mStatusBarStateController).removeCallback(mStatusBarStateListener); for (PanelExpansionListener listener : mExpansionListeners) { - verify(mPanelExpansionStateManager).removeListener(listener); + verify(mPanelExpansionStateManager).removeExpansionListener(listener); } verify(mKeyguardStateController).removeCallback(mKeyguardStateControllerCallback); } @@ -435,7 +435,7 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase { private void captureExpansionListeners() { verify(mPanelExpansionStateManager, times(2)) - .addListener(mExpansionListenerCaptor.capture()); + .addExpansionListener(mExpansionListenerCaptor.capture()); // first (index=0) is from super class, UdfpsAnimationViewController. // second (index=1) is from UdfpsKeyguardViewController mExpansionListeners = mExpansionListenerCaptor.getAllValues(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java index f23f14801484e..fd3783f025210 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java @@ -48,6 +48,7 @@ import com.android.systemui.statusbar.OperatorNameViewController; import com.android.systemui.statusbar.connectivity.NetworkController; import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler; import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController; +import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.Before; @@ -259,6 +260,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { mAnimationScheduler, mLocationPublisher, mMockNotificationAreaController, + new PanelExpansionStateManager(), mock(FeatureFlags.class), () -> Optional.of(mStatusBar), mStatusBarIconController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java index b2b1bf5a1212d..3028737969d98 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java @@ -176,8 +176,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { @Mock private HeadsUpTouchHelper.Callback mHeadsUpCallback; @Mock - private PanelBar mPanelBar; - @Mock private KeyguardUpdateMonitor mUpdateMonitor; @Mock private KeyguardBypassController mKeyguardBypassController; @@ -460,7 +458,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { () -> {}, mNotificationShelfController); mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager); - mNotificationPanelViewController.setBar(mPanelBar); mNotificationPanelViewController.setKeyguardIndicationController( mKeyguardIndicationController); ArgumentCaptor onAttachStateChangeListenerArgumentCaptor = diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt index 300860ca0a498..e8ad5fd36f82f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt @@ -53,40 +53,6 @@ class PhoneStatusBarViewTest : SysuiTestCase() { view.setBar(statusBar) } - @Test - fun panelStateChanged_toStateOpening_listenerNotified() { - val listener = TestStateChangedListener() - view.setPanelStateChangeListener(listener) - - view.panelExpansionChanged(0.5f, true) - - assertThat(listener.state).isEqualTo(PanelBar.STATE_OPENING) - } - - @Test - fun panelStateChanged_toStateOpen_listenerNotified() { - val listener = TestStateChangedListener() - view.setPanelStateChangeListener(listener) - - view.panelExpansionChanged(1f, true) - - assertThat(listener.state).isEqualTo(PanelBar.STATE_OPEN) - } - - @Test - fun panelStateChanged_toStateClosed_listenerNotified() { - val listener = TestStateChangedListener() - view.setPanelStateChangeListener(listener) - - // First, open the panel - view.panelExpansionChanged(1f, true) - - // Then, close it again - view.panelExpansionChanged(0f, false) - - assertThat(listener.state).isEqualTo(PanelBar.STATE_CLOSED) - } - @Test fun onTouchEvent_listenerNotified() { val handler = TestTouchEventHandler() @@ -126,13 +92,6 @@ class PhoneStatusBarViewTest : SysuiTestCase() { // No assert needed, just testing no crash } - private class TestStateChangedListener : PanelBar.PanelStateChangeListener { - var state: Int = 0 - override fun onStateChanged(state: Int) { - this.state = state - } - } - private class TestTouchEventHandler : PhoneStatusBarView.TouchEventHandler { var lastEvent: MotionEvent? = null var returnValue: Boolean = false diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManagerTest.kt index e09cde917285d..32bad5c084f5d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManagerTest.kt @@ -33,9 +33,9 @@ class PanelExpansionStateManagerTest : SysuiTestCase() { } @Test - fun onPanelExpansionChanged_listenersNotified() { + fun onPanelExpansionChanged_listenerNotified() { val listener = TestPanelExpansionListener() - panelExpansionStateManager.addListener(listener) + panelExpansionStateManager.addExpansionListener(listener) val fraction = 0.6f val expanded = true val tracking = true @@ -48,20 +48,143 @@ class PanelExpansionStateManagerTest : SysuiTestCase() { } @Test - fun addPanelExpansionListener_listenerNotifiedOfCurrentValues() { + fun addExpansionListener_listenerNotifiedOfCurrentValues() { val fraction = 0.6f val expanded = true val tracking = true panelExpansionStateManager.onPanelExpansionChanged(fraction, expanded, tracking) val listener = TestPanelExpansionListener() - panelExpansionStateManager.addListener(listener) + panelExpansionStateManager.addExpansionListener(listener) assertThat(listener.fraction).isEqualTo(fraction) assertThat(listener.expanded).isEqualTo(expanded) assertThat(listener.tracking).isEqualTo(tracking) } + @Test + fun updateState_listenerNotified() { + val listener = TestPanelStateListener() + panelExpansionStateManager.addStateListener(listener) + + panelExpansionStateManager.updateState(STATE_OPEN) + + assertThat(listener.state).isEqualTo(STATE_OPEN) + } + + /* ***** [PanelExpansionStateManager.onPanelExpansionChanged] test cases *******/ + + /* Fraction < 1 test cases */ + + @Test + fun onPEC_fractionLessThanOne_expandedTrue_trackingFalse_becomesStateOpening() { + val listener = TestPanelStateListener() + panelExpansionStateManager.addStateListener(listener) + + panelExpansionStateManager.onPanelExpansionChanged( + fraction = 0.5f, expanded = true, tracking = false + ) + + assertThat(listener.state).isEqualTo(STATE_OPENING) + } + + @Test + fun onPEC_fractionLessThanOne_expandedTrue_trackingTrue_becomesStateOpening() { + val listener = TestPanelStateListener() + panelExpansionStateManager.addStateListener(listener) + + panelExpansionStateManager.onPanelExpansionChanged( + fraction = 0.5f, expanded = true, tracking = true + ) + + assertThat(listener.state).isEqualTo(STATE_OPENING) + } + + @Test + fun onPEC_fractionLessThanOne_expandedFalse_trackingFalse_becomesStateClosed() { + val listener = TestPanelStateListener() + panelExpansionStateManager.addStateListener(listener) + // Start out on a different state + panelExpansionStateManager.updateState(STATE_OPEN) + + panelExpansionStateManager.onPanelExpansionChanged( + fraction = 0.5f, expanded = false, tracking = false + ) + + assertThat(listener.state).isEqualTo(STATE_CLOSED) + } + + @Test + fun onPEC_fractionLessThanOne_expandedFalse_trackingTrue_doesNotBecomeStateClosed() { + val listener = TestPanelStateListener() + panelExpansionStateManager.addStateListener(listener) + // Start out on a different state + panelExpansionStateManager.updateState(STATE_OPEN) + + panelExpansionStateManager.onPanelExpansionChanged( + fraction = 0.5f, expanded = false, tracking = true + ) + + assertThat(listener.state).isEqualTo(STATE_OPEN) + } + + /* Fraction = 1 test cases */ + + @Test + fun onPEC_fractionOne_expandedTrue_trackingFalse_becomesStateOpeningThenStateOpen() { + val listener = TestPanelStateListener() + panelExpansionStateManager.addStateListener(listener) + + panelExpansionStateManager.onPanelExpansionChanged( + fraction = 1f, expanded = true, tracking = false + ) + + assertThat(listener.previousState).isEqualTo(STATE_OPENING) + assertThat(listener.state).isEqualTo(STATE_OPEN) + } + + @Test + fun onPEC_fractionOne_expandedTrue_trackingTrue_becomesStateOpening() { + val listener = TestPanelStateListener() + panelExpansionStateManager.addStateListener(listener) + + panelExpansionStateManager.onPanelExpansionChanged( + fraction = 1f, expanded = true, tracking = true + ) + + assertThat(listener.state).isEqualTo(STATE_OPENING) + } + + @Test + fun onPEC_fractionOne_expandedFalse_trackingFalse_becomesStateClosed() { + val listener = TestPanelStateListener() + panelExpansionStateManager.addStateListener(listener) + // Start out on a different state + panelExpansionStateManager.updateState(STATE_OPEN) + + panelExpansionStateManager.onPanelExpansionChanged( + fraction = 1f, expanded = false, tracking = false + ) + + assertThat(listener.state).isEqualTo(STATE_CLOSED) + } + + @Test + fun onPEC_fractionOne_expandedFalse_trackingTrue_doesNotBecomeStateClosed() { + val listener = TestPanelStateListener() + panelExpansionStateManager.addStateListener(listener) + // Start out on a different state + panelExpansionStateManager.updateState(STATE_OPEN) + + panelExpansionStateManager.onPanelExpansionChanged( + fraction = 1f, expanded = false, tracking = true + ) + + assertThat(listener.state).isEqualTo(STATE_OPEN) + } + + /* ***** end [PanelExpansionStateManager.onPanelExpansionChanged] test cases ******/ + class TestPanelExpansionListener : PanelExpansionListener { var fraction: Float = 0f var expanded: Boolean = false @@ -77,4 +200,14 @@ class PanelExpansionStateManagerTest : SysuiTestCase() { this.tracking = tracking } } + + class TestPanelStateListener : PanelStateListener { + @PanelState var previousState: Int = STATE_CLOSED + @PanelState var state: Int = STATE_CLOSED + + override fun onPanelStateChanged(state: Int) { + this.previousState = this.state + this.state = state + } + } }