diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java index 5d576f7bf5..01cf23bffd 100644 --- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java @@ -35,6 +35,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_N import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING; import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_REGION; import android.animation.ArgbEvaluator; @@ -105,6 +106,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT private static final int FLAG_DISABLE_BACK = 1 << 9; private static final int FLAG_NOTIFICATION_SHADE_EXPANDED = 1 << 10; private static final int FLAG_SCREEN_PINNING_ACTIVE = 1 << 11; + private static final int FLAG_VOICE_INTERACTION_WINDOW_SHOWING = 1 << 12; private static final int MASK_IME_SWITCHER_VISIBLE = FLAG_SWITCHER_SUPPORTED | FLAG_IME_VISIBLE; @@ -207,9 +209,12 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT boolean isInKidsMode = mContext.isNavBarKidsModeActive(); boolean alwaysShowButtons = isThreeButtonNav || isInSetup; - // Make sure to remove nav bar buttons translation when notification shade is expanded or - // IME is showing (add separate translation for IME). - int flagsToRemoveTranslation = FLAG_NOTIFICATION_SHADE_EXPANDED | FLAG_IME_VISIBLE; + // Make sure to remove nav bar buttons translation when any of the following occur: + // - Notification shade is expanded + // - IME is showing (add separate translation for IME) + // - VoiceInteractionWindow (assistant) is showing + int flagsToRemoveTranslation = FLAG_NOTIFICATION_SHADE_EXPANDED | FLAG_IME_VISIBLE + | FLAG_VOICE_INTERACTION_WINDOW_SHOWING; mPropertyHolders.add(new StatePropertyHolder(mNavButtonInAppDisplayProgressForSysui, flags -> (flags & flagsToRemoveTranslation) != 0, AnimatedFloat.VALUE, 1, 0)); @@ -443,6 +448,8 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT | SYSUI_STATE_QUICK_SETTINGS_EXPANDED; boolean isNotificationShadeExpanded = (sysUiStateFlags & shadeExpandedFlags) != 0; boolean isScreenPinningActive = (sysUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0; + boolean isVoiceInteractionWindowShowing = + (sysUiStateFlags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0; // TODO(b/202218289) we're getting IME as not visible on lockscreen from system updateStateForFlag(FLAG_IME_VISIBLE, isImeVisible); @@ -453,6 +460,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT updateStateForFlag(FLAG_DISABLE_BACK, isBackDisabled); updateStateForFlag(FLAG_NOTIFICATION_SHADE_EXPANDED, isNotificationShadeExpanded); updateStateForFlag(FLAG_SCREEN_PINNING_ACTIVE, isScreenPinningActive); + updateStateForFlag(FLAG_VOICE_INTERACTION_WINDOW_SHOWING, isVoiceInteractionWindowShowing); if (mA11yButton != null) { // Only used in 3 button @@ -750,6 +758,8 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT appendFlag(str, flags, FLAG_NOTIFICATION_SHADE_EXPANDED, "FLAG_NOTIFICATION_SHADE_EXPANDED"); appendFlag(str, flags, FLAG_SCREEN_PINNING_ACTIVE, "FLAG_SCREEN_PINNING_ACTIVE"); + appendFlag(str, flags, FLAG_VOICE_INTERACTION_WINDOW_SHOWING, + "FLAG_VOICE_INTERACTION_WINDOW_SHOWING"); return str.toString(); } diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java index b7978076c1..f472427520 100644 --- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java @@ -43,7 +43,8 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT public static final int ALPHA_INDEX_STASHED = 0; public static final int ALPHA_INDEX_HOME_DISABLED = 1; - private static final int NUM_ALPHA_CHANNELS = 2; + public static final int ALPHA_INDEX_ASSISTANT_INVOKED = 2; + private static final int NUM_ALPHA_CHANNELS = 3; /** * The SharedPreferences key for whether the stashed handle region is dark. diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 95da118948..61fad50499 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -27,6 +27,7 @@ import static com.android.launcher3.ResourceUtils.getBoolByName; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING; import android.animation.AnimatorSet; import android.animation.ValueAnimator; @@ -200,7 +201,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext { new TaskbarPopupController(this), new TaskbarForceVisibleImmersiveController(this), new TaskbarAllAppsController(this, dp), - new TaskbarInsetsController(this)); + new TaskbarInsetsController(this), + new VoiceInteractionWindowController(this)); } public void init(@NonNull TaskbarSharedState sharedState) { @@ -246,12 +248,20 @@ public class TaskbarActivityContext extends BaseTaskbarContext { return super.getStatsLogManager(); } - /** Creates LayoutParams for adding a view directly to WindowManager as a new window */ + /** @see #createDefaultWindowLayoutParams(int) */ public WindowManager.LayoutParams createDefaultWindowLayoutParams() { + return createDefaultWindowLayoutParams(TYPE_NAVIGATION_BAR_PANEL); + } + + /** + * Creates LayoutParams for adding a view directly to WindowManager as a new window. + * @param type The window type to pass to the created WindowManager.LayoutParams. + */ + public WindowManager.LayoutParams createDefaultWindowLayoutParams(int type) { WindowManager.LayoutParams windowLayoutParams = new WindowManager.LayoutParams( MATCH_PARENT, mLastRequestedNonFullscreenHeight, - TYPE_NAVIGATION_BAR_PANEL, + type, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SLIPPERY, PixelFormat.TRANSLUCENT); @@ -468,6 +478,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext { fromInit); mControllers.navButtonController.updateSysuiFlags(systemUiStateFlags); mControllers.taskbarForceVisibleImmersiveController.updateSysuiFlags(systemUiStateFlags); + mControllers.voiceInteractionWindowController.setIsVoiceInteractionWindowVisible( + (systemUiStateFlags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0, fromInit); } /** @@ -612,7 +624,9 @@ public class TaskbarActivityContext extends BaseTaskbarContext { /** Removes the given view from WindowManager. See {@link #addWindowView}. */ public void removeWindowView(View view) { - mWindowManager.removeViewImmediate(view); + if (view.isAttachedToWindow()) { + mWindowManager.removeViewImmediate(view); + } } protected void onTaskbarIconClicked(View view) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java index 449e0a7311..d7b50b0994 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java @@ -52,6 +52,7 @@ public class TaskbarControllers { public final TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController; public final TaskbarAllAppsController taskbarAllAppsController; public final TaskbarInsetsController taskbarInsetsController; + public final VoiceInteractionWindowController voiceInteractionWindowController; @Nullable private LoggableTaskbarController[] mControllersToLog = null; @@ -80,7 +81,8 @@ public class TaskbarControllers { TaskbarPopupController taskbarPopupController, TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController, TaskbarAllAppsController taskbarAllAppsController, - TaskbarInsetsController taskbarInsetsController) { + TaskbarInsetsController taskbarInsetsController, + VoiceInteractionWindowController voiceInteractionWindowController) { this.taskbarActivityContext = taskbarActivityContext; this.taskbarDragController = taskbarDragController; this.navButtonController = navButtonController; @@ -99,6 +101,7 @@ public class TaskbarControllers { this.taskbarForceVisibleImmersiveController = taskbarForceVisibleImmersiveController; this.taskbarAllAppsController = taskbarAllAppsController; this.taskbarInsetsController = taskbarInsetsController; + this.voiceInteractionWindowController = voiceInteractionWindowController; } /** @@ -126,13 +129,15 @@ public class TaskbarControllers { taskbarAllAppsController.init(this, sharedState.allAppsVisible); navButtonController.init(this); taskbarInsetsController.init(this); + voiceInteractionWindowController.init(this); mControllersToLog = new LoggableTaskbarController[] { taskbarDragController, navButtonController, navbarButtonsViewController, taskbarDragLayerController, taskbarScrimViewController, taskbarViewController, taskbarUnfoldAnimationController, taskbarKeyguardController, stashedHandleViewController, taskbarStashController, taskbarEduController, - taskbarAutohideSuspendController, taskbarPopupController, taskbarInsetsController + taskbarAutohideSuspendController, taskbarPopupController, taskbarInsetsController, + voiceInteractionWindowController }; mAreAllControllersInitialized = true; @@ -172,6 +177,7 @@ public class TaskbarControllers { taskbarAllAppsController.onDestroy(); navButtonController.onDestroy(); taskbarInsetsController.onDestroy(); + voiceInteractionWindowController.onDestroy(); mControllersToLog = null; } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index 3562f5bc3c..fdd9de5db3 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -63,7 +63,8 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar public static final int ALPHA_INDEX_STASH = 2; public static final int ALPHA_INDEX_RECENTS_DISABLED = 3; public static final int ALPHA_INDEX_NOTIFICATION_EXPANDED = 4; - private static final int NUM_ALPHA_CHANNELS = 5; + public static final int ALPHA_INDEX_ASSISTANT_INVOKED = 5; + private static final int NUM_ALPHA_CHANNELS = 6; private final TaskbarActivityContext mActivity; private final TaskbarView mTaskbarView; diff --git a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt new file mode 100644 index 0000000000..946873e7ab --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt @@ -0,0 +1,109 @@ +package com.android.launcher3.taskbar + +import android.graphics.Canvas +import android.view.WindowManager +import android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY +import com.android.launcher3.views.BaseDragLayer +import com.android.systemui.animation.ViewRootSync +import java.io.PrintWriter + +private const val TASKBAR_ICONS_FADE_DURATION = 300L +private const val STASHED_HANDLE_FADE_DURATION = 180L + +/** + * Controls Taskbar behavior while Voice Interaction Window (assistant) is showing. + */ +class VoiceInteractionWindowController(val context: TaskbarActivityContext) + : TaskbarControllers.LoggableTaskbarController { + + private val taskbarBackgroundRenderer = TaskbarBackgroundRenderer(context) + + // Initialized in init. + private lateinit var controllers: TaskbarControllers + private lateinit var separateWindowForTaskbarBackground: BaseDragLayer + private lateinit var separateWindowLayoutParams: WindowManager.LayoutParams + + private var isVoiceInteractionWindowVisible: Boolean = false + + fun init(controllers: TaskbarControllers) { + this.controllers = controllers + + separateWindowForTaskbarBackground = + object : BaseDragLayer(context, null, 0) { + override fun recreateControllers() { + mControllers = emptyArray() + } + + override fun draw(canvas: Canvas) { + super.draw(canvas) + taskbarBackgroundRenderer.draw(canvas) + } + } + separateWindowForTaskbarBackground.recreateControllers() + separateWindowForTaskbarBackground.setWillNotDraw(false) + + separateWindowLayoutParams = context.createDefaultWindowLayoutParams( + TYPE_APPLICATION_OVERLAY) + separateWindowLayoutParams.isSystemApplicationOverlay = true + } + + fun onDestroy() { + setIsVoiceInteractionWindowVisible(visible = false, skipAnim = true) + } + + fun setIsVoiceInteractionWindowVisible(visible: Boolean, skipAnim: Boolean) { + if (isVoiceInteractionWindowVisible == visible) { + return + } + isVoiceInteractionWindowVisible = visible + + // Fade out taskbar icons and stashed handle. + val taskbarIconAlpha = if (isVoiceInteractionWindowVisible) 0f else 1f + val fadeTaskbarIcons = controllers.taskbarViewController.taskbarIconAlpha + .getProperty(TaskbarViewController.ALPHA_INDEX_ASSISTANT_INVOKED) + .animateToValue(taskbarIconAlpha) + .setDuration(TASKBAR_ICONS_FADE_DURATION) + val fadeStashedHandle = controllers.stashedHandleViewController.stashedHandleAlpha + .getProperty(StashedHandleViewController.ALPHA_INDEX_ASSISTANT_INVOKED) + .animateToValue(taskbarIconAlpha) + .setDuration(STASHED_HANDLE_FADE_DURATION) + fadeTaskbarIcons.start() + fadeStashedHandle.start() + if (skipAnim) { + fadeTaskbarIcons.end() + fadeStashedHandle.end() + } + + if (context.isGestureNav && controllers.taskbarStashController.isInAppAndNotStashed) { + moveTaskbarBackgroundToLowerLayer() + } + } + + /** + * Hides the TaskbarDragLayer background and creates a new window to draw just that background. + */ + private fun moveTaskbarBackgroundToLowerLayer() { + val taskbarBackgroundOverride = controllers.taskbarDragLayerController + .overrideBackgroundAlpha + if (isVoiceInteractionWindowVisible) { + // First add the temporary window, then hide the overlapping taskbar background. + context.addWindowView(separateWindowForTaskbarBackground, separateWindowLayoutParams) + ViewRootSync.synchronizeNextDraw(separateWindowForTaskbarBackground, context.dragLayer + ) { + taskbarBackgroundOverride.updateValue(0f) + } + } else { + // First reapply the original taskbar background, then remove the temporary window. + taskbarBackgroundOverride.updateValue(1f) + ViewRootSync.synchronizeNextDraw(separateWindowForTaskbarBackground, context.dragLayer + ) { + context.removeWindowView(separateWindowForTaskbarBackground) + } + } + } + + override fun dumpLogs(prefix: String, pw: PrintWriter) { + pw.println(prefix + "VoiceInteractionWindowController:") + pw.println("$prefix\tisVoiceInteractionWindowVisible=$isVoiceInteractionWindowVisible") + } +} \ No newline at end of file