diff options
Diffstat (limited to 'packages/SystemUI/src')
34 files changed, 700 insertions, 376 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java index fc29f5cddb26..2f103940f3e4 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java @@ -57,27 +57,27 @@ public interface KeyguardViewController { /** * Called when the device started going to sleep. */ - void onStartedGoingToSleep(); + default void onStartedGoingToSleep() {}; /** * Called when the device has finished going to sleep. */ - void onFinishedGoingToSleep(); + default void onFinishedGoingToSleep() {}; /** * Called when the device started waking up. */ - void onStartedWakingUp(); + default void onStartedWakingUp() {}; /** * Called when the device started turning on. */ - void onScreenTurningOn(); + default void onScreenTurningOn() {}; /** * Called when the device has finished turning on. */ - void onScreenTurnedOn(); + default void onScreenTurnedOn() {}; /** * Sets whether the Keyguard needs input. diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java index cc4ee89f2208..f6368c466e91 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java @@ -109,7 +109,7 @@ public class AssistManager { protected static final String CONSTRAINED_KEY = "should_constrain"; public static final int INVOCATION_TYPE_GESTURE = 1; - public static final int INVOCATION_TYPE_ACTIVE_EDGE = 2; + public static final int INVOCATION_TYPE_OTHER = 2; public static final int INVOCATION_TYPE_VOICE = 3; public static final int INVOCATION_TYPE_QUICK_SEARCH_BAR = 4; public static final int INVOCATION_HOME_BUTTON_LONG_PRESS = 5; diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index 5c66462f2a5b..496456deccee 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -125,6 +125,7 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList // Custom options so there is no activity transition animation ActivityOptions options = ActivityOptions.makeCustomAnimation(getContext(), 0 /* enterResId */, 0 /* exitResId */); + options.setTaskAlwaysOnTop(true); // Post to keep the lifecycle normal post(() -> { if (DEBUG_BUBBLE_EXPANDED_VIEW) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index fee33dcd7677..6a7b0da0d8d8 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -1441,7 +1441,7 @@ public class BubbleStackView extends FrameLayout { /** Expands the clicked bubble. */ public void expandBubble(Bubble bubble) { - if (bubble.equals(mBubbleData.getSelectedBubble())) { + if (bubble != null && bubble.equals(mBubbleData.getSelectedBubble())) { // If the bubble we're supposed to expand is the selected bubble, that means the // overflow bubble is currently expanded. Don't tell BubbleData to set this bubble as // selected, since it already is. Just call the stack's setSelectedBubble to expand it. diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTaskView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTaskView.java index 0d6d137491a9..06205c5c1c41 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTaskView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTaskView.java @@ -23,8 +23,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityOptions; import android.app.PendingIntent; -import android.app.TaskEmbedder; -import android.app.TaskOrganizerTaskEmbedder; +import android.window.TaskEmbedder; +import android.window.TaskOrganizerTaskEmbedder; import android.content.Context; import android.content.Intent; import android.content.pm.ShortcutInfo; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java index 3bed3384c91f..f7f9afdd2928 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java @@ -16,6 +16,9 @@ package com.android.systemui.doze; +import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE; +import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING; + import android.annotation.MainThread; import android.hardware.display.AmbientDisplayConfiguration; import android.os.Trace; @@ -368,8 +371,8 @@ public class DozeMachine { case DOZE_PULSE_DONE: final State nextState; @Wakefulness int wakefulness = mWakefulnessLifecycle.getWakefulness(); - if (wakefulness == WakefulnessLifecycle.WAKEFULNESS_AWAKE - || wakefulness == WakefulnessLifecycle.WAKEFULNESS_WAKING) { + if (state != State.INITIALIZED && (wakefulness == WAKEFULNESS_AWAKE + || wakefulness == WAKEFULNESS_WAKING)) { nextState = State.FINISH; } else if (mDockManager.isDocked()) { nextState = mDockManager.isHidden() ? State.DOZE : State.DOZE_AOD_DOCKED; diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java index c40e9c08d44f..15c9dbad1680 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java @@ -41,8 +41,8 @@ import android.os.RemoteException; import android.util.Log; import android.util.Size; import android.view.SurfaceControl; -import android.window.ITaskOrganizer; -import android.window.IWindowContainer; +import android.window.TaskOrganizer; +import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import android.window.WindowOrganizer; @@ -60,7 +60,7 @@ import java.util.function.Consumer; /** * Manages PiP tasks such as resize and offset. * - * This class listens on {@link ITaskOrganizer} callbacks for windowing mode change + * This class listens on {@link TaskOrganizer} callbacks for windowing mode change * both to and from PiP and issues corresponding animation if applicable. * Normally, we apply series of {@link SurfaceControl.Transaction} when the animator is running * and files a final {@link WindowContainerTransaction} at the end of the transition. @@ -68,7 +68,7 @@ import java.util.function.Consumer; * This class is also responsible for general resize/offset PiP operations within SysUI component, * see also {@link com.android.systemui.pip.phone.PipMotionHelper}. */ -public class PipTaskOrganizer extends ITaskOrganizer.Stub { +public class PipTaskOrganizer extends TaskOrganizer { private static final String TAG = PipTaskOrganizer.class.getSimpleName(); private static final int MSG_RESIZE_IMMEDIATE = 1; @@ -182,7 +182,7 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { }; private ActivityManager.RunningTaskInfo mTaskInfo; - private IWindowContainer mToken; + private WindowContainerToken mToken; private SurfaceControl mLeash; private boolean mInPip; private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS; @@ -234,13 +234,9 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { * @param animationDurationMs duration in millisecond for the exiting PiP transition */ public void dismissPip(int animationDurationMs) { - try { - final WindowContainerTransaction wct = new WindowContainerTransaction(); - wct.setActivityWindowingMode(mToken, WINDOWING_MODE_FULLSCREEN); - WindowOrganizer.applyTransaction(wct); - } catch (RemoteException e) { - Log.e(TAG, "Failed to apply container transaction", e); - } + final WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.setActivityWindowingMode(mToken, WINDOWING_MODE_FULLSCREEN); + WindowOrganizer.applyTransaction(wct); final Rect destinationBounds = mBoundsToRestore.remove(mToken.asBinder()); scheduleAnimateResizePip(mLastReportedBounds, destinationBounds, TRANSITION_DIRECTION_TO_FULLSCREEN, animationDurationMs, @@ -258,11 +254,8 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { mTaskInfo = info; mToken = mTaskInfo.token; mInPip = true; - try { - mLeash = mToken.getLeash(); - } catch (RemoteException e) { - throw new RuntimeException("Unable to get leash", e); - } + mLeash = mToken.getLeash(); + final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds(); mBoundsToRestore.put(mToken.asBinder(), currentBounds); if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) { @@ -290,8 +283,8 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { */ @Override public void onTaskVanished(ActivityManager.RunningTaskInfo info) { - IWindowContainer token = info.token; - Objects.requireNonNull(token, "Requires valid IWindowContainer"); + WindowContainerToken token = info.token; + Objects.requireNonNull(token, "Requires valid WindowContainerToken"); if (token.asBinder() != mToken.asBinder()) { Log.wtf(TAG, "Unrecognized token: " + token); return; @@ -502,30 +495,26 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { + "directly"); } mLastReportedBounds.set(destinationBounds); - try { - final WindowContainerTransaction wct = new WindowContainerTransaction(); - final Rect taskBounds; - if (direction == TRANSITION_DIRECTION_TO_FULLSCREEN) { - // If we are animating to fullscreen, then we need to reset the override bounds - // on the task to ensure that the task "matches" the parent's bounds, this applies - // also to the final windowing mode, which should be reset to undefined rather than - // fullscreen. - taskBounds = null; - wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED) - .setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED); - } else { - taskBounds = destinationBounds; - } - if (direction == TRANSITION_DIRECTION_TO_PIP) { - wct.scheduleFinishEnterPip(mToken, taskBounds); - } else { - wct.setBounds(mToken, taskBounds); - } - wct.setBoundsChangeTransaction(mToken, tx); - WindowOrganizer.applyTransaction(wct); - } catch (RemoteException e) { - Log.e(TAG, "Failed to apply container transaction", e); + final WindowContainerTransaction wct = new WindowContainerTransaction(); + final Rect taskBounds; + if (direction == TRANSITION_DIRECTION_TO_FULLSCREEN) { + // If we are animating to fullscreen, then we need to reset the override bounds + // on the task to ensure that the task "matches" the parent's bounds, this applies + // also to the final windowing mode, which should be reset to undefined rather than + // fullscreen. + taskBounds = null; + wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED) + .setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED); + } else { + taskBounds = destinationBounds; + } + if (direction == TRANSITION_DIRECTION_TO_PIP) { + wct.scheduleFinishEnterPip(mToken, taskBounds); + } else { + wct.setBounds(mToken, taskBounds); } + wct.setBoundsChangeTransaction(mToken, tx); + WindowOrganizer.applyTransaction(wct); } private void animateResizePip(Rect currentBounds, Rect destinationBounds, diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index 8a25f4d441d3..99d6df517224 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -18,7 +18,6 @@ package com.android.systemui.pip.phone; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; -import static android.window.WindowOrganizer.TaskOrganizer; import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN; @@ -234,7 +233,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mPipBoundsHandler.onDisplayInfoChanged(displayInfo); try { - TaskOrganizer.registerOrganizer(mPipTaskOrganizer, WINDOWING_MODE_PINNED); + mPipTaskOrganizer.registerOrganizer(WINDOWING_MODE_PINNED); ActivityManager.StackInfo stackInfo = activityTaskManager.getStackInfo( WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED); if (stackInfo != null) { diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index c6e6da16652f..52c8960d1ccf 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -19,7 +19,6 @@ package com.android.systemui.pip.tv; import static android.app.ActivityTaskManager.INVALID_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; -import static android.window.WindowOrganizer.TaskOrganizer; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.StackInfo; @@ -294,7 +293,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio try { WindowManagerWrapper.getInstance().addPinnedStackListener(mPinnedStackListener); - TaskOrganizer.registerOrganizer(mPipTaskOrganizer, WINDOWING_MODE_PINNED); + mPipTaskOrganizer.registerOrganizer(WINDOWING_MODE_PINNED); } catch (RemoteException | UnsupportedOperationException e) { Log.e(TAG, "Failed to register pinned stack listener", e); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt index f710f7fc47e2..448531a132df 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt @@ -25,13 +25,18 @@ import com.android.systemui.qs.TileLayout.exactly class DoubleLineTileLayout(context: Context) : ViewGroup(context), QSPanel.QSTileLayout { + companion object { + private const val NUM_LINES = 2 + } + protected val mRecords = ArrayList<QSPanel.TileRecord>() private var _listening = false private var smallTileSize = 0 private val twoLineHeight - get() = smallTileSize * 2 + cellMarginVertical + get() = smallTileSize * NUM_LINES + cellMarginVertical * (NUM_LINES - 1) private var cellMarginHorizontal = 0 private var cellMarginVertical = 0 + private var tilesToShow = 0 init { isFocusableInTouchMode = true @@ -68,7 +73,7 @@ class DoubleLineTileLayout(context: Context) : ViewGroup(context), QSPanel.QSTil override fun updateResources(): Boolean { with(mContext.resources) { smallTileSize = getDimensionPixelSize(R.dimen.qs_quick_tile_size) - cellMarginHorizontal = getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal) + cellMarginHorizontal = getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal_two_line) cellMarginVertical = getDimensionPixelSize(R.dimen.new_qs_vertical_margin) } requestLayout() @@ -83,11 +88,12 @@ class DoubleLineTileLayout(context: Context) : ViewGroup(context), QSPanel.QSTil } } - override fun getNumVisibleTiles() = mRecords.size + override fun getNumVisibleTiles() = tilesToShow override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) updateResources() + postInvalidate() } override fun onFinishInflate() { @@ -95,39 +101,58 @@ class DoubleLineTileLayout(context: Context) : ViewGroup(context), QSPanel.QSTil } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { - var previousView: View = this - var tiles = 0 mRecords.forEach { - val tileView = it.tileView - if (tileView.visibility != View.GONE) { - tileView.updateAccessibilityOrder(previousView) - previousView = tileView - tiles++ - tileView.measure(exactly(smallTileSize), exactly(smallTileSize)) - } + it.tileView.measure(exactly(smallTileSize), exactly(smallTileSize)) } val height = twoLineHeight - val columns = tiles / 2 - val width = paddingStart + paddingEnd + - columns * smallTileSize + - (columns - 1) * cellMarginHorizontal - setMeasuredDimension(width, height) + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height) + } + + private fun calculateMaxColumns(availableWidth: Int): Int { + if (smallTileSize + cellMarginHorizontal == 0) { + return 0 + } else { + return (availableWidth - smallTileSize) / (smallTileSize + cellMarginHorizontal) + 1 + } } override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { - val tiles = mRecords.filter { it.tileView.visibility != View.GONE } - tiles.forEachIndexed { - index, tile -> - val column = index % (tiles.size / 2) - val left = getLeftForColumn(column) - val top = if (index < tiles.size / 2) 0 else getTopBottomRow() - tile.tileView.layout(left, top, left + smallTileSize, top + smallTileSize) + val availableWidth = r - l - paddingLeft - paddingRight + val maxColumns = calculateMaxColumns(availableWidth) + val actualColumns = Math.min(maxColumns, mRecords.size / NUM_LINES) + if (actualColumns == 0) { + // No tileSize or horizontal margin + return + } + tilesToShow = actualColumns * NUM_LINES + + val interTileSpace = if (actualColumns <= 2) { + // Extra "column" of padding to be distributed on each end + (availableWidth - actualColumns * smallTileSize) / actualColumns + } else { + (availableWidth - actualColumns * smallTileSize) / (actualColumns - 1) + } + + for (index in 0 until mRecords.size) { + val tileView = mRecords[index].tileView + if (index >= tilesToShow) { + tileView.visibility = View.GONE + } else { + tileView.visibility = View.VISIBLE + if (index > 0) tileView.updateAccessibilityOrder(mRecords[index - 1].tileView) + val column = index % actualColumns + val left = getLeftForColumn(column, interTileSpace, actualColumns <= 2) + val top = if (index < actualColumns) 0 else getTopBottomRow() + tileView.layout(left, top, left + smallTileSize, top + smallTileSize) + } } } - private fun getLeftForColumn(column: Int) = column * (smallTileSize + cellMarginHorizontal) + private fun getLeftForColumn(column: Int, interSpace: Int, sideMargin: Boolean): Int { + return (if (sideMargin) interSpace / 2 else 0) + column * (smallTileSize + interSpace) + } private fun getTopBottomRow() = smallTileSize + cellMarginVertical }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java index 66e321145701..b71c4ebb5930 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java @@ -20,7 +20,6 @@ import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED; import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED; import static android.view.Display.DEFAULT_DISPLAY; -import static android.window.WindowOrganizer.TaskOrganizer; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -33,11 +32,12 @@ import android.os.Handler; import android.os.RemoteException; import android.provider.Settings; import android.util.Slog; +import android.window.TaskOrganizer; +import android.window.WindowContainerToken; import android.view.LayoutInflater; import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.View; -import android.window.IWindowContainer; import android.window.WindowContainerTransaction; import android.window.WindowOrganizer; @@ -181,14 +181,9 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks, private boolean mPausedTargetAdjusted = false; private boolean getSecondaryHasFocus(int displayId) { - try { - IWindowContainer imeSplit = TaskOrganizer.getImeTarget(displayId); - return imeSplit != null - && (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder()); - } catch (RemoteException e) { - Slog.w(TAG, "Failed to get IME target", e); - } - return false; + WindowContainerToken imeSplit = TaskOrganizer.getImeTarget(displayId); + return imeSplit != null + && (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder()); } private void updateDimTargets() { @@ -270,10 +265,8 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks, wct.setScreenSizeDp(mSplits.mSecondary.token, SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED); } - try { - WindowOrganizer.applyTransaction(wct); - } catch (RemoteException e) { - } + + WindowOrganizer.applyTransaction(wct); // Update all the adjusted-for-ime states if (!mPaused) { @@ -506,12 +499,8 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks, int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position; final WindowContainerTransaction tct = new WindowContainerTransaction(); mSplitLayout.resizeSplits(midPos, tct); - try { - WindowOrganizer.applyTransaction(tct); - } catch (RemoteException e) { - } - } else if (mRotateSplitLayout != null - && mSplitLayout.mDisplayLayout.rotation() + WindowOrganizer.applyTransaction(tct); + } else if (mSplitLayout.mDisplayLayout.rotation() == mRotateSplitLayout.mDisplayLayout.rotation()) { mSplitLayout.mPrimary = new Rect(mRotateSplitLayout.mPrimary); mSplitLayout.mSecondary = new Rect(mRotateSplitLayout.mSecondary); @@ -653,7 +642,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks, } } updateTouchable(); - WindowManagerProxy.applyContainerTransaction(wct); + WindowOrganizer.applyTransaction(wct); } void setAdjustedForIme(boolean adjustedForIme) { diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java index a6f67412fa50..91d638e70677 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java @@ -22,7 +22,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.view.Display.DEFAULT_DISPLAY; -import static android.window.WindowOrganizer.TaskOrganizer; import android.app.ActivityManager.RunningTaskInfo; import android.app.WindowConfiguration; @@ -32,11 +31,11 @@ import android.util.Log; import android.view.Display; import android.view.SurfaceControl; import android.view.SurfaceSession; -import android.window.ITaskOrganizer; +import android.window.TaskOrganizer; import java.util.ArrayList; -class SplitScreenTaskOrganizer extends ITaskOrganizer.Stub { +class SplitScreenTaskOrganizer extends TaskOrganizer { private static final String TAG = "SplitScreenTaskOrganizer"; private static final boolean DEBUG = Divider.DEBUG; @@ -56,8 +55,8 @@ class SplitScreenTaskOrganizer extends ITaskOrganizer.Stub { } void init(SurfaceSession session) throws RemoteException { - TaskOrganizer.registerOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); - TaskOrganizer.registerOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); + registerOrganizer(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + registerOrganizer(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); try { mPrimary = TaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY, WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); @@ -65,9 +64,9 @@ class SplitScreenTaskOrganizer extends ITaskOrganizer.Stub { WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); mPrimarySurface = mPrimary.token.getLeash(); mSecondarySurface = mSecondary.token.getLeash(); - } catch (RemoteException e) { + } catch (Exception e) { // teardown to prevent callbacks - TaskOrganizer.unregisterOrganizer(this); + unregisterOrganizer(); throw e; } mSplitScreenSupported = true; @@ -99,14 +98,6 @@ class SplitScreenTaskOrganizer extends ITaskOrganizer.Stub { } @Override - public void onTaskAppeared(RunningTaskInfo taskInfo) { - } - - @Override - public void onTaskVanished(RunningTaskInfo taskInfo) { - } - - @Override public void onTaskInfoChanged(RunningTaskInfo taskInfo) { if (taskInfo.displayId != DEFAULT_DISPLAY) { return; diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java index 6ed7afe152df..85dcbb6316d0 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java @@ -20,7 +20,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.Display.DEFAULT_DISPLAY; -import static android.window.WindowOrganizer.TaskOrganizer; import android.annotation.NonNull; import android.app.ActivityManager; @@ -30,7 +29,8 @@ import android.os.RemoteException; import android.util.Log; import android.view.Display; import android.view.WindowManagerGlobal; -import android.window.IWindowContainer; +import android.window.TaskOrganizer; +import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import android.window.WindowOrganizer; @@ -112,27 +112,21 @@ public class WindowManagerProxy { static void applyResizeSplits(int position, SplitDisplayLayout splitLayout) { WindowContainerTransaction t = new WindowContainerTransaction(); splitLayout.resizeSplits(position, t); - try { - WindowOrganizer.applyTransaction(t); - } catch (RemoteException e) { - } + WindowOrganizer.applyTransaction(t); } - private static boolean getHomeAndRecentsTasks(List<IWindowContainer> out, - IWindowContainer parent) { + private static boolean getHomeAndRecentsTasks(List<WindowContainerToken> out, + WindowContainerToken parent) { boolean resizable = false; - try { - List<ActivityManager.RunningTaskInfo> rootTasks = parent == null - ? TaskOrganizer.getRootTasks(Display.DEFAULT_DISPLAY, HOME_AND_RECENTS) - : TaskOrganizer.getChildTasks(parent, HOME_AND_RECENTS); - for (int i = 0, n = rootTasks.size(); i < n; ++i) { - final ActivityManager.RunningTaskInfo ti = rootTasks.get(i); - out.add(ti.token); - if (ti.topActivityType == ACTIVITY_TYPE_HOME) { - resizable = ti.isResizable(); - } + List<ActivityManager.RunningTaskInfo> rootTasks = parent == null + ? TaskOrganizer.getRootTasks(Display.DEFAULT_DISPLAY, HOME_AND_RECENTS) + : TaskOrganizer.getChildTasks(parent, HOME_AND_RECENTS); + for (int i = 0, n = rootTasks.size(); i < n; ++i) { + final ActivityManager.RunningTaskInfo ti = rootTasks.get(i); + out.add(ti.token); + if (ti.topActivityType == ACTIVITY_TYPE_HOME) { + resizable = ti.isResizable(); } - } catch (RemoteException e) { } return resizable; } @@ -142,11 +136,11 @@ public class WindowManagerProxy { * split is minimized. This actually "sticks out" of the secondary split area, but when in * minimized mode, the secondary split gets a 'negative' crop to expose it. */ - static boolean applyHomeTasksMinimized(SplitDisplayLayout layout, IWindowContainer parent, + static boolean applyHomeTasksMinimized(SplitDisplayLayout layout, WindowContainerToken parent, @NonNull WindowContainerTransaction wct) { // Resize the home/recents stacks to the larger minimized-state size final Rect homeBounds; - final ArrayList<IWindowContainer> homeStacks = new ArrayList<>(); + final ArrayList<WindowContainerToken> homeStacks = new ArrayList<>(); boolean isHomeResizable = getHomeAndRecentsTasks(homeStacks, parent); if (isHomeResizable) { homeBounds = layout.calcMinimizedHomeStackBounds(); @@ -170,36 +164,31 @@ public class WindowManagerProxy { * @return whether the home stack is resizable */ static boolean applyEnterSplit(SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout) { - try { - // Set launchtile first so that any stack created after - // getAllStackInfos and before reparent (even if unlikely) are placed - // correctly. - TaskOrganizer.setLaunchRoot(DEFAULT_DISPLAY, tiles.mSecondary.token); - List<ActivityManager.RunningTaskInfo> rootTasks = - TaskOrganizer.getRootTasks(DEFAULT_DISPLAY, null /* activityTypes */); - WindowContainerTransaction wct = new WindowContainerTransaction(); - if (rootTasks.isEmpty()) { - return false; + // Set launchtile first so that any stack created after + // getAllStackInfos and before reparent (even if unlikely) are placed + // correctly. + TaskOrganizer.setLaunchRoot(DEFAULT_DISPLAY, tiles.mSecondary.token); + List<ActivityManager.RunningTaskInfo> rootTasks = + TaskOrganizer.getRootTasks(DEFAULT_DISPLAY, null /* activityTypes */); + WindowContainerTransaction wct = new WindowContainerTransaction(); + if (rootTasks.isEmpty()) { + return false; + } + tiles.mHomeAndRecentsSurfaces.clear(); + for (int i = rootTasks.size() - 1; i >= 0; --i) { + final ActivityManager.RunningTaskInfo rootTask = rootTasks.get(i); + if (isHomeOrRecentTask(rootTask)) { + tiles.mHomeAndRecentsSurfaces.add(rootTask.token.getLeash()); } - tiles.mHomeAndRecentsSurfaces.clear(); - for (int i = rootTasks.size() - 1; i >= 0; --i) { - final ActivityManager.RunningTaskInfo rootTask = rootTasks.get(i); - if (isHomeOrRecentTask(rootTask)) { - tiles.mHomeAndRecentsSurfaces.add(rootTask.token.getLeash()); - } - if (rootTask.configuration.windowConfiguration.getWindowingMode() - != WINDOWING_MODE_FULLSCREEN) { - continue; - } - wct.reparent(rootTask.token, tiles.mSecondary.token, true /* onTop */); + if (rootTask.configuration.windowConfiguration.getWindowingMode() + != WINDOWING_MODE_FULLSCREEN) { + continue; } - boolean isHomeResizable = applyHomeTasksMinimized(layout, null /* parent */, wct); - WindowOrganizer.applyTransaction(wct); - return isHomeResizable; - } catch (RemoteException e) { - Log.w(TAG, "Error moving fullscreen tasks to secondary split: " + e); + wct.reparent(rootTask.token, tiles.mSecondary.token, true /* onTop */); } - return false; + boolean isHomeResizable = applyHomeTasksMinimized(layout, null /* parent */, wct); + WindowOrganizer.applyTransaction(wct); + return isHomeResizable; } private static boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) { @@ -214,82 +203,70 @@ public class WindowManagerProxy { * fullscreen. {@code false} resolves the other way. */ static void applyDismissSplit(SplitScreenTaskOrganizer tiles, boolean dismissOrMaximize) { - try { - // Set launch root first so that any task created after getChildContainers and - // before reparent (pretty unlikely) are put into fullscreen. - TaskOrganizer.setLaunchRoot(Display.DEFAULT_DISPLAY, null); - tiles.mHomeAndRecentsSurfaces.clear(); - // TODO(task-org): Once task-org is more complete, consider using Appeared/Vanished - // plus specific APIs to clean this up. - List<ActivityManager.RunningTaskInfo> primaryChildren = - TaskOrganizer.getChildTasks(tiles.mPrimary.token, null /* activityTypes */); - List<ActivityManager.RunningTaskInfo> secondaryChildren = - TaskOrganizer.getChildTasks(tiles.mSecondary.token, null /* activityTypes */); - // In some cases (eg. non-resizable is launched), system-server will leave split-screen. - // as a result, the above will not capture any tasks; yet, we need to clean-up the - // home task bounds. - List<ActivityManager.RunningTaskInfo> freeHomeAndRecents = - TaskOrganizer.getRootTasks(Display.DEFAULT_DISPLAY, HOME_AND_RECENTS); - if (primaryChildren.isEmpty() && secondaryChildren.isEmpty() - && freeHomeAndRecents.isEmpty()) { - return; + // Set launch root first so that any task created after getChildContainers and + // before reparent (pretty unlikely) are put into fullscreen. + TaskOrganizer.setLaunchRoot(Display.DEFAULT_DISPLAY, null); + tiles.mHomeAndRecentsSurfaces.clear(); + // TODO(task-org): Once task-org is more complete, consider using Appeared/Vanished + // plus specific APIs to clean this up. + List<ActivityManager.RunningTaskInfo> primaryChildren = + TaskOrganizer.getChildTasks(tiles.mPrimary.token, null /* activityTypes */); + List<ActivityManager.RunningTaskInfo> secondaryChildren = + TaskOrganizer.getChildTasks(tiles.mSecondary.token, null /* activityTypes */); + // In some cases (eg. non-resizable is launched), system-server will leave split-screen. + // as a result, the above will not capture any tasks; yet, we need to clean-up the + // home task bounds. + List<ActivityManager.RunningTaskInfo> freeHomeAndRecents = + TaskOrganizer.getRootTasks(Display.DEFAULT_DISPLAY, HOME_AND_RECENTS); + if (primaryChildren.isEmpty() && secondaryChildren.isEmpty() + && freeHomeAndRecents.isEmpty()) { + return; + } + WindowContainerTransaction wct = new WindowContainerTransaction(); + if (dismissOrMaximize) { + // Dismissing, so move all primary split tasks first + for (int i = primaryChildren.size() - 1; i >= 0; --i) { + wct.reparent(primaryChildren.get(i).token, null /* parent */, + true /* onTop */); } - WindowContainerTransaction wct = new WindowContainerTransaction(); - if (dismissOrMaximize) { - // Dismissing, so move all primary split tasks first - for (int i = primaryChildren.size() - 1; i >= 0; --i) { - wct.reparent(primaryChildren.get(i).token, null /* parent */, - true /* onTop */); - } - // Don't need to worry about home tasks because they are already in the "proper" - // order within the secondary split. - for (int i = secondaryChildren.size() - 1; i >= 0; --i) { - final ActivityManager.RunningTaskInfo ti = secondaryChildren.get(i); - wct.reparent(ti.token, null /* parent */, true /* onTop */); - if (isHomeOrRecentTask(ti)) { - wct.setBounds(ti.token, null); - } - } - } else { - // Maximize, so move non-home secondary split first - for (int i = secondaryChildren.size() - 1; i >= 0; --i) { - if (isHomeOrRecentTask(secondaryChildren.get(i))) { - continue; - } - wct.reparent(secondaryChildren.get(i).token, null /* parent */, - true /* onTop */); + // Don't need to worry about home tasks because they are already in the "proper" + // order within the secondary split. + for (int i = secondaryChildren.size() - 1; i >= 0; --i) { + final ActivityManager.RunningTaskInfo ti = secondaryChildren.get(i); + wct.reparent(ti.token, null /* parent */, true /* onTop */); + if (isHomeOrRecentTask(ti)) { + wct.setBounds(ti.token, null); } - // Find and place home tasks in-between. This simulates the fact that there was - // nothing behind the primary split's tasks. - for (int i = secondaryChildren.size() - 1; i >= 0; --i) { - final ActivityManager.RunningTaskInfo ti = secondaryChildren.get(i); - if (isHomeOrRecentTask(ti)) { - wct.reparent(ti.token, null /* parent */, true /* onTop */); - // reset bounds too - wct.setBounds(ti.token, null); - } + } + } else { + // Maximize, so move non-home secondary split first + for (int i = secondaryChildren.size() - 1; i >= 0; --i) { + if (isHomeOrRecentTask(secondaryChildren.get(i))) { + continue; } - for (int i = primaryChildren.size() - 1; i >= 0; --i) { - wct.reparent(primaryChildren.get(i).token, null /* parent */, - true /* onTop */); + wct.reparent(secondaryChildren.get(i).token, null /* parent */, + true /* onTop */); + } + // Find and place home tasks in-between. This simulates the fact that there was + // nothing behind the primary split's tasks. + for (int i = secondaryChildren.size() - 1; i >= 0; --i) { + final ActivityManager.RunningTaskInfo ti = secondaryChildren.get(i); + if (isHomeOrRecentTask(ti)) { + wct.reparent(ti.token, null /* parent */, true /* onTop */); + // reset bounds too + wct.setBounds(ti.token, null); } } - for (int i = freeHomeAndRecents.size() - 1; i >= 0; --i) { - wct.setBounds(freeHomeAndRecents.get(i).token, null); + for (int i = primaryChildren.size() - 1; i >= 0; --i) { + wct.reparent(primaryChildren.get(i).token, null /* parent */, + true /* onTop */); } - // Reset focusable to true - wct.setFocusable(tiles.mPrimary.token, true /* focusable */); - WindowOrganizer.applyTransaction(wct); - } catch (RemoteException e) { - Log.w(TAG, "Failed to remove stack: " + e); } - } - - static void applyContainerTransaction(WindowContainerTransaction wct) { - try { - WindowOrganizer.applyTransaction(wct); - } catch (RemoteException e) { - Log.w(TAG, "Error setting focusability: " + e); + for (int i = freeHomeAndRecents.size() - 1; i >= 0; --i) { + wct.setBounds(freeHomeAndRecents.get(i).token, null); } + // Reset focusable to true + wct.setFocusable(tiles.mPrimary.token, true /* focusable */); + WindowOrganizer.applyTransaction(wct); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt index a978cad1127a..fd44f04a0d80 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt @@ -32,6 +32,7 @@ import com.android.systemui.Dumpable import com.android.systemui.Interpolators import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.statusbar.notification.ActivityLaunchAnimator import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK import com.android.systemui.statusbar.phone.NotificationShadeWindowController @@ -39,7 +40,6 @@ import com.android.systemui.statusbar.phone.PanelExpansionListener import com.android.systemui.statusbar.policy.KeyguardStateController import java.io.FileDescriptor import java.io.PrintWriter -import java.lang.IllegalArgumentException import javax.inject.Inject import javax.inject.Singleton import kotlin.math.max @@ -69,11 +69,41 @@ class NotificationShadeDepthController @Inject constructor( private var notificationAnimator: Animator? = null private var updateScheduled: Boolean = false private var shadeExpansion = 0f + private var ignoreShadeBlurUntilHidden: Boolean = false @VisibleForTesting var shadeSpring = DepthAnimation() @VisibleForTesting var globalActionsSpring = DepthAnimation() + @VisibleForTesting + var brightnessMirrorSpring = DepthAnimation() + var brightnessMirrorVisible: Boolean = false + set(value) { + field = value + brightnessMirrorSpring.animateTo(if (value) blurUtils.blurRadiusOfRatio(1f) + else 0) + } + + /** + * When launching an app from the shade, the animations progress should affect how blurry the + * shade is, overriding the expansion amount. + */ + var notificationLaunchAnimationParams: ActivityLaunchAnimator.ExpandAnimationParameters? = null + set(value) { + field = value + if (value != null) { + scheduleUpdate() + return + } + + if (shadeSpring.radius == 0) { + return + } + ignoreShadeBlurUntilHidden = true + shadeSpring.animateTo(0) + shadeSpring.finishIfRunning() + } + /** * Blur radius of the wake-up animation on this frame. */ @@ -91,7 +121,19 @@ class NotificationShadeDepthController @Inject constructor( val updateBlurCallback = Choreographer.FrameCallback { updateScheduled = false - val blur = max(max(shadeSpring.radius, wakeAndUnlockBlurRadius), globalActionsSpring.radius) + var shadeRadius = max(shadeSpring.radius, wakeAndUnlockBlurRadius).toFloat() + shadeRadius *= 1f - brightnessMirrorSpring.ratio + val launchProgress = notificationLaunchAnimationParams?.linearProgress ?: 0f + shadeRadius *= (1f - launchProgress) * (1f - launchProgress) + + if (ignoreShadeBlurUntilHidden) { + if (shadeRadius == 0f) { + ignoreShadeBlurUntilHidden = false + } else { + shadeRadius = 0f + } + } + val blur = max(shadeRadius.toInt(), globalActionsSpring.radius) blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur) try { wallpaperManager.setWallpaperZoomOut(root.windowToken, @@ -148,6 +190,7 @@ class NotificationShadeDepthController @Inject constructor( if (isDozing) { shadeSpring.finishIfRunning() globalActionsSpring.finishIfRunning() + brightnessMirrorSpring.finishIfRunning() } } } @@ -176,7 +219,6 @@ class NotificationShadeDepthController @Inject constructor( if (statusBarStateController.state == StatusBarState.SHADE) { newBlur = blurUtils.blurRadiusOfRatio(shadeExpansion) } - shadeSpring.animateTo(newBlur) } @@ -199,7 +241,11 @@ class NotificationShadeDepthController @Inject constructor( it.increaseIndent() it.println("shadeRadius: ${shadeSpring.radius}") it.println("globalActionsRadius: ${globalActionsSpring.radius}") + it.println("brightnessMirrorRadius: ${brightnessMirrorSpring.radius}") it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius") + it.println("notificationLaunchAnimationProgress: " + + "${notificationLaunchAnimationParams?.linearProgress}") + it.println("ignoreShadeBlurUntilHidden: $ignoreShadeBlurUntilHidden") } } @@ -212,7 +258,12 @@ class NotificationShadeDepthController @Inject constructor( * Blur radius visible on the UI, in pixels. */ var radius = 0 - private set + + /** + * Depth ratio of the current blur radius. + */ + val ratio + get() = blurUtils.ratioOfBlurRadius(radius) /** * Radius that we're animating to. @@ -239,7 +290,7 @@ class NotificationShadeDepthController @Inject constructor( init { springAnimation.spring = SpringForce(0.0f) springAnimation.spring.dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY - springAnimation.spring.stiffness = SpringForce.STIFFNESS_MEDIUM + springAnimation.spring.stiffness = SpringForce.STIFFNESS_HIGH springAnimation.addEndListener { _, _, _, _ -> pendingRadius = -1 } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java index 564d8bc14c8c..3f74aaf3abf5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java @@ -38,10 +38,12 @@ public class NotificationUiAdjustment { public final String key; public final List<Notification.Action> smartActions; public final List<CharSequence> smartReplies; + public final boolean isConversation; @VisibleForTesting NotificationUiAdjustment( - String key, List<Notification.Action> smartActions, List<CharSequence> smartReplies) { + String key, List<Notification.Action> smartActions, List<CharSequence> smartReplies, + boolean isConversation) { this.key = key; this.smartActions = smartActions == null ? Collections.emptyList() @@ -49,12 +51,14 @@ public class NotificationUiAdjustment { this.smartReplies = smartReplies == null ? Collections.emptyList() : smartReplies; + this.isConversation = isConversation; } public static NotificationUiAdjustment extractFromNotificationEntry( NotificationEntry entry) { return new NotificationUiAdjustment( - entry.getKey(), entry.getSmartActions(), entry.getSmartReplies()); + entry.getKey(), entry.getSmartActions(), entry.getSmartReplies(), + entry.getRanking().isConversation()); } public static boolean needReinflate( @@ -63,6 +67,9 @@ public class NotificationUiAdjustment { if (oldAdjustment == newAdjustment) { return false; } + if (oldAdjustment.isConversation != newAdjustment.isConversation) { + return true; + } if (areDifferent(oldAdjustment.smartActions, newAdjustment.smartActions)) { return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java index 7c061574f19c..6aef6b407f37 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java @@ -34,6 +34,7 @@ import android.view.View; import com.android.internal.policy.ScreenDecorationsUtils; import com.android.systemui.Interpolators; +import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment; @@ -57,6 +58,7 @@ public class ActivityLaunchAnimator { private final NotificationListContainer mNotificationContainer; private final float mWindowCornerRadius; private final NotificationShadeWindowViewController mNotificationShadeWindowViewController; + private final NotificationShadeDepthController mDepthController; private Callback mCallback; private final Runnable mTimeoutRunnable = () -> { setAnimationPending(false); @@ -70,9 +72,11 @@ public class ActivityLaunchAnimator { NotificationShadeWindowViewController notificationShadeWindowViewController, Callback callback, NotificationPanelViewController notificationPanel, + NotificationShadeDepthController depthController, NotificationListContainer container) { mNotificationPanel = notificationPanel; mNotificationContainer = container; + mDepthController = depthController; mNotificationShadeWindowViewController = notificationShadeWindowViewController; mCallback = callback; mWindowCornerRadius = ScreenDecorationsUtils @@ -212,7 +216,7 @@ public class ActivityLaunchAnimator { mWindowCornerRadius, progress); applyParamsToWindow(primary); applyParamsToNotification(mParams); - applyParamsToNotificationList(mParams); + applyParamsToNotificationShade(mParams); } }); anim.addListener(new AnimatorListenerAdapter() { @@ -256,14 +260,15 @@ public class ActivityLaunchAnimator { if (!running) { mCallback.onExpandAnimationFinished(mIsFullScreenLaunch); applyParamsToNotification(null); - applyParamsToNotificationList(null); + applyParamsToNotificationShade(null); } } - private void applyParamsToNotificationList(ExpandAnimationParameters params) { + private void applyParamsToNotificationShade(ExpandAnimationParameters params) { mNotificationContainer.applyExpandAnimationParams(params); mNotificationPanel.applyExpandAnimationParams(params); + mDepthController.setNotificationLaunchAnimationParams(params); } private void applyParamsToNotification(ExpandAnimationParameters params) { @@ -295,7 +300,7 @@ public class ActivityLaunchAnimator { }; public static class ExpandAnimationParameters { - float linearProgress; + public float linearProgress; int[] startPosition; float startTranslationZ; int left; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotificationProcessor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotificationProcessor.kt deleted file mode 100644 index 6be0fff38f2b..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotificationProcessor.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2020 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.app.Notification -import android.content.pm.LauncherApps -import com.android.systemui.statusbar.notification.collection.NotificationEntry -import javax.inject.Inject - -class ConversationNotificationProcessor @Inject constructor( - private val launcherApps: LauncherApps -) { - fun processNotification(entry: NotificationEntry, recoveredBuilder: Notification.Builder) { - val messagingStyle = recoveredBuilder.style as? Notification.MessagingStyle ?: return - messagingStyle.conversationType = - if (entry.ranking.channel.isImportantConversation) - Notification.MessagingStyle.CONVERSATION_TYPE_IMPORTANT - else - Notification.MessagingStyle.CONVERSATION_TYPE_NORMAL - entry.ranking.shortcutInfo?.let { shortcutInfo -> - messagingStyle.shortcutIcon = launcherApps.getShortcutIcon(shortcutInfo) - shortcutInfo.shortLabel?.let { shortLabel -> - messagingStyle.conversationTitle = shortLabel - } - } - } -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt new file mode 100644 index 000000000000..7ef1d0eba3f1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2020 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.app.Notification +import android.content.Context +import android.content.pm.LauncherApps +import android.service.notification.NotificationListenerService.Ranking +import android.service.notification.NotificationListenerService.RankingMap +import com.android.internal.statusbar.NotificationVisibility +import com.android.internal.widget.ConversationLayout +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow +import com.android.systemui.statusbar.notification.row.NotificationContentView +import java.util.concurrent.ConcurrentHashMap +import javax.inject.Inject +import javax.inject.Singleton + +/** Populates additional information in conversation notifications */ +class ConversationNotificationProcessor @Inject constructor( + private val launcherApps: LauncherApps, + private val conversationNotificationManager: ConversationNotificationManager +) { + fun processNotification(entry: NotificationEntry, recoveredBuilder: Notification.Builder) { + val messagingStyle = recoveredBuilder.style as? Notification.MessagingStyle ?: return + messagingStyle.conversationType = + if (entry.ranking.channel.isImportantConversation) + Notification.MessagingStyle.CONVERSATION_TYPE_IMPORTANT + else + Notification.MessagingStyle.CONVERSATION_TYPE_NORMAL + entry.ranking.shortcutInfo?.let { shortcutInfo -> + messagingStyle.shortcutIcon = launcherApps.getShortcutIcon(shortcutInfo) + shortcutInfo.shortLabel?.let { shortLabel -> + messagingStyle.conversationTitle = shortLabel + } + } + messagingStyle.unreadMessageCount = + conversationNotificationManager.getUnreadCount(entry, recoveredBuilder) + } +} + +/** + * Tracks state related to conversation notifications, and updates the UI of existing notifications + * when necessary. + */ +@Singleton +class ConversationNotificationManager @Inject constructor( + private val notificationEntryManager: NotificationEntryManager, + private val context: Context +) { + // Need this state to be thread safe, since it's accessed from the ui thread + // (NotificationEntryListener) and a bg thread (NotificationContentInflater) + private val states = ConcurrentHashMap<String, ConversationState>() + + private var notifPanelCollapsed = true + + init { + notificationEntryManager.addNotificationEntryListener(object : NotificationEntryListener { + + override fun onNotificationRankingUpdated(rankingMap: RankingMap) { + fun getLayouts(view: NotificationContentView) = + sequenceOf(view.contractedChild, view.expandedChild, view.headsUpChild) + val ranking = Ranking() + states.keys.asSequence() + .mapNotNull { notificationEntryManager.getActiveNotificationUnfiltered(it) } + .forEach { entry -> + if (rankingMap.getRanking(entry.sbn.key, ranking) && + ranking.isConversation) { + val important = ranking.channel.isImportantConversation + entry.row?.layouts?.asSequence() + ?.flatMap(::getLayouts) + ?.mapNotNull { it as? ConversationLayout } + ?.forEach { it.setIsImportantConversation(important) } + } + } + } + + override fun onEntryInflated(entry: NotificationEntry) { + if (!entry.ranking.isConversation) return + fun updateCount(isExpanded: Boolean) { + if (isExpanded && !notifPanelCollapsed) { + resetCount(entry.key) + entry.row?.let(::resetBadgeUi) + } + } + entry.row?.setOnExpansionChangedListener(::updateCount) + updateCount(entry.row?.isExpanded == true) + } + + override fun onEntryReinflated(entry: NotificationEntry) = onEntryInflated(entry) + + override fun onEntryRemoved( + entry: NotificationEntry, + visibility: NotificationVisibility?, + removedByUser: Boolean, + reason: Int + ) = removeTrackedEntry(entry) + }) + } + + fun getUnreadCount(entry: NotificationEntry, recoveredBuilder: Notification.Builder): Int = + states.compute(entry.key) { _, state -> + val newCount = state?.run { + val old = Notification.Builder.recoverBuilder(context, notification) + val increment = Notification + .areStyledNotificationsVisiblyDifferent(old, recoveredBuilder) + if (increment) unreadCount + 1 else unreadCount + } ?: 1 + ConversationState(newCount, entry.sbn.notification) + }!!.unreadCount + + fun onNotificationPanelExpandStateChanged(isCollapsed: Boolean) { + notifPanelCollapsed = isCollapsed + if (isCollapsed) return + + // When the notification panel is expanded, reset the counters of any expanded + // conversations + val expanded = states + .asSequence() + .mapNotNull { (key, _) -> + notificationEntryManager.getActiveNotificationUnfiltered(key) + ?.let { entry -> + if (entry.row?.isExpanded == true) key to entry + else null + } + } + .toMap() + states.replaceAll { key, state -> + if (expanded.contains(key)) state.copy(unreadCount = 0) + else state + } + // Update UI separate from the replaceAll call, since ConcurrentHashMap may re-run the + // lambda if threads are in contention. + expanded.values.asSequence().mapNotNull { it.row }.forEach(::resetBadgeUi) + } + + private fun resetCount(key: String) { + states.compute(key) { _, state -> state?.copy(unreadCount = 0) } + } + + private fun removeTrackedEntry(entry: NotificationEntry) { + states.remove(entry.key) + } + + private fun resetBadgeUi(row: ExpandableNotificationRow): Unit = + (row.layouts?.asSequence() ?: emptySequence()) + .mapNotNull { layout -> layout.contractedChild as? ConversationLayout } + .forEach { convoLayout -> convoLayout.setUnreadCount(0) } + + private data class ConversationState(val unreadCount: Int, val notification: Notification) +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java index b90cfa8ae25e..c9cc67009399 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java @@ -249,6 +249,7 @@ public class NotifCollection implements Dumpable { stats.notificationVisibility); } catch (RemoteException e) { // system process is dead if we're here. + mLogger.logRemoteExceptionOnNotificationClear(entry.getKey(), e); } } } @@ -277,6 +278,7 @@ public class NotifCollection implements Dumpable { mStatusBarService.onClearAllNotifications(userId); } catch (RemoteException e) { // system process is dead if we're here. + mLogger.logRemoteExceptionOnClearAllNotifications(e); } final List<NotificationEntry> entries = new ArrayList<>(getAllNotifs()); @@ -743,6 +745,6 @@ public class NotifCollection implements Dumpable { @Retention(RetentionPolicy.SOURCE) public @interface CancellationReason {} - public static final int REASON_NOT_CANCELED = -1; + static final int REASON_NOT_CANCELED = -1; public static final int REASON_UNKNOWN = 0; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt index 8675cca3cffe..ef302f682df8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt @@ -16,11 +16,13 @@ package com.android.systemui.statusbar.notification.collection.notifcollection +import android.os.RemoteException import android.service.notification.NotificationListenerService.RankingMap import com.android.systemui.log.LogBuffer import com.android.systemui.log.LogLevel.DEBUG import com.android.systemui.log.LogLevel.INFO import com.android.systemui.log.LogLevel.WARNING +import com.android.systemui.log.LogLevel.WTF import com.android.systemui.log.dagger.NotificationLog import javax.inject.Inject @@ -92,6 +94,23 @@ class NotifCollectionLogger @Inject constructor( buffer.log(TAG, DEBUG, { str1 = entry }, { " $str1" }) } } + + fun logRemoteExceptionOnNotificationClear(key: String, e: RemoteException) { + buffer.log(TAG, WTF, { + str1 = key + str2 = e.toString() + }, { + "RemoteException while attempting to clear $str1:\n$str2" + }) + } + + fun logRemoteExceptionOnClearAllNotifications(e: RemoteException) { + buffer.log(TAG, WTF, { + str1 = e.toString() + }, { + "RemoteException while attempting to clear all notifications:\n$str1" + }) + } } -private const val TAG = "NotifCollection"
\ No newline at end of file +private const val TAG = "NotifCollection" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 7deabf79a6dd..19b5f5c79ea2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -107,6 +107,7 @@ import com.android.systemui.statusbar.policy.InflatedSmartReplies.SmartRepliesAn import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.function.BooleanSupplier; @@ -136,7 +137,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView */ public interface LayoutListener { void onLayout(); + } + /** Listens for changes to the expansion state of this row. */ + public interface OnExpansionChangedListener { + void onExpansionChanged(boolean isExpanded); } private StatusBarStateController mStatusbarStateController; @@ -323,6 +328,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private boolean mWasChildInGroupWhenRemoved; private NotificationInlineImageResolver mImageResolver; private NotificationMediaManager mMediaManager; + @Nullable private OnExpansionChangedListener mExpansionChangedListener; private SystemNotificationAsyncTask mSystemNotificationAsyncTask = new SystemNotificationAsyncTask(); @@ -351,6 +357,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return isSystemNotification; } + public NotificationContentView[] getLayouts() { + return Arrays.copyOf(mLayouts, mLayouts.length); + } + @Override public boolean isGroupExpansionChanging() { if (isChildInGroup()) { @@ -1659,8 +1669,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } public void showAppOpsIcons(ArraySet<Integer> activeOps) { - if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) { - mChildrenContainer.getHeaderView().showAppOpsIcons(activeOps); + if (mIsSummaryWithChildren) { + mChildrenContainer.showAppOpsIcons(activeOps); } mPrivateLayout.showAppOpsIcons(activeOps); mPublicLayout.showAppOpsIcons(activeOps); @@ -1687,8 +1697,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private final Runnable mExpireRecentlyAlertedFlag = () -> applyAudiblyAlertedRecently(false); private void applyAudiblyAlertedRecently(boolean audiblyAlertedRecently) { - if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) { - mChildrenContainer.getHeaderView().setRecentlyAudiblyAlerted(audiblyAlertedRecently); + if (mIsSummaryWithChildren) { + mChildrenContainer.setRecentlyAudiblyAlerted(audiblyAlertedRecently); } mPrivateLayout.setRecentlyAudiblyAlerted(audiblyAlertedRecently); mPublicLayout.setRecentlyAudiblyAlerted(audiblyAlertedRecently); @@ -2911,9 +2921,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView if (mIsSummaryWithChildren) { mChildrenContainer.onExpansionChanged(); } + if (mExpansionChangedListener != null) { + mExpansionChangedListener.onExpansionChanged(nowExpanded); + } } } + public void setOnExpansionChangedListener(@Nullable OnExpansionChangedListener listener) { + mExpansionChangedListener = listener; + } + @Override public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfoInternal(info); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java index 9b9225e0bde0..8efdc1b56e8e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java @@ -1468,27 +1468,27 @@ public class NotificationContentView extends FrameLayout { } public void showAppOpsIcons(ArraySet<Integer> activeOps) { - if (mContractedChild != null && mContractedWrapper.getNotificationHeader() != null) { - mContractedWrapper.getNotificationHeader().showAppOpsIcons(activeOps); + if (mContractedChild != null) { + mContractedWrapper.showAppOpsIcons(activeOps); } - if (mExpandedChild != null && mExpandedWrapper.getNotificationHeader() != null) { - mExpandedWrapper.getNotificationHeader().showAppOpsIcons(activeOps); + if (mExpandedChild != null) { + mExpandedWrapper.showAppOpsIcons(activeOps); } - if (mHeadsUpChild != null && mHeadsUpWrapper.getNotificationHeader() != null) { - mHeadsUpWrapper.getNotificationHeader().showAppOpsIcons(activeOps); + if (mHeadsUpChild != null) { + mHeadsUpWrapper.showAppOpsIcons(activeOps); } } /** Sets whether the notification being displayed audibly alerted the user. */ public void setRecentlyAudiblyAlerted(boolean audiblyAlerted) { - if (mContractedChild != null && mContractedWrapper.getNotificationHeader() != null) { - mContractedWrapper.getNotificationHeader().setRecentlyAudiblyAlerted(audiblyAlerted); + if (mContractedChild != null) { + mContractedWrapper.setRecentlyAudiblyAlerted(audiblyAlerted); } - if (mExpandedChild != null && mExpandedWrapper.getNotificationHeader() != null) { - mExpandedWrapper.getNotificationHeader().setRecentlyAudiblyAlerted(audiblyAlerted); + if (mExpandedChild != null) { + mExpandedWrapper.setRecentlyAudiblyAlerted(audiblyAlerted); } - if (mHeadsUpChild != null && mHeadsUpWrapper.getNotificationHeader() != null) { - mHeadsUpWrapper.getNotificationHeader().setRecentlyAudiblyAlerted(audiblyAlerted); + if (mHeadsUpChild != null) { + mHeadsUpWrapper.setRecentlyAudiblyAlerted(audiblyAlerted); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java index 82e5f0a3b130..8d675f86c343 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java @@ -47,6 +47,18 @@ public abstract class StackScrollerDecorView extends ExpandableView { } }; + private boolean mSecondaryAnimating = false; + private final Runnable mSecondaryVisibilityEndRunnable = () -> { + mSecondaryAnimating = false; + // If we were on screen, become GONE to avoid touches + if (mSecondaryView == null) return; + if (getVisibility() != View.GONE + && mSecondaryView.getVisibility() != View.GONE + && !mIsSecondaryVisible) { + mSecondaryView.setVisibility(View.GONE); + } + }; + public StackScrollerDecorView(Context context, AttributeSet attrs) { super(context, attrs); setClipChildren(false); @@ -88,9 +100,11 @@ public abstract class StackScrollerDecorView extends ExpandableView { private void setContentVisible(boolean contentVisible, boolean animate) { if (mContentVisible != contentVisible) { mContentAnimating = animate; - setViewVisible(mContent, contentVisible, animate, mContentVisibilityEndRunnable); mContentVisible = contentVisible; - } if (!mContentAnimating) { + setViewVisible(mContent, contentVisible, animate, mContentVisibilityEndRunnable); + } + + if (!mContentAnimating) { mContentVisibilityEndRunnable.run(); } } @@ -136,8 +150,13 @@ public abstract class StackScrollerDecorView extends ExpandableView { */ public void setSecondaryVisible(boolean nowVisible, boolean animate) { if (mIsSecondaryVisible != nowVisible) { - setViewVisible(mSecondaryView, nowVisible, animate, null /* endRunnable */); + mSecondaryAnimating = animate; mIsSecondaryVisible = nowVisible; + setViewVisible(mSecondaryView, nowVisible, animate, mSecondaryVisibilityEndRunnable); + } + + if (!mSecondaryAnimating) { + mSecondaryVisibilityEndRunnable.run(); } } @@ -170,6 +189,12 @@ public abstract class StackScrollerDecorView extends ExpandableView { if (view == null) { return; } + + // Make sure we're visible so animations work + if (view.getVisibility() != View.VISIBLE) { + view.setVisibility(View.VISIBLE); + } + // cancel any previous animations view.animate().cancel(); float endValue = nowVisible ? 1.0f : 0.0f; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java index 7808a4b2dc74..0c311b403c48 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java @@ -18,6 +18,8 @@ package com.android.systemui.statusbar.notification.row.wrapper; import static com.android.systemui.statusbar.notification.TransformState.TRANSFORM_Y; +import android.annotation.NonNull; +import android.app.AppOpsManager; import android.app.Notification; import android.content.Context; import android.util.ArraySet; @@ -60,6 +62,11 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { protected NotificationHeaderView mNotificationHeader; private TextView mHeaderText; private ImageView mWorkProfileImage; + private View mCameraIcon; + private View mMicIcon; + private View mOverlayIcon; + private View mAppOps; + private View mAudiblyAlertedIcon; private boolean mIsLowPriority; private boolean mTransformLowPriorityTitle; @@ -107,6 +114,11 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { mExpandButton = mView.findViewById(com.android.internal.R.id.expand_button); mWorkProfileImage = mView.findViewById(com.android.internal.R.id.profile_badge); mNotificationHeader = mView.findViewById(com.android.internal.R.id.notification_header); + mCameraIcon = mView.findViewById(com.android.internal.R.id.camera); + mMicIcon = mView.findViewById(com.android.internal.R.id.mic); + mOverlayIcon = mView.findViewById(com.android.internal.R.id.overlay); + mAppOps = mView.findViewById(com.android.internal.R.id.app_ops); + mAudiblyAlertedIcon = mView.findViewById(com.android.internal.R.id.alerted_icon); if (mNotificationHeader != null) { mNotificationHeader.setShowExpandButtonAtEnd(mShowExpandButtonAtEnd); mColor = mNotificationHeader.getOriginalIconColor(); @@ -114,8 +126,35 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { } private void addAppOpsOnClickListener(ExpandableNotificationRow row) { + View.OnClickListener listener = row.getAppOpsOnClickListener(); if (mNotificationHeader != null) { - mNotificationHeader.setAppOpsOnClickListener(row.getAppOpsOnClickListener()); + mNotificationHeader.setAppOpsOnClickListener(listener); + } + mAppOps.setOnClickListener(listener); + mCameraIcon.setOnClickListener(listener); + mMicIcon.setOnClickListener(listener); + mOverlayIcon.setOnClickListener(listener); + } + + /** + * Shows or hides 'app op in use' icons based on app usage. + */ + @Override + public void showAppOpsIcons(ArraySet<Integer> appOps) { + if (appOps == null) { + return; + } + if (mOverlayIcon != null) { + mOverlayIcon.setVisibility(appOps.contains(AppOpsManager.OP_SYSTEM_ALERT_WINDOW) + ? View.VISIBLE : View.GONE); + } + if (mCameraIcon != null) { + mCameraIcon.setVisibility(appOps.contains(AppOpsManager.OP_CAMERA) + ? View.VISIBLE : View.GONE); + } + if (mMicIcon != null) { + mMicIcon.setVisibility(appOps.contains(AppOpsManager.OP_RECORD_AUDIO) + ? View.VISIBLE : View.GONE); } } @@ -184,6 +223,18 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TITLE, mHeaderText); } + if (mCameraIcon != null) { + mTransformationHelper.addViewTransformingToSimilar(mCameraIcon); + } + if (mMicIcon != null) { + mTransformationHelper.addViewTransformingToSimilar(mMicIcon); + } + if (mOverlayIcon != null) { + mTransformationHelper.addViewTransformingToSimilar(mOverlayIcon); + } + if (mAudiblyAlertedIcon != null) { + mTransformationHelper.addViewTransformingToSimilar(mAudiblyAlertedIcon); + } } @Override @@ -195,6 +246,13 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { } @Override + public void setRecentlyAudiblyAlerted(boolean audiblyAlerted) { + if (mAudiblyAlertedIcon != null) { + mAudiblyAlertedIcon.setVisibility(audiblyAlerted ? View.VISIBLE : View.GONE); + } + } + + @Override public NotificationHeaderView getNotificationHeader() { return mNotificationHeader; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java index e4fb2f7c42d4..fa7f282be74a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java @@ -29,6 +29,7 @@ import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; +import android.util.ArraySet; import android.view.NotificationHeaderView; import android.view.View; import android.view.ViewGroup; @@ -95,6 +96,14 @@ public abstract class NotificationViewWrapper implements TransformableView { public void onContentUpdated(ExpandableNotificationRow row) { } + /** + * Show a set of app opp icons in the layout. + * + * @param appOps which app ops to show + */ + public void showAppOpsIcons(ArraySet<Integer> appOps) { + } + public void onReinflated() { if (shouldClearBackgroundOnReapply()) { mBackgroundColor = 0; @@ -362,4 +371,10 @@ public abstract class NotificationViewWrapper implements TransformableView { public int getExtraMeasureHeight() { return 0; } + + /** + * Set the view to have recently visibly alerted. + */ + public void setRecentlyAudiblyAlerted(boolean audiblyAlerted) { + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java index 3d0bf3f4c1c6..400e794b820b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java @@ -22,6 +22,7 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.drawable.ColorDrawable; import android.service.notification.StatusBarNotification; +import android.util.ArraySet; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.NotificationHeaderView; @@ -1265,4 +1266,27 @@ public class NotificationChildrenContainer extends ViewGroup { mHeaderVisibleAmount = headerVisibleAmount; mCurrentHeaderTranslation = (int) ((1.0f - headerVisibleAmount) * mTranslationForHeader); } + + /** + * Show a set of app opp icons in the layout. + * + * @param appOps which app ops to show + */ + public void showAppOpsIcons(ArraySet<Integer> appOps) { + if (mNotificationHeaderWrapper != null) { + mNotificationHeaderWrapper.showAppOpsIcons(appOps); + } + if (mNotificationHeaderWrapperLowPriority != null) { + mNotificationHeaderWrapperLowPriority.showAppOpsIcons(appOps); + } + } + + public void setRecentlyAudiblyAlerted(boolean audiblyAlertedRecently) { + if (mNotificationHeaderWrapper != null) { + mNotificationHeaderWrapper.setRecentlyAudiblyAlerted(audiblyAlertedRecently); + } + if (mNotificationHeaderWrapperLowPriority != null) { + mNotificationHeaderWrapperLowPriority.setRecentlyAudiblyAlerted(audiblyAlertedRecently); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java index c05119de1e79..d6039af9232a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.phone; import android.content.Context; import android.os.Handler; import android.os.RemoteException; -import android.util.ArraySet; import android.util.Log; import android.view.IWindowManager; import android.view.MotionEvent; @@ -27,8 +26,6 @@ import android.view.MotionEvent; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.statusbar.AutoHideUiElement; -import java.util.Set; - import javax.inject.Inject; /** A controller to control all auto-hide things. Also see {@link AutoHideUiElement}. */ @@ -38,8 +35,9 @@ public class AutoHideController { private final IWindowManager mWindowManagerService; private final Handler mHandler; - private final Set<AutoHideUiElement> mElements; + private AutoHideUiElement mStatusBar; + private AutoHideUiElement mNavigationBar; private int mDisplayId; private boolean mAutoHideSuspended; @@ -55,28 +53,24 @@ public class AutoHideController { IWindowManager iWindowManager) { mHandler = handler; mWindowManagerService = iWindowManager; - mElements = new ArraySet<>(); mDisplayId = context.getDisplayId(); } /** - * Adds an {@link AutoHideUiElement} whose behavior should be controlled by the + * Sets a {@link AutoHideUiElement} status bar that should be controlled by the * {@link AutoHideController}. */ - public void addAutoHideUiElement(AutoHideUiElement element) { - if (element != null) { - mElements.add(element); - } + public void setStatusBar(AutoHideUiElement element) { + mStatusBar = element; } /** - * Remove an {@link AutoHideUiElement} that was previously added. + * Sets a {@link AutoHideUiElement} navigation bar that should be controlled by the + * {@link AutoHideController}. */ - public void removeAutoHideUiElement(AutoHideUiElement element) { - if (element != null) { - mElements.remove(element); - } + public void setNavigationBar(AutoHideUiElement element) { + mNavigationBar = element; } private void hideTransientBars() { @@ -86,8 +80,12 @@ public class AutoHideController { Log.w(TAG, "Cannot get WindowManager"); } - for (AutoHideUiElement element : mElements) { - element.hide(); + if (mStatusBar != null) { + mStatusBar.hide(); + } + + if (mNavigationBar != null) { + mNavigationBar.hide(); } } @@ -121,15 +119,13 @@ public class AutoHideController { } private Runnable getCheckBarModesRunnable() { - if (mElements.isEmpty()) { + if (mStatusBar != null) { + return () -> mStatusBar.synchronizeState(); + } else if (mNavigationBar != null) { + return () -> mNavigationBar.synchronizeState(); + } else { return null; } - - return () -> { - for (AutoHideUiElement element : mElements) { - element.synchronizeState(); - } - }; } private void cancelAutoHide() { @@ -147,8 +143,11 @@ public class AutoHideController { && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar. && event.getX() == 0 && event.getY() == 0; - for (AutoHideUiElement element : mElements) { - shouldHide &= element.shouldHideOnTouch(); + if (mStatusBar != null) { + shouldHide &= mStatusBar.shouldHideOnTouch(); + } + if (mNavigationBar != null) { + shouldHide &= mNavigationBar.shouldHideOnTouch(); } if (shouldHide) { @@ -162,11 +161,14 @@ public class AutoHideController { } private boolean isAnyTransientBarShown() { - for (AutoHideUiElement element : mElements) { - if (element.isVisible()) { - return true; - } + if (mStatusBar != null && mStatusBar.isVisible()) { + return true; } + + if (mNavigationBar != null && mNavigationBar.isVisible()) { + return true; + } + return false; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 31266db9e144..6fd3bb2c8222 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -1075,12 +1075,9 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback /** Sets {@link AutoHideController} to the navigation bar. */ public void setAutoHideController(AutoHideController autoHideController) { - if (mAutoHideController != null) { - mAutoHideController.removeAutoHideUiElement(mAutoHideUiElement); - } mAutoHideController = autoHideController; if (mAutoHideController != null) { - mAutoHideController.addAutoHideUiElement(mAutoHideUiElement); + mAutoHideController.setNavigationBar(mAutoHideUiElement); } } 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 98ba6e5b88a0..31797d1faa61 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -19,6 +19,8 @@ package com.android.systemui.statusbar.phone; import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL; +import static java.lang.Float.isNaN; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -86,6 +88,7 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.AnimatableProperty; +import com.android.systemui.statusbar.notification.ConversationNotificationManager; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; @@ -238,6 +241,7 @@ public class NotificationPanelViewController extends PanelViewController { private final PulseExpansionHandler mPulseExpansionHandler; private final KeyguardBypassController mKeyguardBypassController; private final KeyguardUpdateMonitor mUpdateMonitor; + private final ConversationNotificationManager mConversationNotificationManager; private KeyguardAffordanceHelper mAffordanceHelper; private KeyguardUserSwitcher mKeyguardUserSwitcher; @@ -451,7 +455,8 @@ public class NotificationPanelViewController extends PanelViewController { ActivityManager activityManager, ZenModeController zenModeController, ConfigurationController configurationController, FlingAnimationUtils.Builder flingAnimationUtilsBuilder, - StatusBarTouchableRegionManager statusBarTouchableRegionManager) { + StatusBarTouchableRegionManager statusBarTouchableRegionManager, + ConversationNotificationManager conversationNotificationManager) { super(view, falsingManager, dozeLog, keyguardStateController, (SysuiStatusBarStateController) statusBarStateController, vibratorHelper, latencyTracker, flingAnimationUtilsBuilder, statusBarTouchableRegionManager); @@ -509,6 +514,7 @@ public class NotificationPanelViewController extends PanelViewController { mShadeController = shadeController; mLockscreenUserManager = notificationLockscreenUserManager; mEntryManager = notificationEntryManager; + mConversationNotificationManager = conversationNotificationManager; mView.setBackgroundColor(Color.TRANSPARENT); OnAttachStateChangeListener onAttachStateChangeListener = new OnAttachStateChangeListener(); @@ -2005,7 +2011,12 @@ public class NotificationPanelViewController extends PanelViewController { @Override protected float getOverExpansionAmount() { - return mNotificationStackScroller.getCurrentOverScrollAmount(true /* top */); + float result = mNotificationStackScroller.getCurrentOverScrollAmount(true /* top */); + if (isNaN(result)) { + Log.wtf(TAG, "OverExpansionAmount is NaN!"); + } + + return result; } @Override @@ -2143,6 +2154,7 @@ public class NotificationPanelViewController extends PanelViewController { super.onExpandingFinished(); mNotificationStackScroller.onExpansionStopped(); mHeadsUpManager.onExpandingFinished(); + mConversationNotificationManager.onNotificationPanelExpandStateChanged(isFullyCollapsed()); mIsExpanding = false; if (isFullyCollapsed()) { DejankUtils.postAfterTraversal(new Runnable() { 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 83cc4e33e2db..f7d403f667cb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.phone; +import static java.lang.Float.isNaN; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; @@ -638,6 +640,9 @@ public abstract class PanelViewController { } public void setExpandedHeightInternal(float h) { + if (isNaN(h)) { + Log.wtf(TAG, "ExpandedHeight set to NaN"); + } if (mExpandLatencyTracking && h != 0f) { DejankUtils.postAfterTraversal( () -> mLatencyTracker.onActionEnd(LatencyTracker.ACTION_EXPAND_PANEL)); 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 d343090900a1..fa55b74606c2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -176,6 +176,7 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.NotificationViewHierarchyManager; import com.android.systemui.statusbar.PulseExpansionHandler; @@ -589,6 +590,7 @@ public class StatusBar extends SystemUI implements DemoMode, private ActivityLaunchAnimator mActivityLaunchAnimator; protected StatusBarNotificationPresenter mPresenter; private NotificationActivityStarter mNotificationActivityStarter; + private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy; private final BubbleController mBubbleController; private final BubbleController.BubbleExpandListener mBubbleExpandListener; @@ -679,6 +681,7 @@ public class StatusBar extends SystemUI implements DemoMode, PhoneStatusBarPolicy phoneStatusBarPolicy, KeyguardIndicationController keyguardIndicationController, DismissCallbackRegistry dismissCallbackRegistry, + Lazy<NotificationShadeDepthController> notificationShadeDepthControllerLazy, StatusBarTouchableRegionManager statusBarTouchableRegionManager) { super(context); mNotificationsController = notificationsController; @@ -735,6 +738,7 @@ public class StatusBar extends SystemUI implements DemoMode, mScreenPinningRequest = screenPinningRequest; mDozeScrimController = dozeScrimController; mBiometricUnlockControllerLazy = biometricUnlockControllerLazy; + mNotificationShadeDepthControllerLazy = notificationShadeDepthControllerLazy; mVolumeComponent = volumeComponent; mCommandQueue = commandQueue; mRecentsOptional = recentsOptional; @@ -1073,7 +1077,7 @@ public class StatusBar extends SystemUI implements DemoMode, } }); - mAutoHideController.addAutoHideUiElement(new AutoHideUiElement() { + mAutoHideController.setStatusBar(new AutoHideUiElement() { @Override public void synchronizeState() { checkBarModes(); @@ -1135,6 +1139,7 @@ public class StatusBar extends SystemUI implements DemoMode, mBrightnessMirrorController = new BrightnessMirrorController( mNotificationShadeWindowView, mNotificationPanelViewController, + mNotificationShadeDepthControllerLazy.get(), (visible) -> { mBrightnessMirrorVisible = visible; updateScrimController(); @@ -1230,6 +1235,7 @@ public class StatusBar extends SystemUI implements DemoMode, // Set up the initial notification state. mActivityLaunchAnimator = new ActivityLaunchAnimator( mNotificationShadeWindowViewController, this, mNotificationPanelViewController, + mNotificationShadeDepthControllerLazy.get(), (NotificationListContainer) mStackScroller); // TODO: inject this. @@ -3333,12 +3339,12 @@ public class StatusBar extends SystemUI implements DemoMode, Trace.traceCounter(Trace.TRACE_TAG_APP, "dozing", mDozing ? 1 : 0); Trace.beginSection("StatusBar#updateDozingState"); - boolean sleepingFromKeyguard = - mStatusBarKeyguardViewManager.isGoingToSleepVisibleNotOccluded(); + boolean visibleNotOccluded = mStatusBarKeyguardViewManager.isShowing() + && !mStatusBarKeyguardViewManager.isOccluded(); boolean wakeAndUnlock = mBiometricUnlockController.getMode() == BiometricUnlockController.MODE_WAKE_AND_UNLOCK; boolean animate = (!mDozing && mDozeServiceHost.shouldAnimateWakeup() && !wakeAndUnlock) - || (mDozing && mDozeServiceHost.shouldAnimateScreenOff() && sleepingFromKeyguard); + || (mDozing && mDozeServiceHost.shouldAnimateScreenOff() && visibleNotOccluded); mNotificationPanelViewController.setDozing(mDozing, animate, mWakeUpTouchLocation); updateQsExpansionEnabled(); 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 31db8eb404a9..45719c7f3936 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -168,7 +168,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private boolean mLastIsDocked; private boolean mLastPulsing; private int mLastBiometricMode; - private boolean mGoingToSleepVisibleNotOccluded; private boolean mLastLockVisible; private OnDismissAction mAfterKeyguardGoneAction; @@ -450,37 +449,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } } - public boolean isGoingToSleepVisibleNotOccluded() { - return mGoingToSleepVisibleNotOccluded; - } - - @Override - public void onStartedGoingToSleep() { - mGoingToSleepVisibleNotOccluded = isShowing() && !isOccluded(); - } - @Override public void onFinishedGoingToSleep() { - mGoingToSleepVisibleNotOccluded = false; mBouncer.onScreenTurnedOff(); } @Override - public void onStartedWakingUp() { - // TODO: remove - } - - @Override - public void onScreenTurningOn() { - // TODO: remove - } - - @Override - public void onScreenTurnedOn() { - // TODO: remove - } - - @Override public void onRemoteInputActive(boolean active) { mRemoteInputActive = active; updateStates(); @@ -999,7 +973,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb pw.println(" mOccluded: " + mOccluded); pw.println(" mRemoteInputActive: " + mRemoteInputActive); pw.println(" mDozing: " + mDozing); - pw.println(" mGoingToSleepVisibleNotOccluded: " + mGoingToSleepVisibleNotOccluded); pw.println(" mAfterKeyguardGoneAction: " + mAfterKeyguardGoneAction); pw.println(" mAfterKeyguardGoneRunnables: " + mAfterKeyguardGoneRunnables); pw.println(" mPendingWakeupAction: " + mPendingWakeupAction); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java index bbc7e7ab8c06..b81a5198b498 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java @@ -51,6 +51,7 @@ import com.android.systemui.statusbar.NavigationBarController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationViewHierarchyManager; import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.SuperStatusBarViewFactory; @@ -197,6 +198,7 @@ public interface StatusBarPhoneModule { UserInfoControllerImpl userInfoControllerImpl, PhoneStatusBarPolicy phoneStatusBarPolicy, KeyguardIndicationController keyguardIndicationController, + Lazy<NotificationShadeDepthController> notificationShadeDepthController, DismissCallbackRegistry dismissCallbackRegistry, StatusBarTouchableRegionManager statusBarTouchableRegionManager) { return new StatusBar( @@ -276,6 +278,7 @@ public interface StatusBarPhoneModule { phoneStatusBarPolicy, keyguardIndicationController, dismissCallbackRegistry, + notificationShadeDepthController, statusBarTouchableRegionManager); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java index d62da10de3d5..78111fb61fd0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java @@ -24,6 +24,7 @@ import android.view.View; import android.widget.FrameLayout; import com.android.systemui.R; +import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.NotificationShadeWindowView; @@ -39,16 +40,19 @@ public class BrightnessMirrorController private final NotificationShadeWindowView mStatusBarWindow; private final Consumer<Boolean> mVisibilityCallback; private final NotificationPanelViewController mNotificationPanel; + private final NotificationShadeDepthController mDepthController; private final ArraySet<BrightnessMirrorListener> mBrightnessMirrorListeners = new ArraySet<>(); private final int[] mInt2Cache = new int[2]; private View mBrightnessMirror; public BrightnessMirrorController(NotificationShadeWindowView statusBarWindow, NotificationPanelViewController notificationPanelViewController, + NotificationShadeDepthController notificationShadeDepthController, @NonNull Consumer<Boolean> visibilityCallback) { mStatusBarWindow = statusBarWindow; mBrightnessMirror = statusBarWindow.findViewById(R.id.brightness_mirror); mNotificationPanel = notificationPanelViewController; + mDepthController = notificationShadeDepthController; mNotificationPanel.setPanelAlphaEndAction(() -> { mBrightnessMirror.setVisibility(View.INVISIBLE); }); @@ -59,11 +63,13 @@ public class BrightnessMirrorController mBrightnessMirror.setVisibility(View.VISIBLE); mVisibilityCallback.accept(true); mNotificationPanel.setPanelAlpha(0, true /* animate */); + mDepthController.setBrightnessMirrorVisible(true); } public void hideMirror() { mVisibilityCallback.accept(false); mNotificationPanel.setPanelAlpha(255, true /* animate */); + mDepthController.setBrightnessMirrorVisible(false); } public void setLocation(View original) { |