diff options
Diffstat (limited to 'libs')
51 files changed, 989 insertions, 523 deletions
diff --git a/libs/WindowManager/Jetpack/tests/unittest/Android.bp b/libs/WindowManager/Jetpack/tests/unittest/Android.bp index b6e743a2b7e1..ed2ff2de245b 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/Android.bp +++ b/libs/WindowManager/Jetpack/tests/unittest/Android.bp @@ -37,7 +37,7 @@ android_test { "androidx.test.rules", "androidx.test.ext.junit", "mockito-target-extended-minus-junit4", - "truth-prebuilt", + "truth", "testables", "platform-test-annotations", ], diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml new file mode 100644 index 000000000000..ee9f070f6765 --- /dev/null +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml @@ -0,0 +1,145 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 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. + --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="@dimen/desktop_mode_handle_menu_width" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="@dimen/desktop_mode_handle_menu_app_info_pill_height" + android:layout_marginTop="@dimen/desktop_mode_handle_menu_margin_top" + android:layout_marginStart="1dp" + android:elevation="1dp" + android:orientation="horizontal" + android:background="@drawable/desktop_mode_decor_handle_menu_background" + android:gravity="center_vertical"> + + <ImageView + android:id="@+id/application_icon" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_marginStart="14dp" + android:layout_marginEnd="14dp" + android:contentDescription="@string/app_icon_text"/> + + <TextView + android:id="@+id/application_name" + android:layout_width="0dp" + android:layout_height="wrap_content" + tools:text="Gmail" + android:textColor="?androidprv:attr/materialColorOnSurface" + android:textSize="14sp" + android:textFontWeight="500" + android:lineHeight="20dp" + android:textStyle="normal" + android:layout_weight="1"/> + + <ImageButton + android:id="@+id/collapse_menu_button" + android:layout_width="32dp" + android:layout_height="32dp" + android:padding="4dp" + android:layout_marginEnd="14dp" + android:layout_marginStart="14dp" + android:contentDescription="@string/collapse_menu_text" + android:src="@drawable/ic_baseline_expand_more_24" + android:rotation="180" + android:tint="?androidprv:attr/materialColorOnSurface" + android:background="?android:selectableItemBackgroundBorderless"/> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="@dimen/desktop_mode_handle_menu_windowing_pill_height" + android:layout_marginTop="@dimen/desktop_mode_handle_menu_pill_spacing_margin" + android:layout_marginStart="1dp" + android:orientation="horizontal" + android:elevation="1dp" + android:background="@drawable/desktop_mode_decor_handle_menu_background" + android:gravity="center_vertical"> + + <ImageButton + android:id="@+id/fullscreen_button" + android:layout_marginEnd="4dp" + android:contentDescription="@string/fullscreen_text" + android:src="@drawable/desktop_mode_ic_handle_menu_fullscreen" + android:tint="?androidprv:attr/materialColorOnSurface" + android:layout_weight="1" + style="@style/DesktopModeHandleMenuWindowingButton"/> + + <ImageButton + android:id="@+id/split_screen_button" + android:layout_marginStart="4dp" + android:layout_marginEnd="4dp" + android:contentDescription="@string/split_screen_text" + android:src="@drawable/desktop_mode_ic_handle_menu_splitscreen" + android:tint="?androidprv:attr/materialColorOnSurface" + android:layout_weight="1" + style="@style/DesktopModeHandleMenuWindowingButton"/> + + <ImageButton + android:id="@+id/floating_button" + android:layout_marginStart="4dp" + android:layout_marginEnd="4dp" + android:contentDescription="@string/float_button_text" + android:src="@drawable/desktop_mode_ic_handle_menu_floating" + android:tint="?androidprv:attr/materialColorOnSurface" + android:layout_weight="1" + style="@style/DesktopModeHandleMenuWindowingButton"/> + + <ImageButton + android:id="@+id/desktop_button" + android:layout_marginStart="4dp" + android:contentDescription="@string/desktop_text" + android:src="@drawable/desktop_mode_ic_handle_menu_desktop" + android:tint="?androidprv:attr/materialColorOnSurface" + android:layout_weight="1" + style="@style/DesktopModeHandleMenuWindowingButton"/> + + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="@dimen/desktop_mode_handle_menu_more_actions_pill_height" + android:layout_marginTop="@dimen/desktop_mode_handle_menu_pill_spacing_margin" + android:layout_marginStart="1dp" + android:orientation="vertical" + android:elevation="1dp" + android:background="@drawable/desktop_mode_decor_handle_menu_background"> + + <Button + android:id="@+id/screenshot_button" + android:contentDescription="@string/screenshot_text" + android:text="@string/screenshot_text" + android:drawableStart="@drawable/desktop_mode_ic_handle_menu_screenshot" + android:drawableTint="?androidprv:attr/materialColorOnSurface" + style="@style/DesktopModeHandleMenuActionButton"/> + + <Button + android:id="@+id/select_button" + android:contentDescription="@string/select_text" + android:text="@string/select_text" + android:drawableStart="@drawable/desktop_mode_ic_handle_menu_select" + android:drawableTint="?androidprv:attr/materialColorOnSurface" + style="@style/DesktopModeHandleMenuActionButton"/> + + </LinearLayout> +</LinearLayout> + diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_app_info_pill.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_app_info_pill.xml deleted file mode 100644 index c2ee3066d059..000000000000 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_app_info_pill.xml +++ /dev/null @@ -1,58 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2023 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. - --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" - xmlns:tools="http://schemas.android.com/tools" - android:layout_width="@dimen/desktop_mode_handle_menu_width" - android:layout_height="@dimen/desktop_mode_handle_menu_app_info_pill_height" - android:orientation="horizontal" - android:background="@drawable/desktop_mode_decor_handle_menu_background" - android:gravity="center_vertical"> - - <ImageView - android:id="@+id/application_icon" - android:layout_width="24dp" - android:layout_height="24dp" - android:layout_marginStart="14dp" - android:layout_marginEnd="14dp" - android:contentDescription="@string/app_icon_text"/> - - <TextView - android:id="@+id/application_name" - android:layout_width="0dp" - android:layout_height="wrap_content" - tools:text="Gmail" - android:textColor="?androidprv:attr/materialColorOnSurface" - android:textSize="14sp" - android:textFontWeight="500" - android:lineHeight="20dp" - android:textStyle="normal" - android:layout_weight="1"/> - - <ImageButton - android:id="@+id/collapse_menu_button" - android:layout_width="32dp" - android:layout_height="32dp" - android:padding="4dp" - android:layout_marginEnd="14dp" - android:layout_marginStart="14dp" - android:contentDescription="@string/collapse_menu_text" - android:src="@drawable/ic_baseline_expand_more_24" - android:rotation="180" - android:tint="?androidprv:attr/materialColorOnSurface" - android:background="?android:selectableItemBackgroundBorderless"/> -</LinearLayout>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_more_actions_pill.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_more_actions_pill.xml deleted file mode 100644 index e637671937bd..000000000000 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_more_actions_pill.xml +++ /dev/null @@ -1,47 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2023 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. - --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" - android:layout_width="@dimen/desktop_mode_handle_menu_width" - android:layout_height="@dimen/desktop_mode_handle_menu_more_actions_pill_height" - android:orientation="vertical" - android:background="@drawable/desktop_mode_decor_handle_menu_background"> - - <Button - android:id="@+id/screenshot_button" - android:contentDescription="@string/screenshot_text" - android:text="@string/screenshot_text" - android:drawableStart="@drawable/desktop_mode_ic_handle_menu_screenshot" - android:drawableTint="?androidprv:attr/materialColorOnSurface" - style="@style/DesktopModeHandleMenuActionButton"/> - - <Button - android:id="@+id/select_button" - android:contentDescription="@string/select_text" - android:text="@string/select_text" - android:drawableStart="@drawable/desktop_mode_ic_handle_menu_select" - android:drawableTint="?androidprv:attr/materialColorOnSurface" - style="@style/DesktopModeHandleMenuActionButton"/> - <Button - android:id="@+id/close_button" - android:contentDescription="@string/close_text" - android:text="@string/close_text" - android:drawableStart="@drawable/desktop_mode_ic_handle_menu_close" - android:drawableTint="?androidprv:attr/materialColorOnSurface" - style="@style/DesktopModeHandleMenuActionButton"/> - -</LinearLayout>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_windowing_pill.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_windowing_pill.xml deleted file mode 100644 index c4b688daeb6e..000000000000 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_windowing_pill.xml +++ /dev/null @@ -1,63 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2023 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. - --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" - android:layout_width="@dimen/desktop_mode_handle_menu_width" - android:layout_height="@dimen/desktop_mode_handle_menu_windowing_pill_height" - android:orientation="horizontal" - android:background="@drawable/desktop_mode_decor_handle_menu_background" - android:gravity="center_vertical"> - - <ImageButton - android:id="@+id/fullscreen_button" - android:layout_marginEnd="4dp" - android:contentDescription="@string/fullscreen_text" - android:src="@drawable/desktop_mode_ic_handle_menu_fullscreen" - android:tint="?androidprv:attr/materialColorOnSurface" - android:layout_weight="1" - style="@style/DesktopModeHandleMenuWindowingButton"/> - - <ImageButton - android:id="@+id/split_screen_button" - android:layout_marginStart="4dp" - android:layout_marginEnd="4dp" - android:contentDescription="@string/split_screen_text" - android:src="@drawable/desktop_mode_ic_handle_menu_splitscreen" - android:tint="?androidprv:attr/materialColorOnSurface" - android:layout_weight="1" - style="@style/DesktopModeHandleMenuWindowingButton"/> - - <ImageButton - android:id="@+id/floating_button" - android:layout_marginStart="4dp" - android:layout_marginEnd="4dp" - android:contentDescription="@string/float_button_text" - android:src="@drawable/desktop_mode_ic_handle_menu_floating" - android:tint="?androidprv:attr/materialColorOnSurface" - android:layout_weight="1" - style="@style/DesktopModeHandleMenuWindowingButton"/> - - <ImageButton - android:id="@+id/desktop_button" - android:layout_marginStart="4dp" - android:contentDescription="@string/desktop_text" - android:src="@drawable/desktop_mode_ic_handle_menu_desktop" - android:tint="?androidprv:attr/materialColorOnSurface" - android:layout_weight="1" - style="@style/DesktopModeHandleMenuWindowingButton"/> - -</LinearLayout>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml index fae83883b7c4..1dbc57b73f6c 100644 --- a/libs/WindowManager/Shell/res/values-eu/strings.xml +++ b/libs/WindowManager/Shell/res/values-eu/strings.xml @@ -36,7 +36,7 @@ <string name="dock_non_resizeble_failed_to_dock_text" msgid="2733543750291266047">"Aplikazioak ez du onartzen pantaila zatitua"</string> <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Leiho bakar batean ireki daiteke aplikazioa."</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Baliteke aplikazioak ez funtzionatzea bigarren mailako pantailetan."</string> - <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikazioa ezin da abiarazi bigarren mailako pantailatan."</string> + <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikazioa ezin da exekutatu bigarren mailako pantailatan."</string> <string name="accessibility_divider" msgid="6407584574218956849">"Pantaila-zatitzailea"</string> <string name="divider_title" msgid="1963391955593749442">"Pantaila-zatitzailea"</string> <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ezarri ezkerraldea pantaila osoan"</string> @@ -110,7 +110,7 @@ <string name="app_icon_text" msgid="2823268023931811747">"Aplikazioaren ikonoa"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pantaila osoa"</string> <string name="desktop_text" msgid="1077633567027630454">"Ordenagailuetarako modua"</string> - <string name="split_screen_text" msgid="1396336058129570886">"Pantaila zatitua"</string> + <string name="split_screen_text" msgid="1396336058129570886">"Pantaila zatitzea"</string> <string name="more_button_text" msgid="3655388105592893530">"Gehiago"</string> <string name="float_button_text" msgid="9221657008391364581">"Leiho gainerakorra"</string> <string name="select_text" msgid="5139083974039906583">"Hautatu"</string> diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml index e155c72bf297..afccac292ebe 100644 --- a/libs/WindowManager/Shell/res/values-sq/strings.xml +++ b/libs/WindowManager/Shell/res/values-sq/strings.xml @@ -97,7 +97,7 @@ <string name="letterbox_education_got_it" msgid="4057634570866051177">"E kuptova"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Zgjeroje për më shumë informacion."</string> <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Rinis për një pamje më të mirë?"</string> - <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Mund të rinisësh aplikacionin në mënyrë që të duket më mirë në ekranin tënd, por mund të humbësh progresin ose çdo ndryshim të paruajtur"</string> + <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Mund ta rinisësh aplikacionin në mënyrë që të duket më mirë në ekranin tënd, por mund ta humbasësh progresin ose çdo ndryshim të paruajtur"</string> <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Anulo"</string> <string name="letterbox_restart_restart" msgid="8529976234412442973">"Rinis"</string> <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Mos e shfaq përsëri"</string> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 705e38731a0c..1f6f7aeadd45 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -143,7 +143,9 @@ <dimen name="bubble_expanded_view_padding">16dp</dimen> <!-- Padding for the edge of the expanded view that is closest to the edge of the screen used when displaying in landscape on a large screen. --> - <dimen name="bubble_expanded_view_largescreen_landscape_padding">128dp</dimen> + <dimen name="bubble_expanded_view_largescreen_landscape_padding">102dp</dimen> + <!-- The width of the expanded view on large screens. --> + <dimen name="bubble_expanded_view_largescreen_width">540dp</dimen> <!-- This should be at least the size of bubble_expanded_view_padding; it is used to include a slight touch slop around the expanded view. --> <dimen name="bubble_expanded_view_slop">8dp</dimen> @@ -434,11 +436,11 @@ <!-- The height of the handle menu's "Windowing" pill in desktop mode. --> <dimen name="desktop_mode_handle_menu_windowing_pill_height">52dp</dimen> - <!-- The height of the handle menu's "More Actions" pill in desktop mode, but not freeform. --> - <dimen name="desktop_mode_handle_menu_more_actions_pill_height">104dp</dimen> + <!-- The height of the handle menu's "More Actions" pill in desktop mode. --> + <dimen name="desktop_mode_handle_menu_more_actions_pill_height">52dp</dimen> - <!-- The height of the handle menu's "More Actions" pill in freeform desktop windowing mode. --> - <dimen name="desktop_mode_handle_menu_more_actions_pill_freeform_height">52dp</dimen> + <!-- The height of the handle menu in desktop mode. --> + <dimen name="desktop_mode_handle_menu_height">328dp</dimen> <!-- The top margin of the handle menu in desktop mode. --> <dimen name="desktop_mode_handle_menu_margin_top">4dp</dimen> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java index 410ae78dba1b..38550b405c0e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java @@ -32,6 +32,7 @@ import android.view.SurfaceControl; import android.window.DisplayAreaAppearedInfo; import android.window.DisplayAreaInfo; import android.window.DisplayAreaOrganizer; +import android.window.SystemPerformanceHinter; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -58,6 +59,14 @@ public class RootTaskDisplayAreaOrganizer extends DisplayAreaOrganizer { /** {@link DisplayAreaContext} list, which is mapped by display IDs. */ private final SparseArray<DisplayAreaContext> mDisplayAreaContexts = new SparseArray<>(); + private final SystemPerformanceHinter.DisplayRootProvider mPerfRootProvider = + new SystemPerformanceHinter.DisplayRootProvider() { + @Override + public SurfaceControl getRootForDisplay(int displayId) { + return mLeashes.get(displayId); + } + }; + private final Context mContext; public RootTaskDisplayAreaOrganizer(Executor executor, Context context) { @@ -229,6 +238,11 @@ public class RootTaskDisplayAreaOrganizer extends DisplayAreaOrganizer { return mDisplayAreaContexts.get(displayId); } + @NonNull + public SystemPerformanceHinter.DisplayRootProvider getPerformanceRootProvider() { + return mPerfRootProvider; + } + public void dump(@NonNull PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; final String childPrefix = innerPrefix + " "; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java index f1ee8fa38485..a67821b7e819 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java @@ -318,7 +318,7 @@ public class BadgedImageView extends ConstraintLayout { /** * Animates the dot to the given scale, running the optional callback when the animation ends. */ - private void animateDotScale(float toScale, @Nullable Runnable after) { + public void animateDotScale(float toScale, @Nullable Runnable after) { mDotIsAnimating = true; // Don't restart the animation if we're already animating to the given value. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index f259902e9565..dddcbd4c96c0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -512,6 +512,7 @@ public class BubbleController implements ConfigurationChangeListener, * <p>If bubble bar is supported, bubble views will be updated to switch to bar mode. */ public void registerBubbleStateListener(Bubbles.BubbleStateListener listener) { + mBubbleProperties.refresh(); if (canShowAsBubbleBar() && listener != null) { // Only set the listener if we can show the bubble bar. mBubbleStateListener = listener; @@ -529,6 +530,7 @@ public class BubbleController implements ConfigurationChangeListener, * will be updated accordingly. */ public void unregisterBubbleStateListener() { + mBubbleProperties.refresh(); if (mBubbleStateListener != null) { mBubbleStateListener = null; setUpBubbleViewsForMode(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt index df19757203eb..dc099d9abda4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt @@ -27,6 +27,7 @@ import android.graphics.drawable.ColorDrawable import android.graphics.drawable.InsetDrawable import android.util.PathParser import android.view.LayoutInflater +import android.view.View.VISIBLE import android.widget.FrameLayout import com.android.launcher3.icons.BubbleIconFactory import com.android.wm.shell.R @@ -156,7 +157,9 @@ class BubbleOverflow(private val context: Context, private val positioner: Bubbl fun setShowDot(show: Boolean) { showDot = show - overflowBtn?.updateDotVisibility(true /* animate */) + if (overflowBtn?.visibility == VISIBLE) { + overflowBtn?.updateDotVisibility(true /* animate */) + } } /** Creates the expanded view for bubbles showing in the stack view. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java index ea7053d8ee49..17e06e93b3a8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java @@ -54,10 +54,6 @@ public class BubblePositioner { public static final float FLYOUT_MAX_WIDTH_PERCENT_LARGE_SCREEN = 0.3f; /** The max percent of screen width to use for the flyout on phone. */ public static final float FLYOUT_MAX_WIDTH_PERCENT = 0.6f; - /** The percent of screen width for the expanded view on a large screen. **/ - private static final float EXPANDED_VIEW_LARGE_SCREEN_LANDSCAPE_WIDTH_PERCENT = 0.48f; - /** The percent of screen width for the expanded view on a large screen. **/ - private static final float EXPANDED_VIEW_LARGE_SCREEN_PORTRAIT_WIDTH_PERCENT = 0.70f; /** The percent of screen width for the expanded view on a small tablet. **/ private static final float EXPANDED_VIEW_SMALL_TABLET_WIDTH_PERCENT = 0.72f; /** The percent of screen width for the expanded view when shown in the bubble bar. **/ @@ -95,6 +91,7 @@ public class BubblePositioner { private int mPointerWidth; private int mPointerHeight; private int mPointerOverlap; + private int mManageButtonHeightIncludingMargins; private int mManageButtonHeight; private int mOverflowHeight; private int mMinimumFlyoutWidthLargeScreen; @@ -176,21 +173,20 @@ public class BubblePositioner { mExpandedViewLargeScreenWidth = (int) (bounds.width() * EXPANDED_VIEW_SMALL_TABLET_WIDTH_PERCENT); } else { - mExpandedViewLargeScreenWidth = isLandscape() - ? (int) (bounds.width() * EXPANDED_VIEW_LARGE_SCREEN_LANDSCAPE_WIDTH_PERCENT) - : (int) (bounds.width() * EXPANDED_VIEW_LARGE_SCREEN_PORTRAIT_WIDTH_PERCENT); + mExpandedViewLargeScreenWidth = + res.getDimensionPixelSize(R.dimen.bubble_expanded_view_largescreen_width); } if (mIsLargeScreen) { - if (isLandscape() && !mIsSmallTablet) { + if (mIsSmallTablet) { + final int centeredInset = (bounds.width() - mExpandedViewLargeScreenWidth) / 2; + mExpandedViewLargeScreenInsetClosestEdge = centeredInset; + mExpandedViewLargeScreenInsetFurthestEdge = centeredInset; + } else { mExpandedViewLargeScreenInsetClosestEdge = res.getDimensionPixelSize( R.dimen.bubble_expanded_view_largescreen_landscape_padding); mExpandedViewLargeScreenInsetFurthestEdge = bounds.width() - mExpandedViewLargeScreenInsetClosestEdge - mExpandedViewLargeScreenWidth; - } else { - final int centeredInset = (bounds.width() - mExpandedViewLargeScreenWidth) / 2; - mExpandedViewLargeScreenInsetClosestEdge = centeredInset; - mExpandedViewLargeScreenInsetFurthestEdge = centeredInset; } } else { mExpandedViewLargeScreenInsetClosestEdge = mExpandedViewPadding; @@ -202,7 +198,9 @@ public class BubblePositioner { mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height); mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin); mPointerOverlap = res.getDimensionPixelSize(R.dimen.bubble_pointer_overlap); - mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_total_height); + mManageButtonHeightIncludingMargins = + res.getDimensionPixelSize(R.dimen.bubble_manage_button_total_height); + mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_height); mExpandedViewMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height); mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height); mMinimumFlyoutWidthLargeScreen = res.getDimensionPixelSize( @@ -420,7 +418,7 @@ public class BubblePositioner { int pointerSize = showBubblesVertically() ? mPointerWidth : (mPointerHeight + mPointerMargin); - int bottomPadding = isOverflow ? mExpandedViewPadding : mManageButtonHeight; + int bottomPadding = isOverflow ? mExpandedViewPadding : mManageButtonHeightIncludingMargins; return getAvailableRect().height() - expandedContainerY - paddingTop @@ -438,6 +436,15 @@ public class BubblePositioner { // overflow in landscape on phone is max return MAX_HEIGHT; } + + if (mIsLargeScreen && !mIsSmallTablet && !isOverflow) { + // the expanded view height on large tablets is calculated based on the shortest screen + // size and is the same in both portrait and landscape + int maxVerticalInset = Math.max(mInsets.top, mInsets.bottom); + int shortestScreenSide = Math.min(mScreenRect.height(), mScreenRect.width()); + return shortestScreenSide - 2 * maxVerticalInset - mManageButtonHeight; + } + float desiredHeight = isOverflow ? mOverflowHeight : ((Bubble) bubble).getDesiredHeight(mContext); @@ -466,7 +473,8 @@ public class BubblePositioner { return topAlignment; } // If we're here, we're showing vertically & developer has made height less than maximum. - int manageButtonHeight = isOverflow ? mExpandedViewPadding : mManageButtonHeight; + int manageButtonHeight = + isOverflow ? mExpandedViewPadding : mManageButtonHeightIncludingMargins; float pointerPosition = getPointerPosition(bubblePosition); float bottomIfCentered = pointerPosition + (expandedViewHeight / 2) + manageButtonHeight; float topIfCentered = pointerPosition - (expandedViewHeight / 2); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index c124b532b89d..2241c343a208 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -1864,6 +1864,14 @@ public class BubbleStackView extends FrameLayout : GONE); } + private void updateOverflowDotVisibility(boolean expanding) { + if (mBubbleOverflow.showDot()) { + mBubbleOverflow.getIconView().animateDotScale(expanding ? 1 : 0f, () -> { + mBubbleOverflow.setVisible(expanding ? VISIBLE : GONE); + }); + } + } + // via BubbleData.Listener void updateBubble(Bubble bubble) { animateInFlyoutForBubble(bubble); @@ -2274,6 +2282,7 @@ public class BubbleStackView extends FrameLayout if (mIsExpanded && mExpandedBubble.getExpandedView() != null) { maybeShowManageEdu(); } + updateOverflowDotVisibility(true /* expanding */); } /* after */); int index; if (mExpandedBubble != null && BubbleOverflow.KEY.equals(mExpandedBubble.getKey())) { @@ -2405,11 +2414,15 @@ public class BubbleStackView extends FrameLayout // since we're about to animate collapsed. mExpandedAnimationController.notifyPreparingToCollapse(); + updateOverflowDotVisibility(false /* expanding */); final Runnable collapseBackToStack = () -> mExpandedAnimationController.collapseBackToStack( mStackAnimationController .getStackPositionAlongNearestHorizontalEdge() /* collapseTo */, - () -> mBubbleContainer.setActiveController(mStackAnimationController)); + () -> { + mBubbleContainer.setActiveController(mStackAnimationController); + updateOverflowVisibility(); + }); final Runnable after = () -> { final BubbleViewProvider previouslySelected = mExpandedBubble; @@ -2424,7 +2437,6 @@ public class BubbleStackView extends FrameLayout Log.d(TAG, BubbleDebugConfig.formatBubblesString(getBubblesOnScreen(), mExpandedBubble)); } - updateOverflowVisibility(); updateZOrder(); updateBadges(true /* setBadgeForCollapsedStack */); afterExpandedViewAnimation(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java index 4d7042bbb3d2..738c94e82a95 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java @@ -34,6 +34,8 @@ import androidx.dynamicanimation.animation.SpringForce; import com.android.wm.shell.R; import com.android.wm.shell.animation.Interpolators; import com.android.wm.shell.animation.PhysicsAnimator; +import com.android.wm.shell.bubbles.BadgedImageView; +import com.android.wm.shell.bubbles.BubbleOverflow; import com.android.wm.shell.bubbles.BubblePositioner; import com.android.wm.shell.bubbles.BubbleStackView; import com.android.wm.shell.common.magnetictarget.MagnetizedObject; @@ -63,6 +65,12 @@ public class ExpandedAnimationController /** Damping ratio for expand/collapse spring. */ private static final float DAMPING_RATIO_MEDIUM_LOW_BOUNCY = 0.65f; + /** + * Damping ratio for the overflow bubble spring; this is less bouncy so it doesn't bounce behind + * the top bubble when it goes to disappear. + */ + private static final float DAMPING_RATIO_OVERFLOW_BOUNCY = 0.90f; + /** Stiffness for the expand/collapse path-following animation. */ private static final int EXPAND_COLLAPSE_ANIM_STIFFNESS = 400; @@ -274,9 +282,14 @@ public class ExpandedAnimationController // of the screen where the bubble will be stacked. path.lineTo(stackedX, p.y); + // The overflow should animate to the collapse point, so 0 offset. + final boolean isOverflow = bubble instanceof BadgedImageView + && BubbleOverflow.KEY.equals(((BadgedImageView) bubble).getKey()); + final float offsetY = isOverflow + ? 0 + : Math.min(index, NUM_VISIBLE_WHEN_RESTING - 1) * mStackOffsetPx; // Then, draw a line down to the stack position. - path.lineTo(stackedX, mCollapsePoint.y - + Math.min(index, NUM_VISIBLE_WHEN_RESTING - 1) * mStackOffsetPx); + path.lineTo(stackedX, mCollapsePoint.y + offsetY); } // The lead bubble should be the bubble with the longest distance to travel when we're @@ -505,8 +518,12 @@ public class ExpandedAnimationController @Override SpringForce getSpringForce(DynamicAnimation.ViewProperty property, View view) { + boolean isOverflow = (view instanceof BadgedImageView) + && BubbleOverflow.KEY.equals(((BadgedImageView) view).getKey()); return new SpringForce() - .setDampingRatio(DAMPING_RATIO_MEDIUM_LOW_BOUNCY) + .setDampingRatio(isOverflow + ? DAMPING_RATIO_OVERFLOW_BOUNCY + : DAMPING_RATIO_MEDIUM_LOW_BOUNCY) .setStiffness(SpringForce.STIFFNESS_LOW); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/BubbleProperties.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/BubbleProperties.kt index 85aaa8ef585c..4206d9320b7d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/BubbleProperties.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/BubbleProperties.kt @@ -29,4 +29,7 @@ interface BubbleProperties { * When this is `false`, bubbles will be floating. */ val isBubbleBarEnabled: Boolean + + /** Refreshes the current value of [isBubbleBarEnabled]. */ + fun refresh() } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/ProdBubbleProperties.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/ProdBubbleProperties.kt index 9d8b9a6f3260..e1dea3babbc2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/ProdBubbleProperties.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/properties/ProdBubbleProperties.kt @@ -22,6 +22,13 @@ import android.os.SystemProperties object ProdBubbleProperties : BubbleProperties { // TODO(b/256873975) Should use proper flag when available to shell/launcher - override val isBubbleBarEnabled = - SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false) + private var _isBubbleBarEnabled = + SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false) + + override val isBubbleBarEnabled + get() = _isBubbleBarEnabled + + override fun refresh() { + _isBubbleBarEnabled = SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false) + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java index 5e42782431fd..e9344ffcce0c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java @@ -203,7 +203,7 @@ public class SystemWindows { + "SystemWindow:" + view); return null; } - return root.getFocusGrantToken(); + return root.getInputTransferToken(); } private class PerDisplay { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index 26b5a5052594..63cdb4f151ff 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -67,6 +67,7 @@ import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.InteractionJankMonitorUtils; +import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition; import com.android.wm.shell.common.split.SplitScreenConstants.SnapPosition; import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition; @@ -484,7 +485,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange } /** Updates divide position and split bounds base on the ratio within root bounds. */ - public void setDivideRatio(@SnapPosition int snapPosition) { + public void setDivideRatio(@PersistentSnapPosition int snapPosition) { final DividerSnapAlgorithm.SnapTarget snapTarget = mDividerSnapAlgorithm.findSnapTarget( snapPosition); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java index ff38b7e70410..e73430056c89 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java @@ -26,6 +26,16 @@ import android.annotation.IntDef; /** Helper utility class of methods and constants that are available to be imported in Launcher. */ public class SplitScreenConstants { + /** + * Duration used for every split fade-in or fade-out. + */ + public static final int FADE_DURATION = 133; + + /////////////// + // IMPORTANT for the following SPLIT_POSITION and SNAP_TO constants: + // These int values must not be changed -- they are persisted to user-defined app pairs, and + // will break things if changed. + // /** * Split position isn't specified normally meaning to use what ever it is currently set to. @@ -44,11 +54,6 @@ public class SplitScreenConstants { */ public static final int SPLIT_POSITION_BOTTOM_OR_RIGHT = 1; - /** - * Duration used for every split fade-in or fade-out. - */ - public static final int FADE_DURATION = 133; - @IntDef(prefix = {"SPLIT_POSITION_"}, value = { SPLIT_POSITION_UNDEFINED, SPLIT_POSITION_TOP_OR_LEFT, @@ -57,38 +62,61 @@ public class SplitScreenConstants { public @interface SplitPosition { } - /** The divider doesn't snap to any target and is freely placeable. */ - public static final int SNAP_TO_NONE = 0; - - /** A snap target positioned near the screen edge for a minimized task */ - public static final int SNAP_TO_MINIMIZE = 1; - - /** If the divider reaches this value, the left/top task should be dismissed. */ - public static final int SNAP_TO_START_AND_DISMISS = 2; - /** A snap target in the first half of the screen, where the split is roughly 30-70. */ - public static final int SNAP_TO_30_70 = 3; + public static final int SNAP_TO_30_70 = 0; /** The 50-50 snap target */ - public static final int SNAP_TO_50_50 = 4; + public static final int SNAP_TO_50_50 = 1; /** A snap target in the latter half of the screen, where the split is roughly 70-30. */ - public static final int SNAP_TO_70_30 = 5; + public static final int SNAP_TO_70_30 = 2; + + /** + * These snap targets are used for split pairs in a stable, non-transient state. They may be + * persisted in Launcher when the user saves an app pair. They are a subset of + * {@link SnapPosition}. + */ + @IntDef(prefix = { "SNAP_TO_" }, value = { + SNAP_TO_30_70, + SNAP_TO_50_50, + SNAP_TO_70_30 + }) + public @interface PersistentSnapPosition {} + + /** + * Checks if the snapPosition in question is a {@link PersistentSnapPosition}. + */ + public static boolean isPersistentSnapPosition(@SnapPosition int snapPosition) { + return snapPosition == SNAP_TO_30_70 + || snapPosition == SNAP_TO_50_50 + || snapPosition == SNAP_TO_70_30; + } + + /** The divider doesn't snap to any target and is freely placeable. */ + public static final int SNAP_TO_NONE = 10; + + /** If the divider reaches this value, the left/top task should be dismissed. */ + public static final int SNAP_TO_START_AND_DISMISS = 11; /** If the divider reaches this value, the right/bottom task should be dismissed. */ - public static final int SNAP_TO_END_AND_DISMISS = 6; + public static final int SNAP_TO_END_AND_DISMISS = 12; + + /** A snap target positioned near the screen edge for a minimized task */ + public static final int SNAP_TO_MINIMIZE = 13; @IntDef(prefix = { "SNAP_TO_" }, value = { - SNAP_TO_NONE, - SNAP_TO_MINIMIZE, - SNAP_TO_START_AND_DISMISS, SNAP_TO_30_70, SNAP_TO_50_50, SNAP_TO_70_30, - SNAP_TO_END_AND_DISMISS + SNAP_TO_NONE, + SNAP_TO_START_AND_DISMISS, + SNAP_TO_END_AND_DISMISS, + SNAP_TO_MINIMIZE }) public @interface SnapPosition {} + /////////////// + public static final int[] CONTROLLED_ACTIVITY_TYPES = {ACTIVITY_TYPE_STANDARD}; public static final int[] CONTROLLED_WINDOWING_MODES = {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED}; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index 998cd5d08c72..e6d3abcc6e1d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -25,6 +25,7 @@ import android.os.Handler; import android.os.SystemProperties; import android.view.IWindowManager; import android.view.accessibility.AccessibilityManager; +import android.window.SystemPerformanceHinter; import com.android.internal.logging.UiEventLogger; import com.android.launcher3.icons.IconProvider; @@ -85,6 +86,7 @@ import com.android.wm.shell.keyguard.KeyguardTransitionHandler; import com.android.wm.shell.keyguard.KeyguardTransitions; import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.onehanded.OneHandedController; +import com.android.wm.shell.performance.PerfHintController; import com.android.wm.shell.recents.RecentTasks; import com.android.wm.shell.recents.RecentTasksController; import com.android.wm.shell.recents.RecentsTransitionHandler; @@ -296,6 +298,17 @@ public abstract class WMShellBaseModule { return new LaunchAdjacentController(syncQueue); } + @WMSingleton + @Provides + static SystemPerformanceHinter provideSystemPerformanceHinter(Context context, + ShellInit shellInit, + ShellCommandHandler shellCommandHandler, + RootTaskDisplayAreaOrganizer rootTdaOrganizer) { + final PerfHintController perfHintController = + new PerfHintController(context, shellInit, shellCommandHandler, rootTdaOrganizer); + return perfHintController.getHinter(); + } + // // Back animation // diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index 9f9854e7e244..5dfba5e7ff1d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -199,6 +199,7 @@ public abstract class WMShellModule { @ShellMainThread Handler mainHandler, @ShellMainThread Choreographer mainChoreographer, ShellInit shellInit, + ShellCommandHandler shellCommandHandler, ShellTaskOrganizer taskOrganizer, DisplayController displayController, ShellController shellController, @@ -213,6 +214,7 @@ public abstract class WMShellModule { mainHandler, mainChoreographer, shellInit, + shellCommandHandler, taskOrganizer, displayController, shellController, @@ -492,13 +494,14 @@ public abstract class WMShellModule { ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler, @DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository, LaunchAdjacentController launchAdjacentController, + RecentsTransitionHandler recentsTransitionHandler, @ShellMainThread ShellExecutor mainExecutor ) { return new DesktopTasksController(context, shellInit, shellCommandHandler, shellController, displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, transitions, enterDesktopTransitionHandler, exitDesktopTransitionHandler, toggleResizeDesktopTaskTransitionHandler, desktopModeTaskRepository, - launchAdjacentController, mainExecutor); + launchAdjacentController, recentsTransitionHandler, mainExecutor); } @WMSingleton diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java index af97cf68915f..8a6403705c1c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java @@ -23,7 +23,7 @@ import com.android.wm.shell.common.pip.PipBoundsAlgorithm; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.dagger.WMShellBaseModule; import com.android.wm.shell.dagger.WMSingleton; -import com.android.wm.shell.pip2.PipTransition; +import com.android.wm.shell.pip2.phone.PipTransition; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java index 570f0a3db35a..f2631eff890d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/PipModule.java @@ -19,6 +19,7 @@ package com.android.wm.shell.dagger.pip; import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.dagger.WMSingleton; import com.android.wm.shell.pip.PipTransitionController; +import com.android.wm.shell.pip2.phone.PipTransition; import dagger.Module; import dagger.Provides; @@ -36,7 +37,7 @@ public abstract class PipModule { @Provides static PipTransitionController providePipTransitionController( com.android.wm.shell.pip.PipTransition legacyPipTransition, - com.android.wm.shell.pip2.PipTransition newPipTransition) { + PipTransition newPipTransition) { if (PipUtils.isPip2ExperimentEnabled()) { return newPipTransition; } else { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index 09ba4f79326e..412a5b5a6997 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -60,6 +60,8 @@ import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksListener import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.TO_DESKTOP_INDICATOR import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE +import com.android.wm.shell.recents.RecentsTransitionHandler +import com.android.wm.shell.recents.RecentsTransitionStateListener import com.android.wm.shell.splitscreen.SplitScreenController import com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_ENTER_DESKTOP import com.android.wm.shell.sysui.ShellCommandHandler @@ -68,7 +70,6 @@ import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.sysui.ShellSharedConstants import com.android.wm.shell.transition.OneShotRemoteHandler import com.android.wm.shell.transition.Transitions -import com.android.wm.shell.transition.Transitions.TransitionHandler import com.android.wm.shell.util.KtProtoLog import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration import com.android.wm.shell.windowdecor.MoveToDesktopAnimator @@ -93,6 +94,7 @@ class DesktopTasksController( ToggleResizeDesktopTaskTransitionHandler, private val desktopModeTaskRepository: DesktopModeTaskRepository, private val launchAdjacentController: LaunchAdjacentController, + private val recentsTransitionHandler: RecentsTransitionHandler, @ShellMainThread private val mainExecutor: ShellExecutor ) : RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler { @@ -119,6 +121,8 @@ class DesktopTasksController( com.android.wm.shell.R.dimen.desktop_mode_transition_area_width ) + private var recentsAnimationRunning = false + // This is public to avoid cyclic dependency; it is set by SplitScreenController lateinit var splitScreenController: SplitScreenController @@ -139,6 +143,19 @@ class DesktopTasksController( ) transitions.addHandler(this) desktopModeTaskRepository.addVisibleTasksListener(taskVisibilityListener, mainExecutor) + + recentsTransitionHandler.addTransitionStateListener( + object : RecentsTransitionStateListener { + override fun onAnimationStateChanged(running: Boolean) { + KtProtoLog.v( + WM_SHELL_DESKTOP_MODE, + "DesktopTasksController: recents animation state changed running=%b", + running + ) + recentsAnimationRunning = running + } + } + ) } /** Show all tasks, that are part of the desktop, on top of launcher */ @@ -644,6 +661,10 @@ class DesktopTasksController( val triggerTask = request.triggerTask val shouldHandleRequest = when { + recentsAnimationRunning -> { + reason = "recents animation is running" + false + } // Only handle open or to front transitions request.type != TRANSIT_OPEN && request.type != TRANSIT_TO_FRONT -> { reason = "transition type not handled (${request.type})" diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java index b71c48e16acb..53b5bd7ceb94 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java @@ -159,9 +159,15 @@ public class KeyguardTransitionHandler implements Transitions.TransitionHandler @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull TransitionFinishCallback finishCallback) { + + if (remoteHandler == null) { + ProtoLog.e(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, + "missing handler for keyguard %s transition", description); + return false; + } + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "start keyguard %s transition, info = %s", description, info); - try { mStartedTransitions.put(transition, new StartedTransition(info, finishTransaction, remoteHandler)); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/performance/PerfHintController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/performance/PerfHintController.kt new file mode 100644 index 000000000000..f7977f88006e --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/performance/PerfHintController.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2023 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.wm.shell.performance + +import android.content.Context +import android.os.PerformanceHintManager +import android.os.Process +import android.window.SystemPerformanceHinter +import com.android.wm.shell.RootTaskDisplayAreaOrganizer +import com.android.wm.shell.sysui.ShellCommandHandler +import com.android.wm.shell.sysui.ShellInit +import java.io.PrintWriter +import java.util.concurrent.TimeUnit + +/** + * Manages the performance hints to the system. + */ +class PerfHintController(private val mContext: Context, + shellInit: ShellInit, + private val mShellCommandHandler: ShellCommandHandler, + rootTdaOrganizer: RootTaskDisplayAreaOrganizer) { + + // The system perf hinter + val hinter: SystemPerformanceHinter + + init { + hinter = SystemPerformanceHinter(mContext, + rootTdaOrganizer.performanceRootProvider) + shellInit.addInitCallback(this::onInit, this) + } + + private fun onInit() { + mShellCommandHandler.addDumpCallback(this::dump, this) + val perfHintMgr = mContext.getSystemService(PerformanceHintManager::class.java) + val adpfSession = perfHintMgr!!.createHintSession(intArrayOf(Process.myTid()), + TimeUnit.SECONDS.toNanos(1)) + hinter.setAdpfSession(adpfSession) + } + + fun dump(pw: PrintWriter, prefix: String?) { + hinter.dump(pw, prefix) + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java index b8e4c04ac262..d704b091754f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java @@ -14,9 +14,14 @@ * limitations under the License. */ -package com.android.wm.shell.pip2; +package com.android.wm.shell.pip2.phone; + +import static android.view.WindowManager.TRANSIT_OPEN; import android.annotation.NonNull; +import android.app.ActivityManager; +import android.app.PictureInPictureParams; +import android.graphics.Rect; import android.os.IBinder; import android.view.SurfaceControl; import android.window.TransitionInfo; @@ -34,8 +39,13 @@ import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; -/** Placeholder, for demonstrate purpose only. */ +/** + * Implementation of transitions for PiP on phone. + */ public class PipTransition extends PipTransitionController { + @Nullable + private IBinder mAutoEnterButtonNavTransition; + public PipTransition( @NonNull ShellInit shellInit, @NonNull ShellTaskOrganizer shellTaskOrganizer, @@ -58,15 +68,63 @@ public class PipTransition extends PipTransitionController { @Override public WindowContainerTransaction handleRequest(@NonNull IBinder transition, @NonNull TransitionRequestInfo request) { + if (isAutoEnterInButtonNavigation(request)) { + mAutoEnterButtonNavTransition = transition; + return getEnterPipTransaction(transition, request); + } return null; } @Override + public void augmentRequest(@NonNull IBinder transition, @NonNull TransitionRequestInfo request, + @NonNull WindowContainerTransaction outWct) { + if (isAutoEnterInButtonNavigation(request)) { + outWct.merge(getEnterPipTransaction(transition, request), true /* transfer */); + mAutoEnterButtonNavTransition = transition; + } + } + + private WindowContainerTransaction getEnterPipTransaction(@NonNull IBinder transition, + @NonNull TransitionRequestInfo request) { + final ActivityManager.RunningTaskInfo pipTask = request.getPipTask(); + PictureInPictureParams pipParams = pipTask.pictureInPictureParams; + mPipBoundsState.setBoundsStateForEntry(pipTask.topActivity, pipTask.topActivityInfo, + pipParams, mPipBoundsAlgorithm); + + // calculate the entry bounds and notify core to move task to pinned with final bounds + final Rect entryBounds = mPipBoundsAlgorithm.getEntryDestinationBounds(); + WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.movePipActivityToPinnedRootTask(pipTask.token, entryBounds); + return wct; + } + + private boolean isAutoEnterInButtonNavigation(@NonNull TransitionRequestInfo requestInfo) { + final ActivityManager.RunningTaskInfo pipTask = requestInfo.getPipTask(); + if (pipTask == null) { + return false; + } + if (pipTask.pictureInPictureParams == null) { + return false; + } + + // Assuming auto-enter is enabled and pipTask is non-null, the TRANSIT_OPEN request type + // implies that we are entering PiP in button navigation mode. This is guaranteed by + // TaskFragment#startPausing()` in Core which wouldn't get called in gesture nav. + return requestInfo.getType() == TRANSIT_OPEN + && pipTask.pictureInPictureParams.isAutoEnterEnabled(); + } + + @Override public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { + if (transition == mAutoEnterButtonNavTransition) { + startTransaction.apply(); + finishCallback.onTransitionFinished(null); + return true; + } return false; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java index ead2f9cbd1ad..d31476c63890 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java @@ -54,6 +54,7 @@ import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.IResultReceiver; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.protolog.ShellProtoLogGroup; @@ -279,7 +280,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { mDeathHandler = () -> { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "[%d] RecentsController.DeathRecipient: binder died", mInstanceId); - finish(mWillFinishToHome, false /* leaveHint */); + finish(mWillFinishToHome, false /* leaveHint */, null /* finishCb */); }; try { mListener.asBinder().linkToDeath(mDeathHandler, 0 /* flags */); @@ -313,7 +314,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } } if (mFinishCB != null) { - finishInner(toHome, false /* userLeave */); + finishInner(toHome, false /* userLeave */, null /* finishCb */); } else { cleanUp(); } @@ -670,7 +671,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { // now and let it do its animation (since recents is going to be occluded). sendCancelWithSnapshots(); mExecutor.executeDelayed( - () -> finishInner(true /* toHome */, false /* userLeaveHint */), 0); + () -> finishInner(true /* toHome */, false /* userLeaveHint */, + null /* finishCb */), 0); return; } if (recentsOpening != null) { @@ -899,11 +901,12 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { @Override @SuppressLint("NewApi") - public void finish(boolean toHome, boolean sendUserLeaveHint) { - mExecutor.execute(() -> finishInner(toHome, sendUserLeaveHint)); + public void finish(boolean toHome, boolean sendUserLeaveHint, IResultReceiver finishCb) { + mExecutor.execute(() -> finishInner(toHome, sendUserLeaveHint, finishCb)); } - private void finishInner(boolean toHome, boolean sendUserLeaveHint) { + private void finishInner(boolean toHome, boolean sendUserLeaveHint, + IResultReceiver runnerFinishCb) { if (mFinishCB == null) { Slog.e(TAG, "Duplicate call to finish"); return; @@ -993,6 +996,16 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } cleanUp(); finishCB.onTransitionFinished(wct.isEmpty() ? null : wct); + if (runnerFinishCb != null) { + try { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + "[%d] RecentsController.finishInner: calling finish callback", + mInstanceId); + runnerFinishCb.send(0, null); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to report transition finished", e); + } + } } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index ccffa02a22c1..664d44910e72 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -23,6 +23,7 @@ import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.RemoteAnimationTarget.MODE_OPENING; + import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; @@ -85,7 +86,7 @@ import com.android.wm.shell.common.SingleInstanceRemoteListener; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.annotations.ExternalThread; -import com.android.wm.shell.common.split.SplitScreenConstants.SnapPosition; +import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition; import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition; import com.android.wm.shell.common.split.SplitScreenUtils; import com.android.wm.shell.desktopmode.DesktopTasksController; @@ -601,7 +602,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo, @Nullable Bundle options1, int taskId, @Nullable Bundle options2, - @SplitPosition int splitPosition, @SnapPosition int snapPosition, + @SplitPosition int splitPosition, @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId) { if (options1 == null) options1 = new Bundle(); final ActivityOptions activityOptions = ActivityOptions.fromBundle(options1); @@ -632,7 +633,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, void startShortcutAndTask(ShortcutInfo shortcutInfo, @Nullable Bundle options1, int taskId, @Nullable Bundle options2, @SplitPosition int splitPosition, - @SnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition, + @PersistentSnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { if (options1 == null) options1 = new Bundle(); final ActivityOptions activityOptions = ActivityOptions.fromBundle(options1); @@ -675,7 +676,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, private void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, int userId1, @Nullable Bundle options1, int taskId, @Nullable Bundle options2, - @SplitPosition int splitPosition, @SnapPosition int snapPosition, + @SplitPosition int splitPosition, @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId) { Intent fillInIntent = null; final String packageName1 = SplitScreenUtils.getPackageName(pendingIntent); @@ -702,7 +703,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, private void startIntentAndTask(PendingIntent pendingIntent, int userId1, @Nullable Bundle options1, int taskId, @Nullable Bundle options2, - @SplitPosition int splitPosition, @SnapPosition int snapPosition, + @SplitPosition int splitPosition, @PersistentSnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { Intent fillInIntent = null; final String packageName1 = SplitScreenUtils.getPackageName(pendingIntent); @@ -736,7 +737,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, @Nullable ShortcutInfo shortcutInfo1, @Nullable Bundle options1, PendingIntent pendingIntent2, int userId2, @Nullable ShortcutInfo shortcutInfo2, @Nullable Bundle options2, @SplitPosition int splitPosition, - @SnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId) { + @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter, + InstanceId instanceId) { Intent fillInIntent1 = null; Intent fillInIntent2 = null; final String packageName1 = SplitScreenUtils.getPackageName(pendingIntent1); @@ -767,7 +769,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, @Nullable ShortcutInfo shortcutInfo1, @Nullable Bundle options1, PendingIntent pendingIntent2, int userId2, @Nullable ShortcutInfo shortcutInfo2, @Nullable Bundle options2, @SplitPosition int splitPosition, - @SnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition, + @PersistentSnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { Intent fillInIntent1 = null; Intent fillInIntent2 = null; @@ -1225,7 +1227,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, @Override public void startTasksWithLegacyTransition(int taskId1, @Nullable Bundle options1, int taskId2, @Nullable Bundle options2, @SplitPosition int splitPosition, - @SnapPosition int snapPosition, RemoteAnimationAdapter adapter, + @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId) { executeRemoteCallWithTaskPermission(mController, "startTasks", (controller) -> controller.mStageCoordinator.startTasksWithLegacyTransition( @@ -1236,7 +1238,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, @Override public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, int userId1, Bundle options1, int taskId, Bundle options2, int splitPosition, - @SnapPosition int snapPosition, RemoteAnimationAdapter adapter, + @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId) { executeRemoteCallWithTaskPermission(mController, "startIntentAndTaskWithLegacyTransition", (controller) -> @@ -1248,7 +1250,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, @Override public void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo, @Nullable Bundle options1, int taskId, @Nullable Bundle options2, - @SplitPosition int splitPosition, @SnapPosition int snapPosition, + @SplitPosition int splitPosition, @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId) { executeRemoteCallWithTaskPermission(mController, "startShortcutAndTaskWithLegacyTransition", (controller) -> @@ -1260,8 +1262,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, @Override public void startTasks(int taskId1, @Nullable Bundle options1, int taskId2, @Nullable Bundle options2, @SplitPosition int splitPosition, - @SnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition, - InstanceId instanceId) { + @PersistentSnapPosition int snapPosition, + @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { executeRemoteCallWithTaskPermission(mController, "startTasks", (controller) -> controller.mStageCoordinator.startTasks(taskId1, options1, taskId2, options2, splitPosition, snapPosition, remoteTransition, @@ -1271,7 +1273,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, @Override public void startIntentAndTask(PendingIntent pendingIntent, int userId1, @Nullable Bundle options1, int taskId, @Nullable Bundle options2, - @SplitPosition int splitPosition, @SnapPosition int snapPosition, + @SplitPosition int splitPosition, @PersistentSnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { executeRemoteCallWithTaskPermission(mController, "startIntentAndTask", (controller) -> controller.startIntentAndTask(pendingIntent, userId1, options1, @@ -1282,8 +1284,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, @Override public void startShortcutAndTask(ShortcutInfo shortcutInfo, @Nullable Bundle options1, int taskId, @Nullable Bundle options2, @SplitPosition int splitPosition, - @SnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition, - InstanceId instanceId) { + @PersistentSnapPosition int snapPosition, + @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { executeRemoteCallWithTaskPermission(mController, "startShortcutAndTask", (controller) -> controller.startShortcutAndTask(shortcutInfo, options1, taskId, options2, splitPosition, snapPosition, remoteTransition, instanceId)); @@ -1294,7 +1296,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, @Nullable ShortcutInfo shortcutInfo1, @Nullable Bundle options1, PendingIntent pendingIntent2, int userId2, @Nullable ShortcutInfo shortcutInfo2, @Nullable Bundle options2, @SplitPosition int splitPosition, - @SnapPosition int snapPosition, RemoteAnimationAdapter adapter, + @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId) { executeRemoteCallWithTaskPermission(mController, "startIntentsWithLegacyTransition", (controller) -> @@ -1309,8 +1311,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, @Nullable ShortcutInfo shortcutInfo1, @Nullable Bundle options1, PendingIntent pendingIntent2, int userId2, @Nullable ShortcutInfo shortcutInfo2, @Nullable Bundle options2, @SplitPosition int splitPosition, - @SnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition, - InstanceId instanceId) { + @PersistentSnapPosition int snapPosition, + @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { executeRemoteCallWithTaskPermission(mController, "startIntents", (controller) -> controller.startIntents(pendingIntent1, userId1, shortcutInfo1, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 4ea14f473c39..b2948667f9e6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -128,7 +128,7 @@ import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.split.SplitLayout; -import com.android.wm.shell.common.split.SplitScreenConstants.SnapPosition; +import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition; import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition; import com.android.wm.shell.common.split.SplitScreenUtils; import com.android.wm.shell.common.split.SplitWindowManager; @@ -143,6 +143,8 @@ import com.android.wm.shell.util.SplitBounds; import com.android.wm.shell.util.TransitionUtil; import com.android.wm.shell.windowdecor.WindowDecorViewModel; +import dalvik.annotation.optimization.NeverCompile; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashSet; @@ -633,7 +635,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, /** Starts 2 tasks in one transition. */ void startTasks(int taskId1, @Nullable Bundle options1, int taskId2, @Nullable Bundle options2, - @SplitPosition int splitPosition, @SnapPosition int snapPosition, + @SplitPosition int splitPosition, @PersistentSnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { final WindowContainerTransaction wct = new WindowContainerTransaction(); if (taskId2 == INVALID_TASK_ID) { @@ -661,7 +663,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, /** Start an intent and a task to a split pair in one transition. */ void startIntentAndTask(PendingIntent pendingIntent, Intent fillInIntent, @Nullable Bundle options1, int taskId, @Nullable Bundle options2, - @SplitPosition int splitPosition, @SnapPosition int snapPosition, + @SplitPosition int splitPosition, @PersistentSnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { final WindowContainerTransaction wct = new WindowContainerTransaction(); if (taskId == INVALID_TASK_ID) { @@ -683,7 +685,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, /** Starts a shortcut and a task to a split pair in one transition. */ void startShortcutAndTask(ShortcutInfo shortcutInfo, @Nullable Bundle options1, int taskId, @Nullable Bundle options2, @SplitPosition int splitPosition, - @SnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition, + @PersistentSnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { final WindowContainerTransaction wct = new WindowContainerTransaction(); if (taskId == INVALID_TASK_ID) { @@ -710,7 +712,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, * {@link SplitscreenEventLogger#logEnter(float, int, int, int, int, boolean)} */ private void startWithTask(WindowContainerTransaction wct, int mainTaskId, - @Nullable Bundle mainOptions, @SnapPosition int snapPosition, + @Nullable Bundle mainOptions, @PersistentSnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { if (!mMainStage.isActive()) { // Build a request WCT that will launch both apps such that task 0 is on the main stage @@ -744,7 +746,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, @Nullable ShortcutInfo shortcutInfo1, @Nullable Bundle options1, PendingIntent pendingIntent2, Intent fillInIntent2, @Nullable ShortcutInfo shortcutInfo2, @Nullable Bundle options2, - @SplitPosition int splitPosition, @SnapPosition int snapPosition, + @SplitPosition int splitPosition, @PersistentSnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { final WindowContainerTransaction wct = new WindowContainerTransaction(); if (pendingIntent2 == null) { @@ -796,7 +798,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, /** Starts a pair of tasks using legacy transition. */ void startTasksWithLegacyTransition(int taskId1, @Nullable Bundle options1, int taskId2, @Nullable Bundle options2, @SplitPosition int splitPosition, - @SnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId) { + @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter, + InstanceId instanceId) { final WindowContainerTransaction wct = new WindowContainerTransaction(); if (options1 == null) options1 = new Bundle(); if (taskId2 == INVALID_TASK_ID) { @@ -826,7 +829,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, @Nullable ShortcutInfo shortcutInfo1, @Nullable Bundle options1, @Nullable PendingIntent pendingIntent2, Intent fillInIntent2, @Nullable ShortcutInfo shortcutInfo2, @Nullable Bundle options2, - @SplitPosition int splitPosition, @SnapPosition int snapPosition, + @SplitPosition int splitPosition, @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId) { final WindowContainerTransaction wct = new WindowContainerTransaction(); if (options1 == null) options1 = new Bundle(); @@ -851,7 +854,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, Intent fillInIntent, @Nullable Bundle options1, int taskId, @Nullable Bundle options2, - @SplitPosition int splitPosition, @SnapPosition int snapPosition, + @SplitPosition int splitPosition, @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId) { final WindowContainerTransaction wct = new WindowContainerTransaction(); if (options1 == null) options1 = new Bundle(); @@ -872,7 +875,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, /** Starts a pair of shortcut and task using legacy transition. */ void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo, @Nullable Bundle options1, int taskId, @Nullable Bundle options2, - @SplitPosition int splitPosition, @SnapPosition int snapPosition, + @SplitPosition int splitPosition, @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId) { final WindowContainerTransaction wct = new WindowContainerTransaction(); if (options1 == null) options1 = new Bundle(); @@ -934,7 +937,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, private void startWithLegacyTransition(WindowContainerTransaction wct, @Nullable PendingIntent mainPendingIntent, @Nullable Intent mainFillInIntent, @Nullable ShortcutInfo mainShortcutInfo, @Nullable Bundle mainOptions, - @SplitPosition int sidePosition, @SnapPosition int snapPosition, + @SplitPosition int sidePosition, @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId) { startWithLegacyTransition(wct, INVALID_TASK_ID, mainPendingIntent, mainFillInIntent, mainShortcutInfo, mainOptions, sidePosition, snapPosition, adapter, instanceId); @@ -942,7 +945,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, private void startWithLegacyTransition(WindowContainerTransaction wct, int mainTaskId, @Nullable Bundle mainOptions, @SplitPosition int sidePosition, - @SnapPosition int snapPosition, RemoteAnimationAdapter adapter, + @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId) { startWithLegacyTransition(wct, mainTaskId, null /* mainPendingIntent */, null /* mainFillInIntent */, null /* mainShortcutInfo */, mainOptions, sidePosition, @@ -957,7 +960,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, private void startWithLegacyTransition(WindowContainerTransaction wct, int mainTaskId, @Nullable PendingIntent mainPendingIntent, @Nullable Intent mainFillInIntent, @Nullable ShortcutInfo mainShortcutInfo, @Nullable Bundle options, - @SplitPosition int sidePosition, @SnapPosition int snapPosition, + @SplitPosition int sidePosition, @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId) { if (!isSplitScreenVisible()) { exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RECREATE_SPLIT); @@ -3108,6 +3111,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, null /* taskInfo */, false /* allowEnterPip */, TYPE_DOCK_DIVIDER); } + @NeverCompile @Override public void dump(@NonNull PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java index 83dc7fa5e869..e828eedc275c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java @@ -23,6 +23,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; + import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED; import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA; @@ -693,9 +694,19 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { + Transitions.TransitionFinishCallback finishCB = wct -> { + mixed.mInFlightSubAnimations--; + if (mixed.mInFlightSubAnimations == 0) { + mActiveTransitions.remove(mixed); + finishCallback.onTransitionFinished(wct); + } + }; + + mixed.mInFlightSubAnimations++; boolean consumed = mRecentsHandler.startAnimation( - mixed.mTransition, info, startTransaction, finishTransaction, finishCallback); + mixed.mTransition, info, startTransaction, finishTransaction, finishCB); if (!consumed) { + mixed.mInFlightSubAnimations--; return false; } if (mDesktopTasksController != null) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/SplitBounds.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/SplitBounds.java index a68b41d6563a..3e06d2d0e797 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/SplitBounds.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/SplitBounds.java @@ -19,7 +19,7 @@ import android.graphics.Rect; import android.os.Parcel; import android.os.Parcelable; -import com.android.wm.shell.common.split.SplitScreenConstants.SnapPosition; +import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition; import java.util.Objects; @@ -39,7 +39,7 @@ public class SplitBounds implements Parcelable { public final float leftTaskPercent; public final float dividerWidthPercent; public final float dividerHeightPercent; - public final @SnapPosition int snapPosition; + public final @PersistentSnapPosition int snapPosition; /** * If {@code true}, that means at the time of creation of this object, the * split-screened apps were vertically stacked. This is useful in scenarios like @@ -51,7 +51,7 @@ public class SplitBounds implements Parcelable { public final int rightBottomTaskId; public SplitBounds(Rect leftTopBounds, Rect rightBottomBounds, int leftTopTaskId, - int rightBottomTaskId, @SnapPosition int snapPosition) { + int rightBottomTaskId, @PersistentSnapPosition int snapPosition) { this.leftTopBounds = leftTopBounds; this.rightBottomBounds = rightBottomBounds; this.leftTopTaskId = leftTopTaskId; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index afa2754803f1..bf99ab35cdd7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -79,11 +79,13 @@ import com.android.wm.shell.recents.RecentsTransitionStateListener; import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.sysui.KeyguardChangeListener; +import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.ExclusionRegionListener; +import java.io.PrintWriter; import java.util.Optional; import java.util.function.Supplier; @@ -97,6 +99,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private final DesktopModeWindowDecoration.Factory mDesktopModeWindowDecorFactory; private final ActivityTaskManager mActivityTaskManager; + private final ShellCommandHandler mShellCommandHandler; private final ShellTaskOrganizer mTaskOrganizer; private final ShellController mShellController; private final Context mContext; @@ -134,6 +137,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { Handler mainHandler, Choreographer mainChoreographer, ShellInit shellInit, + ShellCommandHandler shellCommandHandler, ShellTaskOrganizer taskOrganizer, DisplayController displayController, ShellController shellController, @@ -148,6 +152,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mainHandler, mainChoreographer, shellInit, + shellCommandHandler, taskOrganizer, displayController, shellController, @@ -167,6 +172,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { Handler mainHandler, Choreographer mainChoreographer, ShellInit shellInit, + ShellCommandHandler shellCommandHandler, ShellTaskOrganizer taskOrganizer, DisplayController displayController, ShellController shellController, @@ -189,7 +195,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mTransitions = transitions; mDesktopTasksController = desktopTasksController; mRecentsTransitionHandler = recentsTransitionHandler; - + mShellCommandHandler = shellCommandHandler; mDesktopModeWindowDecorFactory = desktopModeWindowDecorFactory; mInputMonitorFactory = inputMonitorFactory; mTransactionFactory = transactionFactory; @@ -206,6 +212,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { onRecentsTransitionStarted(transition); } }); + mShellCommandHandler.addDumpCallback(this::dump, this); } @Override @@ -369,7 +376,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { public void onClick(View v) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId); final int id = v.getId(); - if (id == R.id.close_window || id == R.id.close_button) { + if (id == R.id.close_window) { mTaskOperations.closeTask(mTaskToken); if (isTaskInSplitScreen(mTaskId)) { RunningTaskInfo remainingTask = getOtherSplitTask(mTaskId); @@ -593,6 +600,15 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { super.dispose(); } + @Override + public String toString() { + return "EventReceiver" + + "{" + + "tasksOnDisplay=" + + mTasksOnDisplay + + "}"; + } + private void incrementTaskNumber() { mTasksOnDisplay++; } @@ -981,6 +997,15 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { && mSplitScreenController.isTaskInSplitScreen(taskId); } + private void dump(PrintWriter pw, String prefix) { + final String innerPrefix = prefix + " "; + pw.println(prefix + "DesktopModeWindowDecorViewModel"); + pw.println(innerPrefix + "DesktopModeStatus=" + DesktopModeStatus.isEnabled()); + pw.println(innerPrefix + "mTransitionDragActive=" + mTransitionDragActive); + pw.println(innerPrefix + "mEventReceiversByDisplay=" + mEventReceiversByDisplay); + pw.println(innerPrefix + "mWindowDecorByTaskId=" + mWindowDecorByTaskId); + } + private class DragStartListenerImpl implements DragPositioningCallbackUtility.DragStartListener { @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index 84ec6b389c4a..380b59e84485 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -18,6 +18,7 @@ package com.android.wm.shell.windowdecor; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.windowingModeToString; import android.app.ActivityManager; import android.app.WindowConfiguration.WindowingMode; @@ -661,6 +662,17 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mRelayoutBlock++; } + @Override + public String toString() { + return "{" + + "mPositionInParent=" + mPositionInParent + ", " + + "mRelayoutBlock=" + mRelayoutBlock + ", " + + "taskId=" + mTaskInfo.taskId + ", " + + "windowingMode=" + windowingModeToString(mTaskInfo.getWindowingMode()) + ", " + + "isFocused=" + isFocused() + + "}"; + } + static class Factory { DesktopModeWindowDecoration create( diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java index a7a11dee80f2..15f8f1cfadf2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java @@ -42,7 +42,6 @@ import android.widget.TextView; import android.window.SurfaceSyncGroup; import com.android.wm.shell.R; -import com.android.wm.shell.desktopmode.DesktopModeStatus; /** * Handle menu opened when the appropriate button is clicked on. @@ -56,12 +55,8 @@ class HandleMenu { private static final String TAG = "HandleMenu"; private final Context mContext; private final WindowDecoration mParentDecor; - private WindowDecoration.AdditionalWindow mAppInfoPill; - private WindowDecoration.AdditionalWindow mWindowingPill; - private WindowDecoration.AdditionalWindow mMoreActionsPill; - private final PointF mAppInfoPillPosition = new PointF(); - private final PointF mWindowingPillPosition = new PointF(); - private final PointF mMoreActionsPillPosition = new PointF(); + private WindowDecoration.AdditionalWindow mHandleMenuWindow; + private final PointF mHandleMenuPosition = new PointF(); private final boolean mShouldShowWindowingPill; private final Drawable mAppIcon; private final CharSequence mAppName; @@ -73,13 +68,8 @@ class HandleMenu { private final int mCaptionY; private int mMarginMenuTop; private int mMarginMenuStart; - private int mMarginMenuSpacing; + private int mMenuHeight; private int mMenuWidth; - private int mAppInfoPillHeight; - private int mWindowingPillHeight; - private int mMoreActionsPillHeight; - private int mShadowRadius; - private int mCornerRadius; HandleMenu(WindowDecoration parentDecor, int layoutResId, int captionX, int captionY, @@ -104,102 +94,86 @@ class HandleMenu { final SurfaceSyncGroup ssg = new SurfaceSyncGroup(TAG); SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - createAppInfoPill(t, ssg); - if (mShouldShowWindowingPill) { - createWindowingPill(t, ssg); - } - createMoreActionsPill(t, ssg); + createHandleMenuWindow(t, ssg); ssg.addTransaction(t); ssg.markSyncReady(); setupHandleMenu(); } - private void createAppInfoPill(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) { - final int x = (int) mAppInfoPillPosition.x; - final int y = (int) mAppInfoPillPosition.y; - mAppInfoPill = mParentDecor.addWindow( - R.layout.desktop_mode_window_decor_handle_menu_app_info_pill, - "Menu's app info pill", - t, ssg, x, y, mMenuWidth, mAppInfoPillHeight, mShadowRadius, mCornerRadius); + private void createHandleMenuWindow(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) { + final int x = (int) mHandleMenuPosition.x; + final int y = (int) mHandleMenuPosition.y; + mHandleMenuWindow = mParentDecor.addWindow( + R.layout.desktop_mode_window_decor_handle_menu, "Handle Menu", + t, ssg, x, y, mMenuWidth, mMenuHeight); } - private void createWindowingPill(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) { - final int x = (int) mWindowingPillPosition.x; - final int y = (int) mWindowingPillPosition.y; - mWindowingPill = mParentDecor.addWindow( - R.layout.desktop_mode_window_decor_handle_menu_windowing_pill, - "Menu's windowing pill", - t, ssg, x, y, mMenuWidth, mWindowingPillHeight, mShadowRadius, mCornerRadius); - } - - private void createMoreActionsPill(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) { - final int x = (int) mMoreActionsPillPosition.x; - final int y = (int) mMoreActionsPillPosition.y; - mMoreActionsPill = mParentDecor.addWindow( - R.layout.desktop_mode_window_decor_handle_menu_more_actions_pill, - "Menu's more actions pill", - t, ssg, x, y, mMenuWidth, mMoreActionsPillHeight, mShadowRadius, mCornerRadius); + /** + * Set up all three pills of the handle menu: app info pill, windowing pill, & more actions + * pill. + */ + private void setupHandleMenu() { + final View handleMenu = mHandleMenuWindow.mWindowViewHost.getView(); + handleMenu.setOnTouchListener(mOnTouchListener); + setupAppInfoPill(handleMenu); + if (mShouldShowWindowingPill) { + setupWindowingPill(handleMenu); + } + setupMoreActionsPill(handleMenu); } /** - * Set up interactive elements and color of this handle menu + * Set up interactive elements of handle menu's app info pill. */ - private void setupHandleMenu() { - // App Info pill setup. - final View appInfoPillView = mAppInfoPill.mWindowViewHost.getView(); - final ImageButton collapseBtn = appInfoPillView.findViewById(R.id.collapse_menu_button); - final ImageView appIcon = appInfoPillView.findViewById(R.id.application_icon); - final TextView appName = appInfoPillView.findViewById(R.id.application_name); + private void setupAppInfoPill(View handleMenu) { + final ImageButton collapseBtn = handleMenu.findViewById(R.id.collapse_menu_button); + final ImageView appIcon = handleMenu.findViewById(R.id.application_icon); + final TextView appName = handleMenu.findViewById(R.id.application_name); collapseBtn.setOnClickListener(mOnClickListener); - appInfoPillView.setOnTouchListener(mOnTouchListener); appIcon.setImageDrawable(mAppIcon); appName.setText(mAppName); + } - // Windowing pill setup. - if (mShouldShowWindowingPill) { - final View windowingPillView = mWindowingPill.mWindowViewHost.getView(); - final ImageButton fullscreenBtn = windowingPillView.findViewById( - R.id.fullscreen_button); - final ImageButton splitscreenBtn = windowingPillView.findViewById( - R.id.split_screen_button); - final ImageButton floatingBtn = windowingPillView.findViewById(R.id.floating_button); - // TODO: Remove once implemented. - floatingBtn.setVisibility(View.GONE); - - final ImageButton desktopBtn = windowingPillView.findViewById(R.id.desktop_button); - fullscreenBtn.setOnClickListener(mOnClickListener); - splitscreenBtn.setOnClickListener(mOnClickListener); - floatingBtn.setOnClickListener(mOnClickListener); - desktopBtn.setOnClickListener(mOnClickListener); - // The button corresponding to the windowing mode that the task is currently in uses a - // different color than the others. - final int[] iconColors = getWindowingIconColor(); - final ColorStateList inActiveColorStateList = ColorStateList.valueOf(iconColors[0]); - final ColorStateList activeColorStateList = ColorStateList.valueOf(iconColors[1]); - fullscreenBtn.setImageTintList( - mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN - ? activeColorStateList : inActiveColorStateList); - splitscreenBtn.setImageTintList( - mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW - ? activeColorStateList : inActiveColorStateList); - floatingBtn.setImageTintList(mTaskInfo.getWindowingMode() == WINDOWING_MODE_PINNED - ? activeColorStateList : inActiveColorStateList); - desktopBtn.setImageTintList(mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM - ? activeColorStateList : inActiveColorStateList); - } + /** + * Set up interactive elements and color of handle menu's windowing pill. + */ + private void setupWindowingPill(View handleMenu) { + final ImageButton fullscreenBtn = handleMenu.findViewById( + R.id.fullscreen_button); + final ImageButton splitscreenBtn = handleMenu.findViewById( + R.id.split_screen_button); + final ImageButton floatingBtn = handleMenu.findViewById(R.id.floating_button); + // TODO: Remove once implemented. + floatingBtn.setVisibility(View.GONE); + + final ImageButton desktopBtn = handleMenu.findViewById(R.id.desktop_button); + fullscreenBtn.setOnClickListener(mOnClickListener); + splitscreenBtn.setOnClickListener(mOnClickListener); + floatingBtn.setOnClickListener(mOnClickListener); + desktopBtn.setOnClickListener(mOnClickListener); + // The button corresponding to the windowing mode that the task is currently in uses a + // different color than the others. + final ColorStateList[] iconColors = getWindowingIconColor(); + final ColorStateList inActiveColorStateList = iconColors[0]; + final ColorStateList activeColorStateList = iconColors[1]; + final int windowingMode = mTaskInfo.getWindowingMode(); + fullscreenBtn.setImageTintList(windowingMode == WINDOWING_MODE_FULLSCREEN + ? activeColorStateList : inActiveColorStateList); + splitscreenBtn.setImageTintList(windowingMode == WINDOWING_MODE_MULTI_WINDOW + ? activeColorStateList : inActiveColorStateList); + floatingBtn.setImageTintList(windowingMode == WINDOWING_MODE_PINNED + ? activeColorStateList : inActiveColorStateList); + desktopBtn.setImageTintList(windowingMode == WINDOWING_MODE_FREEFORM + ? activeColorStateList : inActiveColorStateList); + } - // More Actions pill setup. - final View moreActionsPillView = mMoreActionsPill.mWindowViewHost.getView(); - final Button closeBtn = moreActionsPillView.findViewById(R.id.close_button); - if (shouldShowCloseButton()) { - closeBtn.setVisibility(View.GONE); - } else { - closeBtn.setVisibility(View.VISIBLE); - closeBtn.setOnClickListener(mOnClickListener); - } - final Button selectBtn = moreActionsPillView.findViewById(R.id.select_button); + /** + * Set up interactive elements & height of handle menu's more actions pill + */ + private void setupMoreActionsPill(View handleMenu) { + final Button selectBtn = handleMenu.findViewById(R.id.select_button); selectBtn.setOnClickListener(mOnClickListener); - final Button screenshotBtn = moreActionsPillView.findViewById(R.id.screenshot_button); + final Button screenshotBtn = handleMenu.findViewById(R.id.screenshot_button); // TODO: Remove once implemented. screenshotBtn.setVisibility(View.GONE); } @@ -208,7 +182,7 @@ class HandleMenu { * Returns array of windowing icon color based on current UI theme. First element of the * array is for inactive icons and the second is for active icons. */ - private int[] getWindowingIconColor() { + private ColorStateList[] getWindowingIconColor() { final int mode = mContext.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; final boolean isNightMode = (mode == Configuration.UI_MODE_NIGHT_YES); @@ -218,11 +192,12 @@ class HandleMenu { final int inActiveColor = typedArray.getColor(0, isNightMode ? Color.WHITE : Color.BLACK); final int activeColor = typedArray.getColor(1, isNightMode ? Color.WHITE : Color.BLACK); typedArray.recycle(); - return new int[] {inActiveColor, activeColor}; + return new ColorStateList[]{ColorStateList.valueOf(inActiveColor), + ColorStateList.valueOf(activeColor)}; } /** - * Updates the handle menu pills' position variables to reflect their next positions + * Updates handle menu's position variables to reflect its next position. */ private void updateHandleMenuPillPositions() { final int menuX, menuY; @@ -239,39 +214,19 @@ class HandleMenu { menuY = mCaptionY + mMarginMenuStart; } - // App Info pill setup. - final int appInfoPillY = menuY; - mAppInfoPillPosition.set(menuX, appInfoPillY); + // Handle Menu position setup. + mHandleMenuPosition.set(menuX, menuY); - final int windowingPillY, moreActionsPillY; - if (mShouldShowWindowingPill) { - windowingPillY = appInfoPillY + mAppInfoPillHeight + mMarginMenuSpacing; - mWindowingPillPosition.set(menuX, windowingPillY); - moreActionsPillY = windowingPillY + mWindowingPillHeight + mMarginMenuSpacing; - mMoreActionsPillPosition.set(menuX, moreActionsPillY); - } else { - // Just start after the end of the app info pill + margins. - moreActionsPillY = appInfoPillY + mAppInfoPillHeight + mMarginMenuSpacing; - mMoreActionsPillPosition.set(menuX, moreActionsPillY); - } } /** * Update pill layout, in case task changes have caused positioning to change. */ void relayout(SurfaceControl.Transaction t) { - if (mAppInfoPill != null) { + if (mHandleMenuWindow != null) { updateHandleMenuPillPositions(); - t.setPosition(mAppInfoPill.mWindowSurface, - mAppInfoPillPosition.x, mAppInfoPillPosition.y); - // Only show windowing buttons in proto2. Proto1 uses a system-level mode only. - final boolean shouldShowWindowingPill = DesktopModeStatus.isEnabled(); - if (shouldShowWindowingPill) { - t.setPosition(mWindowingPill.mWindowSurface, - mWindowingPillPosition.x, mWindowingPillPosition.y); - } - t.setPosition(mMoreActionsPill.mWindowSurface, - mMoreActionsPillPosition.x, mMoreActionsPillPosition.y); + t.setPosition(mHandleMenuWindow.mWindowSurface, + mHandleMenuPosition.x, mHandleMenuPosition.y); } } @@ -283,12 +238,12 @@ class HandleMenu { * @param ev the MotionEvent to compare against. */ void checkClickEvent(MotionEvent ev) { - final View appInfoPill = mAppInfoPill.mWindowViewHost.getView(); - final ImageButton collapse = appInfoPill.findViewById(R.id.collapse_menu_button); + final View handleMenu = mHandleMenuWindow.mWindowViewHost.getView(); + final ImageButton collapse = handleMenu.findViewById(R.id.collapse_menu_button); // Translate the input point from display coordinates to the same space as the collapse // button, meaning its parent (app info pill view). - final PointF inputPoint = new PointF(ev.getX() - mAppInfoPillPosition.x, - ev.getY() - mAppInfoPillPosition.y); + final PointF inputPoint = new PointF(ev.getX() - mHandleMenuPosition.x, + ev.getY() - mHandleMenuPosition.y); if (pointInView(collapse, inputPoint.x, inputPoint.y)) { mOnClickListener.onClick(collapse); } @@ -303,23 +258,10 @@ class HandleMenu { */ boolean isValidMenuInput(PointF inputPoint) { if (!viewsLaidOut()) return true; - final boolean pointInAppInfoPill = pointInView( - mAppInfoPill.mWindowViewHost.getView(), - inputPoint.x - mAppInfoPillPosition.x, - inputPoint.y - mAppInfoPillPosition.y); - boolean pointInWindowingPill = false; - if (mWindowingPill != null) { - pointInWindowingPill = pointInView( - mWindowingPill.mWindowViewHost.getView(), - inputPoint.x - mWindowingPillPosition.x, - inputPoint.y - mWindowingPillPosition.y); - } - final boolean pointInMoreActionsPill = pointInView( - mMoreActionsPill.mWindowViewHost.getView(), - inputPoint.x - mMoreActionsPillPosition.x, - inputPoint.y - mMoreActionsPillPosition.y); - - return pointInAppInfoPill || pointInWindowingPill || pointInMoreActionsPill; + return pointInView( + mHandleMenuWindow.mWindowViewHost.getView(), + inputPoint.x - mHandleMenuPosition.x, + inputPoint.y - mHandleMenuPosition.y); } private boolean pointInView(View v, float x, float y) { @@ -331,33 +273,31 @@ class HandleMenu { * Check if the views for handle menu can be seen. */ private boolean viewsLaidOut() { - return mAppInfoPill.mWindowViewHost.getView().isLaidOut(); + return mHandleMenuWindow.mWindowViewHost.getView().isLaidOut(); } - private void loadHandleMenuDimensions() { final Resources resources = mContext.getResources(); mMenuWidth = loadDimensionPixelSize(resources, R.dimen.desktop_mode_handle_menu_width); + mMenuHeight = getHandleMenuHeight(resources); mMarginMenuTop = loadDimensionPixelSize(resources, R.dimen.desktop_mode_handle_menu_margin_top); mMarginMenuStart = loadDimensionPixelSize(resources, R.dimen.desktop_mode_handle_menu_margin_start); - mMarginMenuSpacing = loadDimensionPixelSize(resources, - R.dimen.desktop_mode_handle_menu_pill_spacing_margin); - mAppInfoPillHeight = loadDimensionPixelSize(resources, - R.dimen.desktop_mode_handle_menu_app_info_pill_height); - mWindowingPillHeight = loadDimensionPixelSize(resources, - R.dimen.desktop_mode_handle_menu_windowing_pill_height); - mMoreActionsPillHeight = shouldShowCloseButton() - ? loadDimensionPixelSize(resources, - R.dimen.desktop_mode_handle_menu_more_actions_pill_freeform_height) - : loadDimensionPixelSize(resources, - R.dimen.desktop_mode_handle_menu_more_actions_pill_height); - mShadowRadius = loadDimensionPixelSize(resources, - R.dimen.desktop_mode_handle_menu_shadow_radius); - mCornerRadius = loadDimensionPixelSize(resources, - R.dimen.desktop_mode_handle_menu_corner_radius); + } + + /** + * Determines handle menu height based on if windowing pill should be shown. + */ + private int getHandleMenuHeight(Resources resources) { + int menuHeight = loadDimensionPixelSize(resources, + R.dimen.desktop_mode_handle_menu_height); + if (!mShouldShowWindowingPill) { + menuHeight -= loadDimensionPixelSize(resources, + R.dimen.desktop_mode_handle_menu_windowing_pill_height); + } + return menuHeight; } private int loadDimensionPixelSize(Resources resources, int resourceId) { @@ -367,19 +307,9 @@ class HandleMenu { return resources.getDimensionPixelSize(resourceId); } - private boolean shouldShowCloseButton() { - return mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM; - } - void close() { - mAppInfoPill.releaseView(); - mAppInfoPill = null; - if (mWindowingPill != null) { - mWindowingPill.releaseView(); - mWindowingPill = null; - } - mMoreActionsPill.releaseView(); - mMoreActionsPill = null; + mHandleMenuWindow.releaseView(); + mHandleMenuWindow = null; } static final class Builder { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java index 07fee4316c08..335a5886ba28 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java @@ -44,6 +44,7 @@ import android.window.WindowContainerTransaction; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.desktopmode.DesktopModeStatus; import java.util.function.Supplier; @@ -283,10 +284,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> // Task surface itself float shadowRadius = loadDimension(resources, params.mShadowRadiusId); - int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor(); - mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f; - mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f; - mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f; final Point taskPosition = mTaskInfo.positionInParent; if (isFullscreen) { // Setting the task crop to the width/height stops input events from being sent to @@ -302,13 +299,22 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> finishT.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight); } startT.setShadowRadius(mTaskSurface, shadowRadius) - .setColor(mTaskSurface, mTmpColor) .show(mTaskSurface); finishT.setPosition(mTaskSurface, taskPosition.x, taskPosition.y) .setShadowRadius(mTaskSurface, shadowRadius); if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) { + if (!DesktopModeStatus.isVeiledResizeEnabled()) { + // When fluid resize is enabled, add a background to freeform tasks + int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor(); + mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f; + mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f; + mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f; + startT.setColor(mTaskSurface, mTmpColor); + } startT.setCornerRadius(mTaskSurface, params.mCornerRadius); finishT.setCornerRadius(mTaskSurface, params.mCornerRadius); + } else if (!DesktopModeStatus.isVeiledResizeEnabled()) { + startT.unsetColor(mTaskSurface); } if (mCaptionWindowManager == null) { @@ -425,13 +431,10 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> * @param yPos y position of new window * @param width width of new window * @param height height of new window - * @param shadowRadius radius of the shadow of the new window - * @param cornerRadius radius of the corners of the new window * @return the {@link AdditionalWindow} that was added. */ AdditionalWindow addWindow(int layoutId, String namePrefix, SurfaceControl.Transaction t, - SurfaceSyncGroup ssg, int xPos, int yPos, int width, int height, int shadowRadius, - int cornerRadius) { + SurfaceSyncGroup ssg, int xPos, int yPos, int width, int height) { final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get(); SurfaceControl windowSurfaceControl = builder .setName(namePrefix + " of Task=" + mTaskInfo.taskId) @@ -442,8 +445,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> t.setPosition(windowSurfaceControl, xPos, yPos) .setWindowCrop(windowSurfaceControl, width, height) - .setShadowRadius(windowSurfaceControl, shadowRadius) - .setCornerRadius(windowSurfaceControl, cornerRadius) .show(windowSurfaceControl); final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height, diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt index 213d596a6131..943b16c33a98 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt @@ -23,7 +23,6 @@ import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.LegacyFlickerTest import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.common.flicker.subject.region.RegionTraceSubject import android.tools.device.helpers.WindowUtils import android.tools.device.traces.parsers.toFlickerComponent import androidx.test.filters.RequiresDevice @@ -87,8 +86,6 @@ class AutoEnterPipFromSplitScreenOnGoToHomeTest(flicker: LegacyFlickerTest) : pipApp.enableAutoEnterForPipActivity() } teardown { - // close gracefully so that onActivityUnpinned() can be called before force exit - pipApp.closePipWindow(wmHelper) pipApp.exit(wmHelper) secondAppForSplitScreen.exit(wmHelper) } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt index e38c4c34fc53..19c8435facaf 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt @@ -67,8 +67,6 @@ open class AutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) : override val defaultTeardown: FlickerBuilder.() -> Unit = { teardown { - // close gracefully so that onActivityUnpinned() can be called before force exit - pipApp.closePipWindow(wmHelper) pipApp.exit(wmHelper) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt index 6dd68b0d029d..820af9316aae 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt @@ -55,8 +55,6 @@ class EnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) : EnterPipTransiti override val defaultTeardown: FlickerBuilder.() -> Unit = { teardown { - // close gracefully so that onActivityUnpinned() can be called before force exit - pipApp.closePipWindow(wmHelper) pipApp.exit(wmHelper) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt new file mode 100644 index 000000000000..4f27ceddd705 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2023 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.wm.shell.flicker.pip + +import android.platform.test.annotations.Presubmit +import android.tools.common.Rotation +import android.tools.device.flicker.junit.FlickerParametersRunnerFactory +import android.tools.device.flicker.legacy.FlickerBuilder +import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import com.android.wm.shell.flicker.pip.common.PipTransition +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** Test changing aspect ratio of pip. */ +@RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class PipAspectRatioChangeTest(flicker: LegacyFlickerTest) : PipTransition(flicker) { + override val thisTransition: FlickerBuilder.() -> Unit = { + transitions { + pipApp.changeAspectRatio() + } + } + + @Presubmit + @Test + fun pipAspectRatioChangesProperly() { + flicker.assertLayersStart { this.visibleRegion(pipApp).isSameAspectRatio(16, 9) } + flicker.assertLayersEnd { this.visibleRegion(pipApp).isSameAspectRatio(1, 2) } + } + + companion object { + /** + * Creates the test configurations. + * + * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and + * navigation modes. + */ + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams() = + LegacyFlickerTestFactory.nonRotationTests( + supportedRotations = listOf(Rotation.ROTATION_0) + ) + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp index 54f94986d90c..d09a90cd7dc7 100644 --- a/libs/WindowManager/Shell/tests/unittest/Android.bp +++ b/libs/WindowManager/Shell/tests/unittest/Android.bp @@ -45,7 +45,7 @@ android_test { "kotlinx-coroutines-core", "mockito-kotlin2", "mockito-target-extended-minus-junit4", - "truth-prebuilt", + "truth", "testables", "platform-test-annotations", "servicestests-utils", diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java index 58d9a6486ff2..287a97c9b5b0 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java @@ -22,20 +22,24 @@ import static android.view.View.LAYOUT_DIRECTION_LTR; import static android.view.View.LAYOUT_DIRECTION_RTL; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import android.content.Intent; import android.content.res.Configuration; import android.graphics.Insets; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; +import android.os.UserHandle; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableResources; +import android.util.DisplayMetrics; import android.view.WindowInsets; import android.view.WindowManager; import android.view.WindowMetrics; @@ -257,6 +261,27 @@ public class BubblePositionerTest extends ShellTestCase { assertThat(mPositioner.hasUserModifiedDefaultPosition()).isTrue(); } + @Test + public void testExpandedViewHeight_onLargeTablet() { + Insets insets = Insets.of(10, 20, 5, 15); + Rect screenBounds = new Rect(0, 0, 1800, 2600); + + new WindowManagerConfig() + .setLargeScreen() + .setInsets(insets) + .setScreenBounds(screenBounds) + .setUpConfig(); + mPositioner.update(); + + Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName()); + Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor()); + + int manageButtonHeight = + mContext.getResources().getDimensionPixelSize(R.dimen.bubble_manage_button_height); + float expectedHeight = 1800 - 2 * 20 - manageButtonHeight; + assertThat(mPositioner.getExpandedViewHeight(bubble)).isWithin(0.1f).of(expectedHeight); + } + /** * Calculates the Y position bubbles should be placed based on the config. Based on * the calculations in {@link BubblePositioner#getDefaultStartPosition()} and @@ -323,6 +348,8 @@ public class BubblePositionerTest extends ShellTestCase { ? MIN_WIDTH_FOR_TABLET : MIN_WIDTH_FOR_TABLET - 1; mConfiguration.orientation = mOrientation; + mConfiguration.screenWidthDp = pxToDp(mScreenBounds.width()); + mConfiguration.screenHeightDp = pxToDp(mScreenBounds.height()); when(mConfiguration.getLayoutDirection()).thenReturn(mLayoutDirection); WindowInsets windowInsets = mock(WindowInsets.class); @@ -331,5 +358,11 @@ public class BubblePositionerTest extends ShellTestCase { when(mWindowMetrics.getBounds()).thenReturn(mScreenBounds); when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics); } + + private int pxToDp(float px) { + int dpi = mContext.getResources().getDisplayMetrics().densityDpi; + float dp = px / ((float) dpi / DisplayMetrics.DENSITY_DEFAULT); + return (int) dp; + } } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitScreenConstantsTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitScreenConstantsTest.kt new file mode 100644 index 000000000000..fe261107d65b --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitScreenConstantsTest.kt @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2023 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.wm.shell.common.split + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class SplitScreenConstantsTest { + + /** + * Ensures that some important constants are not changed from their set values. These values + * are persisted in user-defined app pairs, and changing them will break things. + */ + @Test + fun shouldKeepExistingConstantValues() { + assertEquals( + "the value of SPLIT_POSITION_TOP_OR_LEFT should be 0", + 0, + SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT, + ) + assertEquals( + "the value of SPLIT_POSITION_BOTTOM_OR_RIGHT should be 1", + 1, + SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT, + ) + assertEquals( + "the value of SNAP_TO_30_70 should be 0", + 0, + SplitScreenConstants.SNAP_TO_30_70, + ) + assertEquals( + "the value of SNAP_TO_50_50 should be 1", + 1, + SplitScreenConstants.SNAP_TO_50_50, + ) + assertEquals( + "the value of SNAP_TO_70_30 should be 2", + 2, + SplitScreenConstants.SNAP_TO_70_30, + ) + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index dea161786da2..ebcb6407a6fd 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -54,6 +54,8 @@ import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreef import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createHomeTask import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createSplitScreenTask +import com.android.wm.shell.recents.RecentsTransitionHandler +import com.android.wm.shell.recents.RecentsTransitionStateListener import com.android.wm.shell.splitscreen.SplitScreenController import com.android.wm.shell.sysui.ShellCommandHandler import com.android.wm.shell.sysui.ShellController @@ -101,11 +103,13 @@ class DesktopTasksControllerTest : ShellTestCase() { @Mock lateinit var launchAdjacentController: LaunchAdjacentController @Mock lateinit var desktopModeWindowDecoration: DesktopModeWindowDecoration @Mock lateinit var splitScreenController: SplitScreenController + @Mock lateinit var recentsTransitionHandler: RecentsTransitionHandler private lateinit var mockitoSession: StaticMockitoSession private lateinit var controller: DesktopTasksController private lateinit var shellInit: ShellInit private lateinit var desktopModeTaskRepository: DesktopModeTaskRepository + private lateinit var recentsTransitionStateListener: RecentsTransitionStateListener private val shellExecutor = TestShellExecutor() // Mock running tasks are registered here so we can get the list from mock shell task organizer @@ -126,6 +130,10 @@ class DesktopTasksControllerTest : ShellTestCase() { controller.splitScreenController = splitScreenController shellInit.init() + + val captor = ArgumentCaptor.forClass(RecentsTransitionStateListener::class.java) + verify(recentsTransitionHandler).addTransitionStateListener(captor.capture()) + recentsTransitionStateListener = captor.value } private fun createController(): DesktopTasksController { @@ -144,6 +152,7 @@ class DesktopTasksControllerTest : ShellTestCase() { mToggleResizeDesktopTaskTransitionHandler, desktopModeTaskRepository, launchAdjacentController, + recentsTransitionHandler, shellExecutor ) } @@ -355,7 +364,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test fun moveToDesktop_splitTaskExitsSplit() { - var task = setUpSplitScreenTask() + val task = setUpSplitScreenTask() controller.moveToDesktop(desktopModeWindowDecoration, task) val wct = getLatestMoveToDesktopWct() assertThat(wct.changes[task.token.asBinder()]?.windowingMode) @@ -367,7 +376,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test fun moveToDesktop_fullscreenTaskDoesNotExitSplit() { - var task = setUpFullscreenTask() + val task = setUpFullscreenTask() controller.moveToDesktop(desktopModeWindowDecoration, task) val wct = getLatestMoveToDesktopWct() assertThat(wct.changes[task.token.asBinder()]?.windowingMode) @@ -666,6 +675,20 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test + fun handleRequest_recentsAnimationRunning_returnNull() { + // Set up a visible freeform task so a fullscreen task should be converted to freeform + val freeformTask = setUpFreeformTask() + markTaskVisible(freeformTask) + + // Mark recents animation running + recentsTransitionStateListener.onAnimationStateChanged(true) + + // Open a fullscreen task, check that it does not result in a WCT with changes to it + val fullscreenTask = createFullscreenTask() + assertThat(controller.handleRequest(Binder(), createTransition(fullscreenTask))).isNull() + } + + @Test fun stashDesktopApps_stateUpdates() { whenever(DesktopModeStatus.isStashingEnabled()).thenReturn(true) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt index 00d70a75837b..8eaf5a004c0a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt @@ -49,6 +49,7 @@ import com.android.wm.shell.desktopmode.DesktopTasksController import com.android.wm.shell.recents.RecentsTransitionHandler import com.android.wm.shell.recents.RecentsTransitionStateListener import com.android.wm.shell.sysui.KeyguardChangeListener +import com.android.wm.shell.sysui.ShellCommandHandler import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.Transitions @@ -89,6 +90,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { @Mock private lateinit var mockShellExecutor: ShellExecutor @Mock private lateinit var mockRootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer @Mock private lateinit var mockRecentsTransitionHandler: RecentsTransitionHandler + @Mock private lateinit var mockShellCommandHandler: ShellCommandHandler private val transactionFactory = Supplier<SurfaceControl.Transaction> { SurfaceControl.Transaction() @@ -105,6 +107,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { mockMainHandler, mockMainChoreographer, shellInit, + mockShellCommandHandler, mockTaskOrganizer, mockDisplayController, mockShellController, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java index 76bc25aa66ef..fcb7863429d6 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java @@ -17,7 +17,9 @@ package com.android.wm.shell.windowdecor; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlBuilder; import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlTransaction; @@ -36,6 +38,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.same; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.mockito.quality.Strictness.LENIENT; import android.app.ActivityManager; import android.content.Context; @@ -59,10 +62,12 @@ import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; +import com.android.dx.mockito.inline.extended.StaticMockitoSession; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.TestRunningTaskInfoBuilder; import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.desktopmode.DesktopModeStatus; import com.android.wm.shell.tests.R; import org.junit.Before; @@ -119,8 +124,6 @@ public class WindowDecorationTests extends ShellTestCase { private WindowDecoration.RelayoutParams mRelayoutParams = new WindowDecoration.RelayoutParams(); private Configuration mWindowConfiguration = new Configuration(); private int mCaptionMenuWidthId; - private int mCaptionMenuShadowRadiusId; - private int mCaptionMenuCornerRadiusId; @Before public void setUp() { @@ -131,8 +134,6 @@ public class WindowDecorationTests extends ShellTestCase { mRelayoutParams.mLayoutResId = 0; mRelayoutParams.mCaptionHeightId = R.dimen.test_freeform_decor_caption_height; mCaptionMenuWidthId = R.dimen.test_freeform_decor_caption_menu_width; - mCaptionMenuShadowRadiusId = R.dimen.test_caption_menu_shadow_radius; - mCaptionMenuCornerRadiusId = R.dimen.test_caption_menu_corner_radius; mRelayoutParams.mShadowRadiusId = R.dimen.test_window_decor_shadow_radius; mRelayoutParams.mCornerRadius = CORNER_RADIUS; @@ -205,12 +206,8 @@ public class WindowDecorationTests extends ShellTestCase { createMockSurfaceControlBuilder(captionContainerSurface); mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder); - final ActivityManager.TaskDescription.Builder taskDescriptionBuilder = - new ActivityManager.TaskDescription.Builder() - .setBackgroundColor(Color.YELLOW); final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder() .setDisplayId(Display.DEFAULT_DISPLAY) - .setTaskDescriptionBuilder(taskDescriptionBuilder) .setBounds(TASK_BOUNDS) .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y) .setVisible(true) @@ -259,8 +256,6 @@ public class WindowDecorationTests extends ShellTestCase { verify(mMockSurfaceControlFinishT).setCornerRadius(taskSurface, CORNER_RADIUS); verify(mMockSurfaceControlStartT) .show(taskSurface); - verify(mMockSurfaceControlStartT) - .setColor(taskSurface, new float[] {1.f, 1.f, 0.f}); verify(mMockSurfaceControlStartT).setShadowRadius(taskSurface, 10); assertEquals(300, mRelayoutResult.mWidth); @@ -417,16 +412,6 @@ public class WindowDecorationTests extends ShellTestCase { final int height = WindowDecoration.loadDimensionPixelSize( windowDecor.mDecorWindowContext.getResources(), mRelayoutParams.mCaptionHeightId); verify(mMockSurfaceControlAddWindowT).setWindowCrop(additionalWindowSurface, width, height); - final int shadowRadius = WindowDecoration.loadDimensionPixelSize( - windowDecor.mDecorWindowContext.getResources(), - mCaptionMenuShadowRadiusId); - verify(mMockSurfaceControlAddWindowT) - .setShadowRadius(additionalWindowSurface, shadowRadius); - final int cornerRadius = WindowDecoration.loadDimensionPixelSize( - windowDecor.mDecorWindowContext.getResources(), - mCaptionMenuCornerRadiusId); - verify(mMockSurfaceControlAddWindowT) - .setCornerRadius(additionalWindowSurface, cornerRadius); verify(mMockSurfaceControlAddWindowT).show(additionalWindowSurface); verify(mMockSurfaceControlViewHostFactory, Mockito.times(2)) .create(any(), eq(defaultDisplay), any()); @@ -516,6 +501,86 @@ public class WindowDecorationTests extends ShellTestCase { verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockSurfaceControlStartT); } + @Test + public void testRelayout_fluidResizeEnabled_freeformTask_setTaskSurfaceColor() { + StaticMockitoSession mockitoSession = mockitoSession().mockStatic( + DesktopModeStatus.class).strictness( + LENIENT).startMocking(); + when(DesktopModeStatus.isVeiledResizeEnabled()).thenReturn(false); + + final Display defaultDisplay = mock(Display.class); + doReturn(defaultDisplay).when(mMockDisplayController) + .getDisplay(Display.DEFAULT_DISPLAY); + + final SurfaceControl decorContainerSurface = mock(SurfaceControl.class); + final SurfaceControl.Builder decorContainerSurfaceBuilder = + createMockSurfaceControlBuilder(decorContainerSurface); + mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder); + final SurfaceControl captionContainerSurface = mock(SurfaceControl.class); + final SurfaceControl.Builder captionContainerSurfaceBuilder = + createMockSurfaceControlBuilder(captionContainerSurface); + mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder); + + final ActivityManager.TaskDescription.Builder taskDescriptionBuilder = + new ActivityManager.TaskDescription.Builder() + .setBackgroundColor(Color.YELLOW); + + final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder() + .setDisplayId(Display.DEFAULT_DISPLAY) + .setTaskDescriptionBuilder(taskDescriptionBuilder) + .setVisible(true) + .setWindowingMode(WINDOWING_MODE_FREEFORM) + .build(); + taskInfo.isFocused = true; + final SurfaceControl taskSurface = mock(SurfaceControl.class); + final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); + + windowDecor.relayout(taskInfo); + + verify(mMockSurfaceControlStartT).setColor(taskSurface, new float[] {1.f, 1.f, 0.f}); + + mockitoSession.finishMocking(); + } + + @Test + public void testRelayout_fluidResizeEnabled_fullscreenTask_clearTaskSurfaceColor() { + StaticMockitoSession mockitoSession = mockitoSession().mockStatic( + DesktopModeStatus.class).strictness(LENIENT).startMocking(); + when(DesktopModeStatus.isVeiledResizeEnabled()).thenReturn(false); + + final Display defaultDisplay = mock(Display.class); + doReturn(defaultDisplay).when(mMockDisplayController) + .getDisplay(Display.DEFAULT_DISPLAY); + + final SurfaceControl decorContainerSurface = mock(SurfaceControl.class); + final SurfaceControl.Builder decorContainerSurfaceBuilder = + createMockSurfaceControlBuilder(decorContainerSurface); + mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder); + final SurfaceControl captionContainerSurface = mock(SurfaceControl.class); + final SurfaceControl.Builder captionContainerSurfaceBuilder = + createMockSurfaceControlBuilder(captionContainerSurface); + mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder); + + final ActivityManager.TaskDescription.Builder taskDescriptionBuilder = + new ActivityManager.TaskDescription.Builder() + .setBackgroundColor(Color.YELLOW); + final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder() + .setDisplayId(Display.DEFAULT_DISPLAY) + .setTaskDescriptionBuilder(taskDescriptionBuilder) + .setVisible(true) + .setWindowingMode(WINDOWING_MODE_FULLSCREEN) + .build(); + taskInfo.isFocused = true; + final SurfaceControl taskSurface = mock(SurfaceControl.class); + final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); + + windowDecor.relayout(taskInfo); + + verify(mMockSurfaceControlStartT).unsetColor(taskSurface); + + mockitoSession.finishMocking(); + } + private TestWindowDecoration createWindowDecoration( ActivityManager.RunningTaskInfo taskInfo, SurfaceControl testSurface) { return new TestWindowDecoration(mContext, mMockDisplayController, mMockShellTaskOrganizer, @@ -588,13 +653,11 @@ public class WindowDecorationTests extends ShellTestCase { int y = mRelayoutParams.mCaptionY; int width = loadDimensionPixelSize(resources, mCaptionMenuWidthId); int height = loadDimensionPixelSize(resources, mRelayoutParams.mCaptionHeightId); - int shadowRadius = loadDimensionPixelSize(resources, mCaptionMenuShadowRadiusId); - int cornerRadius = loadDimensionPixelSize(resources, mCaptionMenuCornerRadiusId); String name = "Test Window"; WindowDecoration.AdditionalWindow additionalWindow = - addWindow(R.layout.desktop_mode_window_decor_handle_menu_app_info_pill, name, + addWindow(R.layout.desktop_mode_window_decor_handle_menu, name, mMockSurfaceControlAddWindowT, mMockSurfaceSyncGroup, x, y, - width, height, shadowRadius, cornerRadius); + width, height); return additionalWindow; } } diff --git a/libs/dream/lowlight/tests/Android.bp b/libs/dream/lowlight/tests/Android.bp index 64b53cbb5c5a..4dafd0aa6df4 100644 --- a/libs/dream/lowlight/tests/Android.bp +++ b/libs/dream/lowlight/tests/Android.bp @@ -34,7 +34,7 @@ android_test { "mockito-target-extended-minus-junit4", "platform-test-annotations", "testables", - "truth-prebuilt", + "truth", ], libs: [ "android.test.mock", diff --git a/libs/hwui/OWNERS b/libs/hwui/OWNERS index 6ca991d8b294..bc174599a4d3 100644 --- a/libs/hwui/OWNERS +++ b/libs/hwui/OWNERS @@ -4,9 +4,8 @@ alecmouri@google.com djsollen@google.com jreck@google.com njawad@google.com -reed@google.com scroggo@google.com -stani@google.com +sumir@google.com # For text, e.g. Typeface, Font, Minikin, etc. nona@google.com diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp index 2c13ceb77b52..a952be020855 100644 --- a/libs/hwui/jni/Shader.cpp +++ b/libs/hwui/jni/Shader.cpp @@ -65,21 +65,41 @@ static jlong Shader_getNativeFinalizer(JNIEnv*, jobject) { return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref)); } -static jlong createBitmapShaderHelper(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle, - jint tileModeX, jint tileModeY, bool isDirectSampled, - const SkSamplingOptions& sampling) { +/////////////////////////////////////////////////////////////////////////////////////////////// + +static SkGainmapInfo sNoOpGainmap = { + .fGainmapRatioMin = {1.f, 1.f, 1.f, 1.0}, + .fGainmapRatioMax = {1.f, 1.f, 1.f, 1.0}, + .fGainmapGamma = {1.f, 1.f, 1.f, 1.f}, + .fEpsilonSdr = {0.f, 0.f, 0.f, 1.0}, + .fEpsilonHdr = {0.f, 0.f, 0.f, 1.0}, + .fDisplayRatioSdr = 1.f, + .fDisplayRatioHdr = 1.f, +}; + +static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle, + jint tileModeX, jint tileModeY, jint maxAniso, bool filter, + bool isDirectSampled, jlong overrideGainmapPtr) { + SkSamplingOptions sampling = maxAniso > 0 ? SkSamplingOptions::Aniso(static_cast<int>(maxAniso)) + : SkSamplingOptions(filter ? SkFilterMode::kLinear + : SkFilterMode::kNearest, + SkMipmapMode::kNone); const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); + const Gainmap* gainmap = reinterpret_cast<Gainmap*>(overrideGainmapPtr); sk_sp<SkImage> image; if (bitmapHandle) { // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise, // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility. auto& bitmap = android::bitmap::toBitmap(bitmapHandle); image = bitmap.makeImage(); + if (!gainmap && bitmap.hasGainmap()) { + gainmap = bitmap.gainmap().get(); + } - if (!isDirectSampled && bitmap.hasGainmap()) { - sk_sp<SkShader> gainmapShader = MakeGainmapShader( - image, bitmap.gainmap()->bitmap->makeImage(), bitmap.gainmap()->info, - (SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling); + if (!isDirectSampled && gainmap && gainmap->info != sNoOpGainmap) { + sk_sp<SkShader> gainmapShader = + MakeGainmapShader(image, gainmap->bitmap->makeImage(), gainmap->info, + (SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling); if (gainmapShader) { if (matrix) { gainmapShader = gainmapShader->makeWithLocalMatrix(*matrix); @@ -111,26 +131,6 @@ static jlong createBitmapShaderHelper(JNIEnv* env, jobject o, jlong matrixPtr, j /////////////////////////////////////////////////////////////////////////////////////////////// -static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle, - jint tileModeX, jint tileModeY, bool filter, - bool isDirectSampled) { - SkSamplingOptions sampling(filter ? SkFilterMode::kLinear : SkFilterMode::kNearest, - SkMipmapMode::kNone); - return createBitmapShaderHelper(env, o, matrixPtr, bitmapHandle, tileModeX, tileModeY, - isDirectSampled, sampling); -} - -static jlong BitmapShader_constructorWithMaxAniso(JNIEnv* env, jobject o, jlong matrixPtr, - jlong bitmapHandle, jint tileModeX, - jint tileModeY, jint maxAniso, - bool isDirectSampled) { - auto sampling = SkSamplingOptions::Aniso(static_cast<int>(maxAniso)); - return createBitmapShaderHelper(env, o, matrixPtr, bitmapHandle, tileModeX, tileModeY, - isDirectSampled, sampling); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// - static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) { const size_t count = env->GetArrayLength(colorArray); const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr); @@ -419,8 +419,7 @@ static const JNINativeMethod gShaderMethods[] = { }; static const JNINativeMethod gBitmapShaderMethods[] = { - {"nativeCreate", "(JJIIZZ)J", (void*)BitmapShader_constructor}, - {"nativeCreateWithMaxAniso", "(JJIIIZ)J", (void*)BitmapShader_constructorWithMaxAniso}, + {"nativeCreate", "(JJIIIZZJ)J", (void*)BitmapShader_constructor}, }; diff --git a/libs/securebox/tests/Android.bp b/libs/securebox/tests/Android.bp index 7df546ae0ff6..80b501da1aa5 100644 --- a/libs/securebox/tests/Android.bp +++ b/libs/securebox/tests/Android.bp @@ -32,7 +32,7 @@ android_test { "platform-test-annotations", "testables", "testng", - "truth-prebuilt", + "truth", ], libs: [ "android.test.mock", |