diff options
Diffstat (limited to 'libs')
140 files changed, 4228 insertions, 2444 deletions
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewListenerTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewListenerTest.kt new file mode 100644 index 000000000000..9ebc3d78b3a7 --- /dev/null +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewListenerTest.kt @@ -0,0 +1,491 @@ +/* + * Copyright (C) 2025 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.bubbles + +import android.app.Notification +import android.app.PendingIntent +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.pm.ShortcutInfo +import android.graphics.drawable.Icon +import android.os.UserHandle +import android.service.notification.NotificationListenerService.Ranking +import android.service.notification.StatusBarNotification +import android.view.View +import android.widget.FrameLayout +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation +import com.android.internal.protolog.ProtoLog +import com.android.wm.shell.R +import com.android.wm.shell.bubbles.Bubbles.BubbleMetadataFlagListener +import com.android.wm.shell.common.TestShellExecutor +import com.android.wm.shell.taskview.TaskView +import com.android.wm.shell.taskview.TaskViewController +import com.android.wm.shell.taskview.TaskViewTaskController +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito +import org.mockito.Mockito.never +import org.mockito.Mockito.reset +import org.mockito.kotlin.any +import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +/** + * Tests for [BubbleTaskViewListener]. + */ +@SmallTest +@RunWith(AndroidJUnit4::class) +class BubbleTaskViewListenerTest { + + private val context = ApplicationProvider.getApplicationContext<Context>() + + private var taskViewController = mock<TaskViewController>() + private var listenerCallback = mock<BubbleTaskViewListener.Callback>() + private var expandedViewManager = mock<BubbleExpandedViewManager>() + + private lateinit var bubbleTaskViewListener: BubbleTaskViewListener + private lateinit var taskView: TaskView + private lateinit var bubbleTaskView: BubbleTaskView + private lateinit var parentView: ViewPoster + private lateinit var mainExecutor: TestShellExecutor + private lateinit var bgExecutor: TestShellExecutor + + @Before + fun setUp() { + ProtoLog.REQUIRE_PROTOLOGTOOL = false + ProtoLog.init() + + parentView = ViewPoster(context) + mainExecutor = TestShellExecutor() + bgExecutor = TestShellExecutor() + + taskView = TaskView(context, taskViewController, mock<TaskViewTaskController>()) + bubbleTaskView = BubbleTaskView(taskView, mainExecutor) + + bubbleTaskViewListener = + BubbleTaskViewListener( + context, + bubbleTaskView, + parentView, + expandedViewManager, + listenerCallback + ) + } + + @Test + fun createBubbleTaskViewListener_withCreatedTaskView() { + // Make the bubbleTaskView look like it's been created + val taskId = 123 + bubbleTaskView.listener.onTaskCreated(taskId, mock<ComponentName>()) + reset(listenerCallback) + + bubbleTaskViewListener = + BubbleTaskViewListener( + context, + bubbleTaskView, + parentView, + expandedViewManager, + listenerCallback + ) + + assertThat(bubbleTaskView.delegateListener).isEqualTo(bubbleTaskViewListener) + assertThat(bubbleTaskViewListener.taskView).isEqualTo(bubbleTaskView.taskView) + + verify(listenerCallback).onTaskCreated() + assertThat(bubbleTaskViewListener.taskId).isEqualTo(taskId) + } + + @Test + fun createBubbleTaskViewListener() { + bubbleTaskViewListener = + BubbleTaskViewListener( + context, + bubbleTaskView, + parentView, + expandedViewManager, + listenerCallback + ) + + assertThat(bubbleTaskView.delegateListener).isEqualTo(bubbleTaskViewListener) + assertThat(bubbleTaskViewListener.taskView).isEqualTo(bubbleTaskView.taskView) + verify(listenerCallback, never()).onTaskCreated() + } + + @Test + fun onInitialized_pendingIntentChatBubble() { + val target = Intent(context, TestActivity::class.java) + val pendingIntent = PendingIntent.getActivity(context, 0, target, + PendingIntent.FLAG_MUTABLE) + + val b = createChatBubble("key", pendingIntent) + bubbleTaskViewListener.setBubble(b) + + assertThat(b.isChat).isTrue() + // Has shortcut info + assertThat(b.shortcutInfo).isNotNull() + // But it didn't use that on bubble metadata + assertThat(b.metadataShortcutId).isNull() + + getInstrumentation().runOnMainSync { + bubbleTaskViewListener.onInitialized() + } + getInstrumentation().waitForIdleSync() + + // ..so it's pending intent-based, and launches that + assertThat(b.isPendingIntentActive).isTrue() + verify(taskViewController).startActivity(any(), eq(pendingIntent), any(), any(), any()) + } + + @Test + fun onInitialized_shortcutChatBubble() { + val shortcutInfo = ShortcutInfo.Builder(context) + .setId("mockShortcutId") + .build() + val b = createChatBubble("key", shortcutInfo) + bubbleTaskViewListener.setBubble(b) + + assertThat(b.isChat).isTrue() + assertThat(b.shortcutInfo).isNotNull() + // Chat bubble using a shortcut + assertThat(b.metadataShortcutId).isNotNull() + + getInstrumentation().runOnMainSync { + bubbleTaskViewListener.onInitialized() + } + getInstrumentation().waitForIdleSync() + + assertThat(b.isPendingIntentActive).isFalse() + verify(taskViewController).startShortcutActivity(any(), eq(shortcutInfo), any(), any()) + } + + @Test + fun onInitialized_appBubble() { + val b = createAppBubble() + bubbleTaskViewListener.setBubble(b) + + assertThat(b.isApp).isTrue() + + getInstrumentation().runOnMainSync { + bubbleTaskViewListener.onInitialized() + } + getInstrumentation().waitForIdleSync() + + assertThat(b.isPendingIntentActive).isFalse() + verify(taskViewController).startActivity(any(), any(), anyOrNull(), any(), any()) + } + + @Test + fun onInitialized_preparingTransition() { + val b = createAppBubble() + bubbleTaskViewListener.setBubble(b) + taskView = Mockito.spy(taskView) + val preparingTransition = mock<BubbleTransitions.BubbleTransition>() + b.preparingTransition = preparingTransition + + getInstrumentation().runOnMainSync { + bubbleTaskViewListener.onInitialized() + } + getInstrumentation().waitForIdleSync() + + verify(preparingTransition).surfaceCreated() + } + + @Test + fun onInitialized_destroyed() { + val b = createAppBubble() + bubbleTaskViewListener.setBubble(b) + + assertThat(b.isApp).isTrue() + + getInstrumentation().runOnMainSync { + bubbleTaskViewListener.onReleased() + bubbleTaskViewListener.onInitialized() + } + getInstrumentation().waitForIdleSync() + + verify(taskViewController, never()).startActivity(any(), any(), anyOrNull(), any(), any()) + } + + @Test + fun onInitialized_initialized() { + val b = createAppBubble() + bubbleTaskViewListener.setBubble(b) + + assertThat(b.isApp).isTrue() + + getInstrumentation().runOnMainSync { + bubbleTaskViewListener.onInitialized() + } + getInstrumentation().waitForIdleSync() + + reset(taskViewController) + + getInstrumentation().runOnMainSync { + bubbleTaskViewListener.onInitialized() + } + // Already initialized, so no activity should be started. + verify(taskViewController, never()).startActivity(any(), any(), anyOrNull(), any(), any()) + } + + @Test + fun onTaskCreated() { + val b = createAppBubble() + bubbleTaskViewListener.setBubble(b) + + getInstrumentation().runOnMainSync { + bubbleTaskViewListener.onInitialized() + } + getInstrumentation().waitForIdleSync() + verify(taskViewController).startActivity(any(), any(), anyOrNull(), any(), any()) + + val taskId = 123 + getInstrumentation().runOnMainSync { + bubbleTaskViewListener.onTaskCreated(taskId, mock<ComponentName>()) + } + getInstrumentation().waitForIdleSync() + + verify(listenerCallback).onTaskCreated() + verify(expandedViewManager, never()).setNoteBubbleTaskId(any(), any()) + assertThat(bubbleTaskViewListener.taskId).isEqualTo(taskId) + } + + @Test + fun onTaskCreated_noteBubble() { + val b = createNoteBubble() + bubbleTaskViewListener.setBubble(b) + assertThat(b.isNote).isTrue() + + getInstrumentation().runOnMainSync { + bubbleTaskViewListener.onInitialized() + } + getInstrumentation().waitForIdleSync() + verify(taskViewController).startActivity(any(), any(), anyOrNull(), any(), any()) + + val taskId = 123 + getInstrumentation().runOnMainSync { + bubbleTaskViewListener.onTaskCreated(taskId, mock<ComponentName>()) + } + getInstrumentation().waitForIdleSync() + + verify(listenerCallback).onTaskCreated() + verify(expandedViewManager).setNoteBubbleTaskId(eq(b.key), eq(taskId)) + assertThat(bubbleTaskViewListener.taskId).isEqualTo(taskId) + } + + @Test + fun onTaskVisibilityChanged_true() { + getInstrumentation().runOnMainSync { + bubbleTaskViewListener.onTaskVisibilityChanged(1, true) + } + verify(listenerCallback).onContentVisibilityChanged(eq(true)) + } + + @Test + fun onTaskVisibilityChanged_false() { + getInstrumentation().runOnMainSync { + bubbleTaskViewListener.onTaskVisibilityChanged(1, false) + } + verify(listenerCallback).onContentVisibilityChanged(eq(false)) + } + + @Test + fun onTaskRemovalStarted() { + val mockTaskView = mock<TaskView>() + bubbleTaskView = BubbleTaskView(mockTaskView, mainExecutor) + + bubbleTaskViewListener = + BubbleTaskViewListener( + context, + bubbleTaskView, + parentView, + expandedViewManager, + listenerCallback + ) + + val b = createAppBubble() + bubbleTaskViewListener.setBubble(b) + + getInstrumentation().runOnMainSync { + bubbleTaskViewListener.onInitialized() + } + getInstrumentation().waitForIdleSync() + verify(mockTaskView).startActivity(any(), anyOrNull(), any(), any()) + + getInstrumentation().runOnMainSync { + bubbleTaskViewListener.onTaskRemovalStarted(1) + } + + verify(expandedViewManager).removeBubble(eq(b.key), eq(Bubbles.DISMISS_TASK_FINISHED)) + verify(mockTaskView).release() + assertThat(parentView.lastRemovedView).isEqualTo(mockTaskView) + assertThat(bubbleTaskViewListener.taskView).isNull() + verify(listenerCallback).onTaskRemovalStarted() + } + + @Test + fun onBackPressedOnTaskRoot_expanded() { + val taskId = 123 + whenever(expandedViewManager.isStackExpanded()).doReturn(true) + + getInstrumentation().runOnMainSync { + bubbleTaskViewListener.onTaskCreated(taskId, mock<ComponentName>()) + bubbleTaskViewListener.onBackPressedOnTaskRoot(taskId) + } + verify(listenerCallback).onBackPressed() + } + + @Test + fun onBackPressedOnTaskRoot_notExpanded() { + val taskId = 123 + whenever(expandedViewManager.isStackExpanded()).doReturn(false) + + getInstrumentation().runOnMainSync { + bubbleTaskViewListener.onTaskCreated(taskId, mock<ComponentName>()) + bubbleTaskViewListener.onBackPressedOnTaskRoot(taskId) + } + verify(listenerCallback, never()).onBackPressed() + } + + @Test + fun onBackPressedOnTaskRoot_taskIdMissMatch() { + val taskId = 123 + whenever(expandedViewManager.isStackExpanded()).doReturn(true) + + getInstrumentation().runOnMainSync { + bubbleTaskViewListener.onTaskCreated(taskId, mock<ComponentName>()) + bubbleTaskViewListener.onBackPressedOnTaskRoot(42) + } + verify(listenerCallback, never()).onBackPressed() + } + + @Test + fun setBubble_isNew() { + val b = createAppBubble() + val isNew = bubbleTaskViewListener.setBubble(b) + assertThat(isNew).isTrue() + } + + @Test + fun setBubble_launchContentChanged() { + val target = Intent(context, TestActivity::class.java) + val pendingIntent = PendingIntent.getActivity( + context, 0, target, + PendingIntent.FLAG_MUTABLE + ) + + val b = createChatBubble("key", pendingIntent) + var isNew = bubbleTaskViewListener.setBubble(b) + // First time bubble is set, so it is "new" + assertThat(isNew).isTrue() + + val b2 = createChatBubble("key", pendingIntent) + isNew = bubbleTaskViewListener.setBubble(b2) + // Second time bubble is set & it uses same type of launch content, not "new" + assertThat(isNew).isFalse() + + val shortcutInfo = ShortcutInfo.Builder(context) + .setId("mockShortcutId") + .build() + val b3 = createChatBubble("key", shortcutInfo) + // bubble is using different content, so it is "new" + isNew = bubbleTaskViewListener.setBubble(b3) + assertThat(isNew).isTrue() + } + + private fun createAppBubble(): Bubble { + val target = Intent(context, TestActivity::class.java) + target.setPackage(context.packageName) + return Bubble.createAppBubble(target, mock<UserHandle>(), mock<Icon>(), + mainExecutor, bgExecutor) + } + + private fun createNoteBubble(): Bubble { + val target = Intent(context, TestActivity::class.java) + target.setPackage(context.packageName) + return Bubble.createNotesBubble(target, mock<UserHandle>(), mock<Icon>(), + mainExecutor, bgExecutor) + } + + private fun createChatBubble(key: String, shortcutInfo: ShortcutInfo): Bubble { + return Bubble( + key, + shortcutInfo, + 0 /* desiredHeight */, + 0 /* desiredHeightResId */, + "title", + -1 /*taskId */, + null /* locusId */, true /* isdismissabel */, + mainExecutor, bgExecutor, mock<BubbleMetadataFlagListener>() + ) + } + + private fun createChatBubble(key: String, pendingIntent: PendingIntent): Bubble { + val metadata = Notification.BubbleMetadata.Builder( + pendingIntent, + Icon.createWithResource(context, R.drawable.bubble_ic_create_bubble) + ).build() + val shortcutInfo = ShortcutInfo.Builder(context) + .setId("shortcutId") + .build() + val notification: Notification = + Notification.Builder(context, key) + .setSmallIcon(mock<Icon>()) + .setWhen(System.currentTimeMillis()) + .setContentTitle("title") + .setContentText("content") + .setBubbleMetadata(metadata) + .build() + val sbn = mock<StatusBarNotification>() + val ranking = mock<Ranking>() + whenever(sbn.getNotification()).thenReturn(notification) + whenever(sbn.getKey()).thenReturn(key) + whenever(ranking.getConversationShortcutInfo()).thenReturn(shortcutInfo) + val entry = BubbleEntry(sbn, ranking, true, false, false, false) + return Bubble( + entry, mock<BubbleMetadataFlagListener>(), null, mainExecutor, + bgExecutor + ) + } + + /** + * FrameLayout that immediately runs any runnables posted to it and tracks view removals. + */ + class ViewPoster(context: Context) : FrameLayout(context) { + + lateinit var lastRemovedView: View + + override fun post(r: Runnable): Boolean { + r.run() + return true + } + + override fun removeView(v: View) { + super.removeView(v) + lastRemovedView = v + } + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml b/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml index ce242751c172..05c1e094d7ae 100644 --- a/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml +++ b/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml @@ -13,20 +13,10 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<vector - xmlns:android="http://schemas.android.com/apk/res/android" - android:width="128dp" - android:height="4dp" - android:viewportWidth="128" - android:viewportHeight="4" - > - <group> - <clip-path - android:pathData="M2 0H126C127.105 0 128 0.895431 128 2C128 3.10457 127.105 4 126 4H2C0.895431 4 0 3.10457 0 2C0 0.895431 0.895431 0 2 0Z" - /> - <path - android:pathData="M0 0V4H128V0" - android:fillColor="@android:color/black" - /> - </group> -</vector> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="@android:color/black"/> + <corners android:radius="2dp"/> + <size android:height="4dp"/> +</shape> diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_app_handle.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_app_handle.xml index 1d1cdfa85040..9451fd43b1d8 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_app_handle.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_app_handle.xml @@ -20,7 +20,7 @@ android:id="@+id/desktop_mode_caption" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:gravity="center_horizontal"> + android:gravity="center"> <com.android.wm.shell.windowdecor.HandleImageButton android:id="@+id/caption_handle" 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 index 50c08732543a..477d207a5c7e 100644 --- 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 @@ -41,7 +41,7 @@ android:id="@+id/application_icon" android:layout_width="@dimen/desktop_mode_caption_icon_radius" android:layout_height="@dimen/desktop_mode_caption_icon_radius" - android:layout_marginStart="12dp" + android:layout_marginStart="10dp" android:layout_marginEnd="12dp" android:contentDescription="@string/app_icon_text" android:importantForAccessibility="no"/> @@ -53,10 +53,9 @@ <com.android.wm.shell.windowdecor.HandleMenuImageButton android:id="@+id/collapse_menu_button" - android:layout_width="32dp" - android:layout_height="32dp" - android:padding="4dp" - android:layout_marginEnd="14dp" + android:layout_width="16dp" + android:layout_height="16dp" + android:layout_marginEnd="16dp" android:layout_marginStart="14dp" android:contentDescription="@string/collapse_menu_text" android:src="@drawable/ic_baseline_expand_more_24" @@ -78,40 +77,55 @@ <ImageButton android:id="@+id/fullscreen_button" - android:layout_marginEnd="4dp" + android:paddingStart="16dp" + android:paddingEnd="12dp" android:contentDescription="@string/fullscreen_text" android:src="@drawable/desktop_mode_ic_handle_menu_fullscreen" android:tint="@androidprv:color/materialColorOnSurface" - android:layout_weight="1" style="@style/DesktopModeHandleMenuWindowingButton"/> + <Space + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_weight="1"/> + <ImageButton android:id="@+id/split_screen_button" - android:layout_marginStart="4dp" - android:layout_marginEnd="4dp" + android:paddingStart="14dp" + android:paddingEnd="14dp" android:contentDescription="@string/split_screen_text" android:src="@drawable/desktop_mode_ic_handle_menu_splitscreen" android:tint="@androidprv:color/materialColorOnSurface" - android:layout_weight="1" style="@style/DesktopModeHandleMenuWindowingButton"/> + <Space + android:id="@+id/floating_button_space" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_weight="1"/> + <ImageButton android:id="@+id/floating_button" - android:layout_marginStart="4dp" - android:layout_marginEnd="4dp" + android:paddingStart="14dp" + android:paddingEnd="14dp" android:contentDescription="@string/float_button_text" android:src="@drawable/desktop_mode_ic_handle_menu_floating" android:tint="@androidprv:color/materialColorOnSurface" - android:layout_weight="1" style="@style/DesktopModeHandleMenuWindowingButton"/> + <Space + android:id="@+id/desktop_button_space" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_weight="1"/> + <ImageButton android:id="@+id/desktop_button" - android:layout_marginStart="4dp" + android:paddingStart="12dp" + android:paddingEnd="16dp" android:contentDescription="@string/desktop_text" android:src="@drawable/desktop_mode_ic_handle_menu_desktop" android:tint="@androidprv:color/materialColorOnSurface" - android:layout_weight="1" style="@style/DesktopModeHandleMenuWindowingButton"/> </LinearLayout> @@ -126,77 +140,33 @@ android:elevation="@dimen/desktop_mode_handle_menu_pill_elevation" android:background="@drawable/desktop_mode_decor_handle_menu_background"> - <LinearLayout + <com.android.wm.shell.windowdecor.HandleMenuActionButton android:id="@+id/screenshot_button" android:contentDescription="@string/screenshot_text" - style="@style/DesktopModeHandleMenuActionButtonLayout"> - - <ImageView - android:id="@+id/image" - android:src="@drawable/desktop_mode_ic_handle_menu_screenshot" - android:importantForAccessibility="no" - style="@style/DesktopModeHandleMenuActionButtonImage"/> - - <com.android.wm.shell.windowdecor.MarqueedTextView - android:id="@+id/label" - android:text="@string/screenshot_text" - style="@style/DesktopModeHandleMenuActionButtonTextView"/> + android:text="@string/screenshot_text" + android:src="@drawable/desktop_mode_ic_handle_menu_screenshot" + style="@style/DesktopModeHandleMenuActionButton"/> - </LinearLayout> - - <LinearLayout + <com.android.wm.shell.windowdecor.HandleMenuActionButton android:id="@+id/new_window_button" android:contentDescription="@string/new_window_text" - style="@style/DesktopModeHandleMenuActionButtonLayout"> - - <ImageView - android:id="@+id/image" - android:src="@drawable/desktop_mode_ic_handle_menu_new_window" - android:importantForAccessibility="no" - style="@style/DesktopModeHandleMenuActionButtonImage"/> - - <com.android.wm.shell.windowdecor.MarqueedTextView - android:id="@+id/label" - android:text="@string/new_window_text" - style="@style/DesktopModeHandleMenuActionButtonTextView"/> + android:text="@string/new_window_text" + android:src="@drawable/desktop_mode_ic_handle_menu_new_window" + style="@style/DesktopModeHandleMenuActionButton"/> - </LinearLayout> - - <LinearLayout + <com.android.wm.shell.windowdecor.HandleMenuActionButton android:id="@+id/manage_windows_button" android:contentDescription="@string/manage_windows_text" - style="@style/DesktopModeHandleMenuActionButtonLayout"> - - <ImageView - android:id="@+id/image" - android:src="@drawable/desktop_mode_ic_handle_menu_manage_windows" - android:importantForAccessibility="no" - style="@style/DesktopModeHandleMenuActionButtonImage"/> - - <com.android.wm.shell.windowdecor.MarqueedTextView - android:id="@+id/label" - android:text="@string/manage_windows_text" - style="@style/DesktopModeHandleMenuActionButtonTextView"/> - - </LinearLayout> + android:text="@string/manage_windows_text" + android:src="@drawable/desktop_mode_ic_handle_menu_manage_windows" + style="@style/DesktopModeHandleMenuActionButton"/> - <LinearLayout + <com.android.wm.shell.windowdecor.HandleMenuActionButton android:id="@+id/change_aspect_ratio_button" android:contentDescription="@string/change_aspect_ratio_text" - style="@style/DesktopModeHandleMenuActionButtonLayout"> - - <ImageView - android:id="@+id/image" - android:src="@drawable/desktop_mode_ic_handle_menu_change_aspect_ratio" - android:importantForAccessibility="no" - style="@style/DesktopModeHandleMenuActionButtonImage"/> - - <com.android.wm.shell.windowdecor.MarqueedTextView - android:id="@+id/label" - android:text="@string/change_aspect_ratio_text" - style="@style/DesktopModeHandleMenuActionButtonTextView"/> - - </LinearLayout> + android:text="@string/change_aspect_ratio_text" + android:src="@drawable/desktop_mode_ic_handle_menu_change_aspect_ratio" + style="@style/DesktopModeHandleMenuActionButton"/> </LinearLayout> <LinearLayout @@ -209,29 +179,14 @@ android:elevation="@dimen/desktop_mode_handle_menu_pill_elevation" android:background="@drawable/desktop_mode_decor_handle_menu_background"> - <LinearLayout + <com.android.wm.shell.windowdecor.HandleMenuActionButton android:id="@+id/open_in_app_or_browser_button" - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" - android:layout_marginEnd="8dp" - android:gravity="start|center_vertical" - android:paddingStart="16dp" android:contentDescription="@string/open_in_browser_text" - android:background="?android:selectableItemBackground"> - - <ImageView - android:id="@+id/image" - android:src="@drawable/desktop_mode_ic_handle_menu_open_in_browser" - android:importantForAccessibility="no" - style="@style/DesktopModeHandleMenuActionButtonImage"/> - - <com.android.wm.shell.windowdecor.MarqueedTextView - android:id="@+id/label" - android:text="@string/open_in_browser_text" - style="@style/DesktopModeHandleMenuActionButtonTextView"/> - - </LinearLayout> + android:text="@string/open_in_browser_text" + android:src="@drawable/desktop_mode_ic_handle_menu_open_in_browser" + style="@style/DesktopModeHandleMenuActionButton" + android:layout_width="0dp" + android:layout_weight="1"/> <ImageButton android:id="@+id/open_by_default_button" diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_action_button.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_action_button.xml new file mode 100644 index 000000000000..379f4e984b73 --- /dev/null +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_action_button.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2025 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:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/action_button" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="start|center_vertical" + android:paddingHorizontal="16dp" + android:clickable="true" + android:focusable="true" + android:orientation="horizontal" + android:background="?android:attr/selectableItemBackground"> + + <ImageView + android:id="@+id/image" + android:contentDescription="@+id/label" + style="@style/DesktopModeHandleMenuActionButtonImage"/> + + <com.android.wm.shell.windowdecor.MarqueedTextView + android:id="@+id/label" + style="@style/DesktopModeHandleMenuActionButtonTextView"/> +</LinearLayout> diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml index 13e5f34e1586..5444c26e9ec9 100644 --- a/libs/WindowManager/Shell/res/values-af/strings.xml +++ b/libs/WindowManager/Shell/res/values-af/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Links 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Links 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Volskerm regs"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Ruil apps om"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Volskerm bo"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Bo 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Bo 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Stel terug"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Spring na links"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Spring na regs"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Verander grootte van linkerkantse venster"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Verander grootte van regterkantse venster"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimeer of stel venstergrootte terug"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Gaan na deelskermmodus"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Gaan na werkskermvenstermodus"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Verander grootte van linkerkantse venster"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Verander grootte van regterkantse venster"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimeer of stel venstergrootte terug"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maksimeer of stel venstergrootte terug"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimeer appvenster"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Maak By Verstek Oop-instellings"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Kies hoe om webskakels vir hierdie app oop te maak"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In die app"</string> diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml index 14a79aa8475b..f3bc29d95673 100644 --- a/libs/WindowManager/Shell/res/values-am/strings.xml +++ b/libs/WindowManager/Shell/res/values-am/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ግራ 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ግራ 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"የቀኝ ሙሉ ማያ ገፅ"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"መተግበሪያዎችን ይቀያይሩ"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"የላይ ሙሉ ማያ ገፅ"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ከላይ 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ከላይ 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"ወደነበረበት መልስ"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ወደ ግራ አሳድግ"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"ወደ ቀኝ አሳድግ"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"የመተግበሪያ መስኮትን ወደ ግራ መጠን ቀይር"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"የመተግበሪያ መስኮትን ወደ ቀኝ መጠን ቀይር"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"የመስኮት መጠንን አሳድግ ወይም ወደነበረበት መልስ"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"ወደ የተከፈለ ማያ ገፅ ሁነታ ግባ"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ወደ የዴስክቶፕ መስኮት ሁነታ ግባ"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"መስኮትን ወደ ግራ መጠን ቀይር"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"መስኮትን ወደ ቀኝ መጠን ቀይር"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"የመስኮት መጠንን አሳድግ ወይም ወደነበረበት መልስ"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"የመስኮት መጠንን አሳድግ ወይም ወደነበረበት መልስ"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"የመተግበሪያ መስኮትን አሳንስ"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"በነባሪ ቅንብሮች ክፈት"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ለዚህ የድር መተግበሪያ አገናኙን እንዴት እንደሚከፍቱ ይምረጡ"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"በመተግበሪያው ውስጥ"</string> diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml index 9a6869a64f3f..60f27cfdee91 100644 --- a/libs/WindowManager/Shell/res/values-ar/strings.xml +++ b/libs/WindowManager/Shell/res/values-ar/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ضبط حجم النافذة اليسرى ليكون ٥٠%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ضبط حجم النافذة اليسرى ليكون ٣٠%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"عرض النافذة اليمنى بملء الشاشة"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"تبديل التطبيقات"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"عرض النافذة العلوية بملء الشاشة"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ضبط حجم النافذة العلوية ليكون ٧٠%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ضبط حجم النافذة العلوية ليكون ٥٠%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"استعادة"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"المحاذاة إلى اليسار"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"المحاذاة إلى اليمين"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"تغيير حجم نافذة التطبيق بمحاذاتها إلى اليمين"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"تغيير حجم نافذة التطبيق بمحاذاتها إلى اليسار"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"تكبير حجم النافذة أو استعادته"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"تفعيل \"وضع تقسيم الشاشة\""</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"تفعيل وضع عرض المحتوى في النافذة الحالية على سطح المكتب"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"تغيير حجم النافذة بمحاذاتها إلى اليمين"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"تغيير حجم النافذة بمحاذاتها إلى اليسار"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"تكبير حجم النافذة أو استعادته"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"تكبير حجم النافذة أو استعادته"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"تصغير نافذة التطبيق"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"إعدادات الفتح تلقائيًا"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"اختيار طريقة فتح روابط الويب لهذا التطبيق"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"في التطبيق"</string> diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml index 5181930edf57..aced354ac826 100644 --- a/libs/WindowManager/Shell/res/values-az/strings.xml +++ b/libs/WindowManager/Shell/res/values-az/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Sol 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Sol 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Sağ tam ekran"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Tətbiqləri dəyişin"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Yuxarı tam ekran"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Yuxarı 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Yuxarı 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Bərpa edin"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Sola tərəf çəkin"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Sağa tərəf çəkin"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Tətbiq pəncərəsinin ölçüsünü sola dəyişin"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Tətbiq pəncərəsinin ölçüsünü sağa dəyişin"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Pəncərə ölçüsünü artırın və ya bərpa edin"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Bölünmüş ekran rejiminə daxil olun"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Masaüstü pəncərə rejiminə daxil olun"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Pəncərə ölçüsünü sola dəyişin"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Pəncərə ölçüsünü sağa dəyişin"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Pəncərə ölçüsünü artırın və ya bərpa edin"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Pəncərə ölçüsünü artırın və ya bərpa edin"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Tətbiq pəncərəsini kiçildin"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Defolt ayarlarla açın"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Bu tətbiq üçün veb-linklərin necə açılacağını seçin"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Tətbiqdə"</string> diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml index 92580d39f12c..b07c61258f4e 100644 --- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml +++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml @@ -125,11 +125,11 @@ <string name="float_button_text" msgid="9221657008391364581">"Plutajuće"</string> <string name="select_text" msgid="5139083974039906583">"Izaberite"</string> <string name="screenshot_text" msgid="1477704010087786671">"Snimak ekrana"</string> - <string name="open_in_browser_text" msgid="9181692926376072904">"Otvorite u pregledaču"</string> + <string name="open_in_browser_text" msgid="9181692926376072904">"Otvori u pregledaču"</string> <string name="open_in_app_text" msgid="2874590745116268525">"Otvorite u aplikaciji"</string> <string name="new_window_text" msgid="6318648868380652280">"Novi prozor"</string> <string name="manage_windows_text" msgid="5567366688493093920">"Upravljajte prozorima"</string> - <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Promenite razmeru"</string> + <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Promeni razmeru"</string> <string name="close_text" msgid="4986518933445178928">"Zatvorite"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite meni"</string> <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otvorite meni"</string> @@ -138,7 +138,7 @@ <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacija ne može da se premesti ovde"</string> <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Imerzivne"</string> <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Vrati"</string> - <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Uvećajte"</string> + <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Uvećaj"</string> <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Vratite"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Prikačite levo"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Prikačite desno"</string> diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml index e7feb5b6fa8c..fcc4d83baf75 100644 --- a/libs/WindowManager/Shell/res/values-bg/strings.xml +++ b/libs/WindowManager/Shell/res/values-bg/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ляв екран: 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ляв екран: 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Десен екран: Показване на цял екран"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Размяна на приложенията"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Горен екран: Показване на цял екран"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Горен екран: 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Горен екран: 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Възстановяване"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Прилепване наляво"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Прилепване надясно"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Преоразмеряване на прозореца на приложението наляво"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Преоразмеряване на прозореца на приложението надясно"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Увеличаване или възстановяване на размера на прозореца"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Активиране на режима за разделен екран"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Активиране на режима за настолни компютри"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Преоразмеряване на прозореца наляво"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Преоразмеряване на прозореца надясно"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Увеличаване или възстановяване на размера на прозореца"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Увеличаване или възстановяване на размера на прозореца"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Намаляване на прозореца на приложението"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Отваряне на настройките по подразбиране"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Изберете как да се отварят уеб връзките за това приложение"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"В приложението"</string> diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml index f4f887771fd9..b2c435e5ef0e 100644 --- a/libs/WindowManager/Shell/res/values-bn/strings.xml +++ b/libs/WindowManager/Shell/res/values-bn/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"৫০% বাকি আছে"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"৩০% বাকি আছে"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ডান দিকের অংশ নিয়ে পূর্ণ স্ক্রিন"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"অ্যাপ পাল্টান"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"উপর দিকের অংশ নিয়ে পূর্ণ স্ক্রিন"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"শীর্ষ ৭০%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"শীর্ষ ৫০%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"ফিরিয়ে আনুন"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"বাঁদিকে স্ন্যাপ করুন"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"ডানদিকে স্ন্যাপ করুন"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"বাঁদিকে অ্যাপ উইন্ডো রিসাইজ করুন"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ডানদিকে অ্যাপ উইন্ডো রিসাইজ করুন"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"উইন্ডো সাইজ বড় বা রিস্টোর করুন"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"স্প্লিট স্ক্রিন মোডে প্রবেশ করুন"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ডেস্কটপ উইন্ডোইং মোডে প্রবেশ করুন"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"বাঁদিকে উইন্ডো রিসাইজ করুন"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ডানদিকে উইন্ডো রিসাইজ করুন"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"উইন্ডো সাইজ বড় বা রিস্টোর করুন"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"উইন্ডো সাইজ বড় বা রিস্টোর করুন"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"অ্যাপ উইন্ডো ছোট করুন"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"ডিফল্ট হিসেবে থাকা সেটিংস খুলুন"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"এই অ্যাপের জন্য কীভাবে ওয়েব লিঙ্ক খুলবেন তা বেছে নিন"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"অ্যাপের মধ্যে"</string> diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml index 12e4fc2700ed..8c1619ce925c 100644 --- a/libs/WindowManager/Shell/res/values-bs/strings.xml +++ b/libs/WindowManager/Shell/res/values-bs/strings.xml @@ -43,7 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Lijevo 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Lijevo 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Desno cijeli ekran"</string> - <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Zamijeni aplikacije"</string> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Zamjena aplikacija"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Gore cijeli ekran"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Gore 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gore 50%"</string> @@ -138,20 +138,20 @@ <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ne možete premjestiti aplikaciju ovdje"</string> <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Uvjerljivo"</string> <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Vraćanje"</string> - <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimiziranje"</string> + <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimiziraj"</string> <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Vraćanje"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Pomicanje ulijevo"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Pomicanje udesno"</string> - <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Promijeni veličinu prozora aplikacije ulijevo"</string> - <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Promijeni veličinu prozora aplikacije udesno"</string> - <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimiziraj ili vrati veličinu prozora"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Pokreni način podijeljenog zaslona"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Pokreni način prikaza u prozorima na računalu"</string> - <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Promijeni veličinu prozora ulijevo"</string> - <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Promijeni veličinu prozora udesno"</string> - <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimiziraj ili vrati veličinu prozora"</string> - <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maksimiziraj ili vrati veličinu prozora"</string> - <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimiziraj prozor aplikacije"</string> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Promjena veličine prozora aplikacije lijevo"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Promjena veličine prozora aplikacije desno"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimiziranje ili vraćanje veličine prozora"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Pokretanje načina rada podijeljenog ekrana"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Pokretanje načina rada s prozorima na radnoj površini"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Promjena veličine prozora i poravnanje lijevo"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Promjena veličine prozora i poravnanje desno"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimiziranje ili vraćanje veličine prozora"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maksimiziranje ili vraćanje veličine prozora"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimiziranje prozora aplikacije"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Otvaranje prema zadanim postavkama"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Odaberite način otvaranja web linkova za ovu aplikaciju"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"U aplikaciji"</string> diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml index 1623954d1d7c..37802f4c7f94 100644 --- a/libs/WindowManager/Shell/res/values-ca/strings.xml +++ b/libs/WindowManager/Shell/res/values-ca/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Pantalla esquerra al 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Pantalla esquerra al 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pantalla dreta completa"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Canvia les aplicacions"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Pantalla superior completa"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Pantalla superior al 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Pantalla superior al 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restaura"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Ajusta a l\'esquerra"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Ajusta a la dreta"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Canvia la mida de la finestra de l\'aplicació a l\'esquerra"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Canvia la mida de la finestra de l\'aplicació a la dreta"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximitza o restaura la mida de la finestra"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Entra al mode de pantalla dividida"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Entra al mode d\'enfinestrament a l\'escriptori"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Canvia la mida de la finestra a l\'esquerra"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Canvia la mida de la finestra a la dreta"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximitza o restaura la mida de la finestra"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maximitza o restaura la mida de la finestra"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimitza la finestra de l\'aplicació"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Configuració d\'obertura predeterminada"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Tria com vols obrir els enllaços web per a aquesta aplicació"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"A l\'aplicació"</string> diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml index f6ac59ca24b7..c4514eb4ce8d 100644 --- a/libs/WindowManager/Shell/res/values-cs/strings.xml +++ b/libs/WindowManager/Shell/res/values-cs/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % vlevo"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30 % vlevo"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pravá část na celou obrazovku"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Zaměnit aplikace"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Horní část na celou obrazovku"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70 % nahoře"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % nahoře"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Obnovit"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Přichytit vlevo"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Přichytit vpravo"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Změnit velikost okna aplikace vlevo"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Změnit velikost okna aplikace vpravo"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximalizovat nebo obnovit velikost okna"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Přechod do režimu rozdělené obrazovky"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Přejít do režimu okenního systému pro počítače"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Přichytit okno vlevo"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Přichytit okno vpravo"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximalizovat nebo obnovit velikost okna"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maximalizovat nebo obnovit velikost okna"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimalizovat okno aplikace"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Otevírat podle výchozího nastavení"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Určete, jak se v této aplikaci mají otevírat webové odkazy"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"V aplikaci"</string> diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml index d7ee8a0cf8c3..7b21719bc880 100644 --- a/libs/WindowManager/Shell/res/values-de/strings.xml +++ b/libs/WindowManager/Shell/res/values-de/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % links"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30 % links"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Vollbild rechts"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Apps austauschen"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Vollbild oben"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70 % oben"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % oben"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Wiederherstellen"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Links andocken"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Rechts andocken"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Größe des linken App-Fensters anpassen"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Größe des rechten App-Fensters anpassen"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Fenstergröße maximieren oder wiederherstellen"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Splitscreen-Modus aktivieren"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Desktop-Fenstermodus aktivieren"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Fenstergröße links anpassen"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Fenstergröße rechts anpassen"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Fenstergröße maximieren oder wiederherstellen"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Fenstergröße maximieren oder wiederherstellen"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"App-Fenster minimieren"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Einstellungen für die Option „Standardmäßig öffnen“"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Festlegen, wie Weblinks für diese App geöffnet werden"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In der App"</string> diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml index 4ba68b4fc9db..eb45a31c5d8a 100644 --- a/libs/WindowManager/Shell/res/values-el/strings.xml +++ b/libs/WindowManager/Shell/res/values-el/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Αριστερή 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Αριστερή 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Δεξιά πλήρης οθόνη"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Εναλλαγή εφαρμογών"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Πάνω πλήρης οθόνη"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Πάνω 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Πάνω 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Επαναφορά"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Κούμπωμα αριστερά"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Κούμπωμα δεξιά"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Αλλαγή μεγέθους παραθύρου εφαρμογής αριστερά"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Αλλαγή μεγέθους παραθύρου εφαρμογής δεξιά"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Μεγιστοποίηση ή επαναφορά μεγέθους παραθύρου"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Είσοδος στη λειτουργία διαχωρισμού οθόνης"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Είσοδος στη λειτουργία προσαρμογής σε παράθυρο υπολογιστή"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Αλλαγή μεγέθους παραθύρου προς τα αριστερά"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Αλλαγή μεγέθους παραθύρου προς τα δεξιά"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Μεγιστοποίηση ή επαναφορά μεγέθους παραθύρου"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Μεγιστοποίηση ή επαναφορά μεγέθους παραθύρου"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Ελαχιστοποίηση παραθύρου εφαρμογής"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Άνοιγμα ρυθμίσεων από προεπιλογή"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Επιλογή τρόπου ανοίγματος συνδέσμων ιστού για την εφαρμογή"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Στην εφαρμογή"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml index 8b1a14f66195..8dc27dabfc2c 100644 --- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Left 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Right full screen"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Swap apps"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Top full screen"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Top 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restore"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Snap left"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Snap right"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Resize app window left"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Resize app window right"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximise or restore window size"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Enter split-screen mode"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Enter desktop windowing mode"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Resize window to left"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Resize window to right"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximise or restore window size"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maximise or restore window size"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimise app window"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Open by default settings"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choose how to open web links for this app"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In the app"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml index 8b1a14f66195..8dc27dabfc2c 100644 --- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Left 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Right full screen"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Swap apps"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Top full screen"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Top 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restore"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Snap left"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Snap right"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Resize app window left"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Resize app window right"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximise or restore window size"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Enter split-screen mode"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Enter desktop windowing mode"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Resize window to left"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Resize window to right"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximise or restore window size"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maximise or restore window size"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimise app window"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Open by default settings"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choose how to open web links for this app"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In the app"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml index 8b1a14f66195..8dc27dabfc2c 100644 --- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Left 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Right full screen"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Swap apps"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Top full screen"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Top 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restore"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Snap left"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Snap right"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Resize app window left"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Resize app window right"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximise or restore window size"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Enter split-screen mode"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Enter desktop windowing mode"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Resize window to left"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Resize window to right"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximise or restore window size"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maximise or restore window size"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimise app window"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Open by default settings"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choose how to open web links for this app"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In the app"</string> diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml index f36135e1febd..dd9635dccfcb 100644 --- a/libs/WindowManager/Shell/res/values-es/strings.xml +++ b/libs/WindowManager/Shell/res/values-es/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Izquierda 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Izquierda 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pantalla derecha completa"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Cambiar aplicaciones"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Pantalla superior completa"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Superior 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Superior 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restaurar"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Acoplar a la izquierda"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Acoplar a la derecha"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Cambiar tamaño de la ventana de la aplicación izquierda"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Cambiar tamaño de la ventana de la aplicación derecha"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximizar o restaurar tamaño de la ventana"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Activar modo Pantalla dividida"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Activar modo Escritorio basado en ventanas"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Cambiar tamaño de la ventana a la izquierda"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Cambiar tamaño de la ventana a la derecha"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar o restaurar tamaño de la ventana"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maximizar o restaurar tamaño de la ventana"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimizar ventana de la aplicación"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Abrir con los ajustes predeterminados"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Elige cómo quieres abrir los enlaces web de esta aplicación"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"En la aplicación"</string> diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml index b77d0eb642f7..9898af0c394d 100644 --- a/libs/WindowManager/Shell/res/values-eu/strings.xml +++ b/libs/WindowManager/Shell/res/values-eu/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ezarri ezkerraldea % 50en"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ezarri ezkerraldea % 30en"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Ezarri eskuinaldea pantaila osoan"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Aldatu aplikazioz"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Ezarri goialdea pantaila osoan"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Ezarri goialdea % 70en"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Ezarri goialdea % 50en"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Leheneratu"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Ezarri ezkerrean"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Ezarri eskuinean"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Aldatu aplikazioaren leihoaren tamaina eta eraman ezkerrera"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Aldatu aplikazioaren leihoaren tamaina eta eraman eskuinera"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximizatu edo leheneratu leihoaren tamaina"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Sartu pantaila zatituaren moduan"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Sartu ordenagailuan leihoak erabiltzeko moduan"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Aldatu leihoaren tamaina eta eraman ezkerrera"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Aldatu leihoaren tamaina eta eraman eskuinera"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizatu edo leheneratu leihoaren tamaina"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maximizatu edo leheneratu leihoaren tamaina"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimizatu aplikazioaren leihoa"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Modu lehenetsian irekitzearen ezarpenak"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Aukeratu nola ireki sareko estekak aplikazio honetan"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Aplikazioan"</string> diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml index 06ff6e74322c..b23c833fa453 100644 --- a/libs/WindowManager/Shell/res/values-fi/strings.xml +++ b/libs/WindowManager/Shell/res/values-fi/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vasen 50 %"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Vasen 30 %"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Oikea koko näytölle"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Vaihda sovellusta"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Yläosa koko näytölle"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Yläosa 70 %"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Yläosa 50 %"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Palauta"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Siirrä vasemmalle"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Siirrä oikealle"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Muuta vasemmanpuoleisen sovellusikkunan kokoa"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Muuta oikeanpuoleisen sovellusikkunan kokoa"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Suurenna ikkuna tai palauta ikkunan koko"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Avaa kahtia jaettu näyttö"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Siirry työpöydän ikkunointitilaan"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Muuta vasemmanpuoleisen ikkunan kokoa"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Muuta vasemmanpuoleisen ikkunan kokoa"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Suurenna ikkuna tai palauta ikkunan koko"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Suurenna ikkuna tai palauta ikkunan koko"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Pienennä sovellusikkuna"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Avaa oletusasetusten mukaan"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Valitse, miten verkkolinkit avataan tässä sovelluksessa"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Sovelluksessa"</string> diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml index 08ff1d35a8c7..34b5b0acf753 100644 --- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % à la gauche"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30 % à la gauche"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Plein écran à la droite"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Permuter des applis"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Plein écran dans le haut"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70 % dans le haut"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % dans le haut"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restaurer"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Épingler à gauche"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Épingler à droite"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Redimensionner la fenêtre de l\'appli à gauche"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Redimensionner la fenêtre de l\'appli à droite"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Agrandir ou restaurer la taille de la fenêtre"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Entrer en mode Écran divisé"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Entrer en mode Fenêtrage bureau"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionner la fenêtre vers la gauche"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionner la fenêtre vers la droite"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Agrandir ou restaurer la taille de la fenêtre"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Agrandir ou restaurer la taille de la fenêtre"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Réduire la fenêtre de l\'appli"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Ouvrir les paramètres par défaut"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choisissez comment ouvrir les liens Web pour cette appli"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Dans l\'appli"</string> diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml index 9ced5c7bafd4..be41bba34772 100644 --- a/libs/WindowManager/Shell/res/values-fr/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Écran de gauche à 50 %"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Écran de gauche à 30 %"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Écran de droite en plein écran"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Échanger les applis"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Écran du haut en plein écran"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Écran du haut à 70 %"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Écran du haut à 50 %"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restaurer"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Ancrer à gauche"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Ancrer à droite"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Redimensionner la fenêtre de l\'appli vers la gauche"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Redimensionner la fenêtre de l\'appli vers la droite"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Agrandir ou restaurer la taille de la fenêtre"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Passer en mode Écran partagé"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Activer le mode fenêtrage du bureau"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionner la fenêtre vers la gauche"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionner la fenêtre vers la droite"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Agrandir ou restaurer la taille de la fenêtre"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Agrandir ou restaurer la taille de la fenêtre"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Réduire la fenêtre de l\'application"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Ouvrir les paramètres par défaut"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choisir comment ouvrir les liens Web pour cette appli"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Dans l\'application"</string> diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml index d8c422fd1bd2..dcd57385809f 100644 --- a/libs/WindowManager/Shell/res/values-gu/strings.xml +++ b/libs/WindowManager/Shell/res/values-gu/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ડાબે 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ડાબે 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"જમણી સ્ક્રીન સ્ક્રીન"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"ઍપને સ્વૉપ કરો"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"શીર્ષ પૂર્ણ સ્ક્રીન"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"શીર્ષ 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"શીર્ષ 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"રિસ્ટોર કરો"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ડાબે સ્નૅપ કરો"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"જમણે સ્નૅપ કરો"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ડાબી બાજુથી ઍપની વિન્ડોનું કદ બદલો"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"જમણી બાજુથી ઍપની વિન્ડોનું કદ બદલો"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"વિન્ડોનું કદ મહત્તમ કરો અથવા રિસ્ટોર કરો"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"સ્ક્રીન-વિભાજન મોડ દાખલ કરો"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ડેસ્કટૉપ વિન્ડો મોડ દાખલ કરો"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ડાબી બાજુ વિન્ડોનું કદ બદલો"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"જમણી બાજુ વિન્ડોનું કદ બદલો"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"વિન્ડોનું કદ મહત્તમ કરો અથવા રિસ્ટોર કરો"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"વિન્ડોનું કદ મહત્તમ કરો અથવા રિસ્ટોર કરો"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"ઍપની વિન્ડોને નાની કરો"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"\'ડિફૉલ્ટ તરીકે ખોલો\' સેટિંગ"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"આ ઍપ માટે વેબ લિંક ખોલવાની રીત પસંદ કરો"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ઍપમાં"</string> diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml index f8215afb1c05..4bf2d92c1860 100644 --- a/libs/WindowManager/Shell/res/values-hi/strings.xml +++ b/libs/WindowManager/Shell/res/values-hi/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"बाईं स्क्रीन को 50% बनाएं"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"बाईं स्क्रीन को 30% बनाएं"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"दाईं स्क्रीन को फ़ुल स्क्रीन बनाएं"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"ऐप्लिकेशन स्वैप करें"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ऊपर की स्क्रीन को फ़ुल स्क्रीन बनाएं"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ऊपर की स्क्रीन को 70% बनाएं"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ऊपर की स्क्रीन को 50% बनाएं"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"पहले जैसा करें"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"बाईं ओर स्नैप करें"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"दाईं ओर स्नैप करें"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ऐप्लिकेशन विंडो का साइज़ बाईं ओर से बदलें"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ऐप्लिकेशन विंडो का साइज़ दाईं ओर से बदलें"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"विंडो को बड़ा करें या उसका साइज़ पहले जैसा करें"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"स्प्लिट स्क्रीन मोड में चालू करें"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"डेस्कटॉप विंडो मोड में जाएं"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"विंडो का साइज़ बाईं ओर से बदलें"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"विंडो का साइज़ दाईं ओर से बढ़ाएं"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"विंडो को बड़ा करें या उसका साइज़ पहले जैसा करें"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"विंडो को बड़ा करें या उसका साइज़ पहले जैसा करें"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"ऐप्लिकेशन की विंडो को छोटा करें"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"डिफ़ॉल्ट सेटिंग के हिसाब से खोलें"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"इस ऐप्लिकेशन के लिए वेब लिंक खोलने का तरीका चुनें"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ऐप्लिकेशन में"</string> diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml index 76e7579232d9..546a465c8699 100644 --- a/libs/WindowManager/Shell/res/values-hu/strings.xml +++ b/libs/WindowManager/Shell/res/values-hu/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Bal oldali 50%-ra"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Bal oldali 30%-ra"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Jobb oldali teljes képernyőre"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Váltás az alkalmazások között"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Felső teljes képernyőre"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Felső 70%-ra"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Felső 50%-ra"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Visszaállítás"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Balra igazítás"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Jobbra igazítás"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Alkalmazásablak átméretezése balra"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Alkalmazásablak átméretezése jobbra"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Ablak teljes méretre állítása vagy visszaállítása"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Belépés osztott képernyős módba"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Asztali ablakkezelési mód indítása"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ablak átméretezése balra"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ablak átméretezése jobbra"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Ablak teljes méretre állítása vagy visszaállítása"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Ablak teljes méretre állítása vagy visszaállítása"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Alkalmazásablak kis méretre állítása"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Alapértelmezett beállítások megnyitása"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Az app webes linkjeinek megnyitásához használt módszer"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Az alkalmazásban"</string> diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml index 0eb75c79e4b8..39a395f9add1 100644 --- a/libs/WindowManager/Shell/res/values-hy/strings.xml +++ b/libs/WindowManager/Shell/res/values-hy/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ձախ էկրանը՝ 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ձախ էկրանը՝ 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Աջ էկրանը՝ լիաէկրան"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Հավելվածները տեղերով փոխել"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Վերևի էկրանը՝ լիաէկրան"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Վերևի էկրանը՝ 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Վերևի էկրանը՝ 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Վերականգնել"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Ամրացնել ձախ կողմում"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Ամրացնել աջ կողմում"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Ձգել հավելվածի պատուհանը դեպի ձախ"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Ձգել հավելվածի պատուհանը դեպի աջ"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Ծավալել կամ վերականգնել պատուհանի չափսը"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Մտնել էկրանի տրոհման ռեժիմ"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Մտնել համակարգչի ռեժիմ"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ձգել պատուհանը դեպի ձախ"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ձգել պատուհանը դեպի աջ"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Ծավալել կամ վերականգնել պատուհանի չափսը"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Ծավալել կամ վերականգնել պատուհանի չափսը"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Ծալել հավելվածի պատուհանը"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Բացել կարգավորումներն ըստ կանխադրման"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Ընտրեք՝ ինչպես բացել այս հավելվածի վեբ հղումները"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Հավելվածում"</string> diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml index 813e9783f336..09ce5257c56e 100644 --- a/libs/WindowManager/Shell/res/values-in/strings.xml +++ b/libs/WindowManager/Shell/res/values-in/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kiri 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kiri 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Layar penuh di kanan"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Ganti Aplikasi"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Layar penuh di atas"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Atas 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Atas 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Pulihkan"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Maksimalkan ke kiri"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Maksimalkan ke kanan"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Ubah ukuran jendela aplikasi ke kiri"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Ubah ukuran jendela aplikasi ke kanan"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimalkan atau pulihkan ukuran jendela"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Masuk ke mode layar terpisah"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Masuk ke mode windowing desktop"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ubah ukuran jendela ke kiri"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ubah ukuran jendela ke kanan"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimalkan atau pulihkan ukuran jendela"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maksimalkan atau pulihkan ukuran jendela"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimalkan jendela aplikasi"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Buka dengan setelan default"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Pilih cara membuka link web untuk aplikasi ini"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Di aplikasi"</string> diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml index 1cd89a615cb2..b164b1131ad2 100644 --- a/libs/WindowManager/Shell/res/values-iw/strings.xml +++ b/libs/WindowManager/Shell/res/values-iw/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"שמאלה 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"שמאלה 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"מסך ימני מלא"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"מעבר בין אפליקציות"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"מסך עליון מלא"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"עליון 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"עליון 50%"</string> @@ -130,7 +129,7 @@ <string name="open_in_app_text" msgid="2874590745116268525">"פתיחה באפליקציה"</string> <string name="new_window_text" msgid="6318648868380652280">"חלון חדש"</string> <string name="manage_windows_text" msgid="5567366688493093920">"ניהול החלונות"</string> - <string name="change_aspect_ratio_text" msgid="9104456064548212806">"שינוי של יחס גובה-רוחב"</string> + <string name="change_aspect_ratio_text" msgid="9104456064548212806">"שינוי יחס הגובה-רוחב"</string> <string name="close_text" msgid="4986518933445178928">"סגירה"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"סגירת התפריט"</string> <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"פתיחת התפריט"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"שחזור"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"הצמדה לשמאל"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"הצמדה לימין"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"שינוי הגודל של חלון האפליקציה שמשמאל"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"שינוי הגודל של חלון האפליקציה שמימין"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"שחזור של גודל החלון או הגדלת החלון"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"כניסה למצב מסך מפוצל"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"כניסה למצב שינוי הגודל של החלונות בממשק המחשב"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"שינוי גודל החלון שמשמאל"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"שינוי גודל החלון שמימין"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"שחזור של גודל החלון או הגדלת החלון"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"שחזור של גודל החלון או הגדלת החלון"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"מזעור החלון של האפליקציה"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"הגדרות לפתיחה כברירת מחדל"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"כאן בוחרים איך לפתוח באפליקציה הזו קישורים לדפי אינטרנט"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"באפליקציה"</string> diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml index 02e0f320eea6..1be19af9b372 100644 --- a/libs/WindowManager/Shell/res/values-ka/strings.xml +++ b/libs/WindowManager/Shell/res/values-ka/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"მარცხენა ეკრანი — 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"მარცხენა ეკრანი — 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"მარჯვენა ნაწილის სრულ ეკრანზე გაშლა"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"აპების გადართვა"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ზედა ნაწილის სრულ ეკრანზე გაშლა"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ზედა ეკრანი — 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ზედა ეკრანი — 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"აღდგენა"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"მარცხნივ გადატანა"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"მარჯვნივ გადატანა"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"აპის მარცხენა ფანჯრის ზომის შეცვლა"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"აპის მარჯვენა ფანჯრის ზომის შეცვლა"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ფანჯრის მაქსიმალურ ზომამდე გაზრდა ან აღდგენა"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"გაყოფილი ეკრანის რეჟიმში შესვლა"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"დესკტოპის ფანჯრის რეჟიმში შესვლა"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ფანჯრის ზომის შეცვლა მარცხნივ"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ფანჯრის ზომის შეცვლა მარჯვნივ"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ფანჯრის მაქსიმალურ ზომამდე გაზრდა ან აღდგენა"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"ფანჯრის მაქსიმალურ ზომამდე გაზრდა ან აღდგენა"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"აპის ფანჯრის ზომის შემცირება"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"პარამეტრების ნაგულისხმევად გახსნა"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ამ აპისთვის ვებ ბმულების გახსნის წესის არჩევა"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"აპში"</string> diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml index 61c331df7598..5bd85191ec65 100644 --- a/libs/WindowManager/Shell/res/values-kk/strings.xml +++ b/libs/WindowManager/Shell/res/values-kk/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% сол жақта"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30% сол жақта"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Оң жағын толық экранға шығару"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Қолданбаларды ауыстыру"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Жоғарғы жағын толық экранға шығару"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70% жоғарғы жақта"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% жоғарғы жақта"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Қалпына келтіру"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Солға тіркеу"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Оңға тіркеу"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Қолданба терезесінің өлшемін сол жақтан өзгерту"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Қолданба терезесінің өлшемін оң жақтан өзгерту"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Терезе өлшемін ұлғайту не қалпына келтіру"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Экранды бөлу режиміне өту"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Жұмыс үстелінің терезе режиміне өту"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Терезе өлшемін сол жаққа өзгерту"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Терезе өлшемін оң жаққа өзгерту"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Терезе өлшемін ұлғайту не қалпына келтіру"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Терезе өлшемін ұлғайту не қалпына келтіру"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Қолданба терезесін кішірейту"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Әдепкісінше ашу параметрлері"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Осы қолданбадағы веб-сілтемелерді ашу жолын таңдаңыз"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Қолданбада"</string> diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml index 13c700952609..65add57a9e6b 100644 --- a/libs/WindowManager/Shell/res/values-ko/strings.xml +++ b/libs/WindowManager/Shell/res/values-ko/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"왼쪽 화면 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"왼쪽 화면 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"오른쪽 화면 전체화면"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"앱 전환"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"위쪽 화면 전체화면"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"위쪽 화면 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"위쪽 화면 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"복원"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"왼쪽으로 맞추기"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"오른쪽으로 맞추기"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"앱 창 크기 왼쪽으로 조절"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"앱 창 크기 오른쪽으로 조절"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"창 최대화 또는 크기 복원"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"화면 분할 모드 시작"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"데스크톱 창 모드 시작"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"창 크기 왼쪽으로 조절"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"창 크기 오른쪽으로 조절"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"창 최대화 또는 크기 복원"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"창 최대화 또는 크기 복원"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"앱 창 최소화"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"기본값으로 열기 설정"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"이 앱에서 웹 링크를 여는 방법을 선택하세요"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"앱에서"</string> diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml index eb990f142da8..96c2226daf58 100644 --- a/libs/WindowManager/Shell/res/values-ky/strings.xml +++ b/libs/WindowManager/Shell/res/values-ky/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Сол жактагы экранды 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Сол жактагы экранды 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Оң жактагы экранды толук экран режимине өткөрүү"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Колдонмолорду алмаштыруу"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Үстүнкү экранды толук экран режимине өткөрүү"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Үстүнкү экранды 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Үстүнкү экранды 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Калыбына келтирүү"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Солго жылдыруу"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Оңго жылдыруу"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Колдонмонун терезесинин өлчөмүн солго өзгөртүү"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Колдонмонун терезесинин өлчөмүн оңго өзгөртүү"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Терезенин өлчөмүн чоңойтуу же калыбына келтирүү"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Экранды бөлүү режимине өтүү"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Иш тактанын терезелери режимине өтүү"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Терезенин өлчөмүн солго өзгөртүү"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Терезенин өлчөмүн оңго өзгөртүү"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Терезенин өлчөмүн чоңойтуу же калыбына келтирүү"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Терезенин өлчөмүн чоңойтуу же калыбына келтирүү"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Колдонмонун терезесин кичирейтүү"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Демейки шартта ачылуучу шилтемелердин параметрлери"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Колдонмодо шилтемелер кантип ачыларын тандаңыз"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Колдонмодо"</string> diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml index 50164c081bb4..9337efc92606 100644 --- a/libs/WindowManager/Shell/res/values-lo/strings.xml +++ b/libs/WindowManager/Shell/res/values-lo/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ຊ້າຍ 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ຊ້າຍ 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ເຕັມໜ້າຈໍຂວາ"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"ສະຫຼັບແອັບ"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ເຕັມໜ້າຈໍເທິງສຸດ"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ເທິງສຸດ 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ເທິງສຸດ 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"ກູ້ຄືນ"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ແນບຊ້າຍ"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"ແນບຂວາ"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ປັບຂະໜາດໜ້າຈໍແອັບໄປທາງຊ້າຍ"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ປັບຂະໜາດໜ້າຈໍແອັບໄປທາງຂວາ"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ຂະຫຍາຍ ຫຼື ຄືນຄ່າຂະໜາດໜ້າຈໍ"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"ເຂົ້າສູ່ໂໝດແບ່ງໜ້າຈໍ"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ເຂົ້າສູ່ໂໝດໜ້າຈໍເດັສທັອບ"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ປັບຂະໜາດໜ້າຈໍໄປທາງຊ້າຍ"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ປັບຂະໜາດໜ້າຈໍໄປທາງຂວາ"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ຂະຫຍາຍ ຫຼື ຄືນຄ່າຂະໜາດໜ້າຈໍ"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"ຂະຫຍາຍ ຫຼື ຄືນຄ່າຂະໜາດໜ້າຈໍ"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"ຫຍໍ້ໜ້າຈໍແອັບ"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"ເປີດຕາມການຕັ້ງຄ່າເລີ່ມຕົ້ນ"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ເລືອກວິທີເປີດລິ້ງເວັບສຳລັບແອັບນີ້"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ໃນແອັບ"</string> diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml index a5547b0f71ea..24a969bc8c1b 100644 --- a/libs/WindowManager/Shell/res/values-lv/strings.xml +++ b/libs/WindowManager/Shell/res/values-lv/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Pa kreisi 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Pa kreisi 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Labā daļa pa visu ekrānu"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Apmainīt lietotnes"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Augšdaļa pa visu ekrānu"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Augšdaļa 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Augšdaļa 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Atjaunot"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Piestiprināt pa kreisi"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Piestiprināt pa labi"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Mainīt lietotnes loga lielumu uz kreiso pusi"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Mainīt lietotnes loga lielumu uz labo pusi"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimizēt vai atjaunot loga lielumu"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Ieslēgt ekrāna sadalīšanas režīmu"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Ieslēgt darbvirsmas logu režīmu"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Mainīt loga lielumu uz kreiso pusi"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Mainīt loga lielumu uz labo pusi"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimizēt vai atjaunot loga lielumu"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maksimizēt vai atjaunot loga lielumu"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimizēt lietotnes logu"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Atvērt pēc noklusējuma iestatījumiem"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Izvēlieties, kā atvērt šajā lietotnē norādītās saites"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Lietotnē"</string> diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml index 6593e2d9e66b..f7177acc8681 100644 --- a/libs/WindowManager/Shell/res/values-mk/strings.xml +++ b/libs/WindowManager/Shell/res/values-mk/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Левиот 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Левиот 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Десниот на цел екран"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Менувајте апликации"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Горниот на цел екран"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Горниот 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Горниот 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Врати"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Фотографирај лево"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Фотографирај десно"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Променете ја големината на прозорецот на апликацијата одлево"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Променете ја големината на прозорецот на апликацијата оддесно"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Максимизирајте или вратете ја големината на прозорецот"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Влезете во „Режим на поделен екран“"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Влезете во „Режим со прозорци на работната површина“"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Променете ја големината на прозорецот налево"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Променете ја големината на прозорецот надесно"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Максимизирајте или вратете ја големината на прозорецот"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Максимизирајте или вратете ја големината на прозорецот"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Минимизирајте го прозорецот на апликацијата"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Отвори според стандардните поставки"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Изберете како да се отвораат линковите за апликацијава"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Во апликацијата"</string> diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml index 8914e1fa782a..b38026cc5445 100644 --- a/libs/WindowManager/Shell/res/values-mn/strings.xml +++ b/libs/WindowManager/Shell/res/values-mn/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Зүүн 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Зүүн 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Баруун талын бүтэн дэлгэц"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Аппуудыг солих"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Дээд талын бүтэн дэлгэц"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Дээд 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Дээд 50%"</string> @@ -130,7 +129,7 @@ <string name="open_in_app_text" msgid="2874590745116268525">"Аппад нээх"</string> <string name="new_window_text" msgid="6318648868380652280">"Шинэ цонх"</string> <string name="manage_windows_text" msgid="5567366688493093920">"Windows-г удирдах"</string> - <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Харьцааг өөрчлөх"</string> + <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Аспектын харьцааг өөрчлөх"</string> <string name="close_text" msgid="4986518933445178928">"Хаах"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Цэсийг хаах"</string> <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Цэсийг нээх"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Сэргээх"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Зүүн тийш зэрэгцүүлэх"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Баруун тийш зэрэгцүүлэх"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Аппын цонхны хэмжээг зүүн тал руу өөрчлөх"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Аппын цонхны хэмжээг баруун тал руу өөрчлөх"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Цонхны хэмжээг томруулах эсвэл сэргээх"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Дэлгэц хуваах горимд орох"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Дэлгэцийн цонхны горимд орох"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Цонхны хэмжээг зүүн тал руу өөрчлөх"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Цонхны хэмжээг баруун тал руу өөрчлөх"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Цонхны хэмжээг томруулах эсвэл сэргээх"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Цонхны хэмжээг томруулах эсвэл сэргээх"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Аппын цонхыг жижгэрүүлэх"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Өгөгдмөл тохиргоогоор нээх"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Энэ аппад веб холбоосыг хэрхэн нээхийг сонгоно уу"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Аппад"</string> diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml index 81594798ef48..d9c1d1f45a55 100644 --- a/libs/WindowManager/Shell/res/values-mr/strings.xml +++ b/libs/WindowManager/Shell/res/values-mr/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"डावी 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"डावी 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"उजवी फुल स्क्रीन"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"अॅप्स स्वॅप करा"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"शीर्ष फुल स्क्रीन"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"शीर्ष 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"शीर्ष 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"रिस्टोअर करा"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"डावीकडे स्नॅप करा"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"उजवीकडे स्नॅप करा"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"अॅप विंडोचा डावीकडून आकार बदला"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"अॅप विंडोचा उजवीकडून आकार बदला"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"विंडोचा आकार मोठा करा किंवा रिस्टोअर करा"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"स्प्लिट स्क्रीन मोड एंटर करा"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"डेस्कटॉप विंडोइंग मोड एंटर करा"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"अॅप विंडोचा डावीकडे आकार बदला"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"अॅप विंडोचा उजवीकडे आकार बदला"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"विंडोचा आकार मोठा करा किंवा रिस्टोअर करा"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"विंडोचा आकार मोठा करा किंवा रिस्टोअर करा"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"अॅप विंडो लहान करा"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"बाय डीफॉल्ट सेटिंग्ज उघडा"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"या अॅपसाठीच्या वेब लिंक कशा उघडाव्यात हे निवडा"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ॲपमध्ये"</string> diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml index b749b670f74d..1f4db6d9b872 100644 --- a/libs/WindowManager/Shell/res/values-my/strings.xml +++ b/libs/WindowManager/Shell/res/values-my/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ဘယ်ဘက် မျက်နှာပြင် ၅၀%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ဘယ်ဘက် မျက်နှာပြင် ၃၀%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ညာဘက် မျက်နှာပြင်အပြည့်"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"အက်ပ်ပြောင်းရန်"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"အပေါ်ဘက် မျက်နှာပြင်အပြည့်"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"အပေါ်ဘက် မျက်နှာပြင် ၇၀%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"အပေါ်ဘက် မျက်နှာပြင် ၅၀%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"ပြန်ပြောင်းရန်"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ဘယ်တွင် ချဲ့ရန်"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"ညာတွင် ချဲ့ရန်"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"အက်ပ်ဝင်းဒိုး ဘယ်ဘက်ကို အရွယ်ပြင်ရန်"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"အက်ပ်ဝင်းဒိုး ညာဘက်ကို အရွယ်ပြင်ရန်"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ဝင်းဒိုးအရွယ်အစားကို ချဲ့ရန် (သို့) ပြန်ပြောင်းရန်"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"မျက်နှာပြင်ခွဲပြခြင်းမုဒ်သို့ ဝင်ရန်"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ဒက်စ်တော့ ဝင်းဒိုးမုဒ်သို့ ဝင်ရန်"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ဝင်းဒိုးကို ဘယ်ဘက်သို့ အရွယ်ပြင်ရန်"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ဝင်းဒိုးကို ညာဘက်သို့ အရွယ်ပြင်ရန်"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ဝင်းဒိုးအရွယ်အစားကို ချဲ့ရန် (သို့) ပြန်ပြောင်းရန်"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"ဝင်းဒိုးအရွယ်အစားကို ချဲ့ရန် (သို့) ပြန်ပြောင်းရန်"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"အက်ပ်ဝင်းဒိုးကို ချုံ့ရန်"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"မူရင်းဆက်တင်ဖြင့် ဖွင့်ရန်"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ဤအက်ပ်အတွက် ဝဘ်လင့်ခ်များ မည်သို့ဖွင့်မည်ကို ရွေးပါ"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"အက်ပ်တွင်"</string> diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml index 86aa19650003..586a50f74f0d 100644 --- a/libs/WindowManager/Shell/res/values-nb/strings.xml +++ b/libs/WindowManager/Shell/res/values-nb/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Sett størrelsen på den venstre delen av skjermen til 50 %"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Sett størrelsen på den venstre delen av skjermen til 30 %"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Utvid den høyre delen av skjermen til hele skjermen"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Bytt apper"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Utvid den øverste delen av skjermen til hele skjermen"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Sett størrelsen på den øverste delen av skjermen til 70 %"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Sett størrelsen på den øverste delen av skjermen til 50 %"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Gjenopprett"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Fest til venstre"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Fest til høyre"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Endre størrelsen på appvinduet til venstre"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Endre størrelsen på appvinduet til høyre"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimer eller gjenopprett størrelsen på vinduet"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Start modusen for delt skjerm"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Start vindusmodus for skrivebordet"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Endre størrelsen på vinduet til venstre"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Endre størrelsen på vinduet til høyre"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimer eller gjenopprett størrelsen på vinduet"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maksimer eller gjenopprett størrelsen på vinduet"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimer appvinduet"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Innstillinger for åpning som standard"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Velg hvordan nettlinker skal åpnes for denne appen"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"I appen"</string> diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml index bc45b0f45750..f66fb1d30359 100644 --- a/libs/WindowManager/Shell/res/values-ne/strings.xml +++ b/libs/WindowManager/Shell/res/values-ne/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"बायाँ भाग ५०%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"बायाँ भाग ३०%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"दायाँ भाग फुल स्क्रिन"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"एपहरू अदलबदल गर्नुहोस्"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"माथिल्लो भाग फुल स्क्रिन"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"माथिल्लो भाग ७०%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"माथिल्लो भाग ५०%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"रिस्टोर गर्नुहोस्"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"बायाँतिर स्न्याप गर्नुहोस्"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"दायाँतिर स्न्याप गर्नुहोस्"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"एपको विन्डोको आकार बदलेर बायाँतिर लैजानुहोस्"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"एपको विन्डोको आकार बदलेर दायाँतिर लैजानुहोस्"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"विन्डोको आकार म्याक्सिमाइज गर्नुहोस् वा रिस्टोर गर्नुहोस्"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"स्प्लिट स्क्रिन मोड प्रयोग गर्नुहोस्"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"डेस्कटप विन्डोइङ मोड प्रयोग गर्नुहोस्"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"विन्डोको आकार बदलेर बायाँतिर लैजानुहोस्"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"विन्डोको आकार बदलेर दायाँतिर लैजानुहोस्"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"विन्डोको आकार म्याक्सिमाइज गर्नुहोस् वा रिस्टोर गर्नुहोस्"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"विन्डोको आकार म्याक्सिमाइज गर्नुहोस् वा रिस्टोर गर्नुहोस्"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"एपको विन्डो मिनिमाइज गर्नुहोस्"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"डिफल्ट सेटिङअनुसार खोल्नुहोस्"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"यो एपका वेब लिंकहरू खोल्ने तरिका छनौट गर्नुहोस्"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"एपमा"</string> diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml index b16092ec46f9..edb520872d1f 100644 --- a/libs/WindowManager/Shell/res/values-or/strings.xml +++ b/libs/WindowManager/Shell/res/values-or/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ବାମ ପଟକୁ 50% କରନ୍ତୁ"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ବାମ ପଟେ 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ଡାହାଣ ପଟକୁ ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍ କରନ୍ତୁ"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"ଆପ୍ସ ସ୍ୱାପ କରନ୍ତୁ"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ଉପର ଆଡ଼କୁ ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍ କରନ୍ତୁ"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ଉପର ଆଡ଼କୁ 70% କରନ୍ତୁ"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ଉପର ଆଡ଼କୁ 50% କରନ୍ତୁ"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"ରିଷ୍ଟୋର କରନ୍ତୁ"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"ବାମରେ ସ୍ନାପ କରନ୍ତୁ"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"ଡାହାଣରେ ସ୍ନାପ କରନ୍ତୁ"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ଆପ ୱିଣ୍ଡୋ ରିସାଇଜ କରିବା ପାଇଁ ବାମ ବଟନ"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ଆପ ୱିଣ୍ଡୋ ରିସାଇଜ କରିବା ପାଇଁ ଡାହାଣ ବଟନ"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ୱିଣ୍ଡୋ ସାଇଜକୁ ମେକ୍ସିମାଇଜ କିମ୍ବା ରିଷ୍ଟୋର କରନ୍ତୁ"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ମୋଡରେ ପ୍ରବେଶ କରନ୍ତୁ"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ଡେସ୍କଟପ ୱିଣ୍ଡୋଇଂ ମୋଡରେ ପ୍ରବେଶ କରନ୍ତୁ"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ବାମପଟକୁ ୱିଣ୍ଡୋ ରିସାଇଜ କରନ୍ତୁ"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ଡାହାଣପଟକୁ ୱିଣ୍ଡୋ ରିସାଇଜ କରନ୍ତୁ"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ୱିଣ୍ଡୋ ସାଇଜକୁ ମେକ୍ସିମାଇଜ କିମ୍ବା ରିଷ୍ଟୋର କରନ୍ତୁ"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"ୱିଣ୍ଡୋ ସାଇଜକୁ ମେକ୍ସିମାଇଜ କିମ୍ବା ରିଷ୍ଟୋର କରନ୍ତୁ"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"ଆପ ୱିଣ୍ଡୋକୁ ମିନିମାଇଜ କରନ୍ତୁ"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"ଡିଫଲ୍ଟ ସେଟିଂସକୁ ଖୋଲନ୍ତୁ"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ଏହି ଆପ ପାଇଁ ୱେବ ଲିଙ୍କଗୁଡ଼ିକୁ କିପରି ଖୋଲିବେ, ତାହା ବାଛନ୍ତୁ"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ଆପରେ"</string> diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml index d06603fbe206..47ee80e6a4e8 100644 --- a/libs/WindowManager/Shell/res/values-pl/strings.xml +++ b/libs/WindowManager/Shell/res/values-pl/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% lewej części ekranu"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30% lewej części ekranu"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Prawa część ekranu na pełnym ekranie"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Zamień aplikacje"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Górna część ekranu na pełnym ekranie"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70% górnej części ekranu"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% górnej części ekranu"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Przywróć"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Przyciągnij do lewej"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Przyciągnij do prawej"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Zmień rozmiar okna aplikacji po lewej"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Zmień rozmiar okna aplikacji po prawej"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Zmaksymalizuj lub przywróć rozmiar okna"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Włącz tryb podzielonego ekranu"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Włącz tryb okien na pulpicie"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Zmień rozmiar okna do lewej"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Zmień rozmiar okna do prawej"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Zmaksymalizuj lub przywróć rozmiar okna"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Zmaksymalizuj lub przywróć rozmiar okna"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Zminimalizuj okno aplikacji"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Ustawienia domyślnego otwierania"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Wybierz, gdzie chcesz otwierać linki z tej aplikacji"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"W aplikacji"</string> diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml index 3039950e47ee..a3313b6496e0 100644 --- a/libs/WindowManager/Shell/res/values-ro/strings.xml +++ b/libs/WindowManager/Shell/res/values-ro/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Partea stângă: 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Partea stângă: 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Partea dreaptă pe ecran complet"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Comută între aplicații"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Partea de sus pe ecran complet"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Partea de sus: 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Partea de sus: 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restabilește"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Trage la stânga"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Trage la dreapta"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Redimensionează fereastra aplicației la stânga"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Redimensionează fereastra aplicației la dreapta"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximizează sau restabilește dimensiunea ferestrei"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Accesează modul ecran împărțit"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Accesează modul de windowing pe desktop"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionează fereastra la stânga"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionează fereastra la dreapta"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizează sau restabilește dimensiunea ferestrei"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maximizează sau restabilește dimensiunea ferestrei"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimizează fereastra aplicației"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Setări de deschidere în mod prestabilit"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Alege modul de deschidere a linkurilor web pentru aplicație"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"În aplicație"</string> diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml index fe03feb901ed..fcb0aa6559fa 100644 --- a/libs/WindowManager/Shell/res/values-sq/strings.xml +++ b/libs/WindowManager/Shell/res/values-sq/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Majtas 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Majtas 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Ekrani i plotë djathtas"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Ndërro aplikacionet"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Ekrani i plotë lart"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Lart 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Lart 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Restauro"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Zhvendos majtas"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Zhvendos djathtas"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Ndrysho përmasat e dritares së aplikacionit majtas"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Ndrysho përmasat e dritares së aplikacionit djathtas"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimizo ose restauro madhësinë e dritares"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Hyr në modalitetin e ekranit të ndarë"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Hyr në modalitetin e dritareve në desktop"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ndrysho përmasat e dritares në të majtë"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ndrysho përmasat e dritares në të djathtë"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimizo ose restauro madhësinë e dritares"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maksimizo ose restauro madhësinë e dritares"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimizo dritaren e aplikacionit"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Hap sipas cilësimeve të parazgjedhura"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Zgjidh si do t\'i hapësh lidhjet e uebit për këtë aplikacion"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Në aplikacion"</string> diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml index 5163fc69dfb5..6a2ffcdf8e89 100644 --- a/libs/WindowManager/Shell/res/values-sr/strings.xml +++ b/libs/WindowManager/Shell/res/values-sr/strings.xml @@ -125,11 +125,11 @@ <string name="float_button_text" msgid="9221657008391364581">"Плутајуће"</string> <string name="select_text" msgid="5139083974039906583">"Изаберите"</string> <string name="screenshot_text" msgid="1477704010087786671">"Снимак екрана"</string> - <string name="open_in_browser_text" msgid="9181692926376072904">"Отворите у прегледачу"</string> + <string name="open_in_browser_text" msgid="9181692926376072904">"Отвори у прегледачу"</string> <string name="open_in_app_text" msgid="2874590745116268525">"Отворите у апликацији"</string> <string name="new_window_text" msgid="6318648868380652280">"Нови прозор"</string> <string name="manage_windows_text" msgid="5567366688493093920">"Управљајте прозорима"</string> - <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Промените размеру"</string> + <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Промени размеру"</string> <string name="close_text" msgid="4986518933445178928">"Затворите"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Затворите мени"</string> <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Отворите мени"</string> @@ -138,7 +138,7 @@ <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Апликација не може да се премести овде"</string> <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Имерзивне"</string> <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Врати"</string> - <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Увећајте"</string> + <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Увећај"</string> <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Вратите"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Прикачите лево"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Прикачите десно"</string> diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml index 29f4aab0502a..a9df47650dad 100644 --- a/libs/WindowManager/Shell/res/values-sv/strings.xml +++ b/libs/WindowManager/Shell/res/values-sv/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vänster 50 %"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Vänster 30 %"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Helskärm på höger skärm"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Byt appar"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Helskärm på övre skärm"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Övre 70 %"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Övre 50 %"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Återställ"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Fäst till vänster"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Fäst till höger"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Ändra storlek på appfönstret åt vänster"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Ändra storlek på appfönstret åt höger"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximera eller återställ fönsterstorleken"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Starta läget för delad skärm"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Starta datorläget"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ändra storlek på fönstret åt vänster"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ändra storlek på fönstret åt höger"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximera eller återställ fönsterstorleken"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Maximera eller återställ fönsterstorleken"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Minimera appfönstret"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Inställningar för Öppna som standard"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Välj hur webblänkar ska öppnas för den här appen"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"I appen"</string> diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml index 6471e3b723e0..a3c9a0d3989c 100644 --- a/libs/WindowManager/Shell/res/values-sw/strings.xml +++ b/libs/WindowManager/Shell/res/values-sw/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kushoto 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kushoto 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Skrini nzima ya kulia"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Badilisha Programu"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Skrini nzima ya juu"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Juu 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Juu 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Rejesha"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Telezesha kushoto"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Telezesha kulia"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Badilisha ukubwa wa dirisha la programu kushoto"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Badilisha ukubwa wa dirisha la programu kulia"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Panua au urejeshe ukubwa wa dirisha"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Ingia katika hali ya skrini iliyogawanywa"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Ingia katika hali ya madirisha ya kompyuta ya mezani"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Badilisha ukubwa wa dirisha kushoto"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Badilisha ukubwa wa dirisha kulia"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Panua au urejeshe ukubwa wa dirisha"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Panua au urejeshe ukubwa wa dirisha"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Punguza dirisha la programu"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Fungua kwa mipangilio chaguomsingi"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Chagua jinsi ya kufungua viungo vya wavuti vya programu hii"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Kwenye programu"</string> diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml index 03e55c8dcf79..b1b8c7ff2075 100644 --- a/libs/WindowManager/Shell/res/values-ta/strings.xml +++ b/libs/WindowManager/Shell/res/values-ta/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"இடது புறம் 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"இடது புறம் 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"வலது புறம் முழுத் திரை"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"ஆப்ஸை மாற்றும்"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"மேற்புறம் முழுத் திரை"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"மேலே 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"மேலே 50%"</string> @@ -126,7 +125,7 @@ <string name="float_button_text" msgid="9221657008391364581">"மிதக்கும் சாளரம்"</string> <string name="select_text" msgid="5139083974039906583">"தேர்ந்தெடுக்கும்"</string> <string name="screenshot_text" msgid="1477704010087786671">"ஸ்கிரீன்ஷாட்"</string> - <string name="open_in_browser_text" msgid="9181692926376072904">"உலாவியில் திறக்கும்"</string> + <string name="open_in_browser_text" msgid="9181692926376072904">"பிரவுசரில் திற"</string> <string name="open_in_app_text" msgid="2874590745116268525">"ஆப்ஸில் திறக்கும்"</string> <string name="new_window_text" msgid="6318648868380652280">"புதிய சாளரம்"</string> <string name="manage_windows_text" msgid="5567366688493093920">"சாளரங்களை நிர்வகிக்கலாம்"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"மீட்டெடுக்கும்"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"இடதுபுறம் நகர்த்தும்"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"வலதுபுறம் நகர்த்தும்"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ஆப்ஸ் சாளரத்தின் இடதுபுறத்தில் அளவை மாற்றும்"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ஆப்ஸ் சாளரத்தின் வலதுபுறத்தில் அளவை மாற்றும்"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"சாளரத்தின் அளவைப் பெரிதாக்கும்/மீட்டெடுக்கும்"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"திரைப் பிரிப்புப் பயன்முறையில் உள்நுழையும்"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"டெஸ்க்டாப் சாளரப் பயன்முறையில் உள்நுழையும்"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"சாளரத்தை இடதுபுறமாக அளவு மாற்றும்"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"சாளரத்தை வலதுபுறமாக அளவு மாற்றும்"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"சாளரத்தின் அளவைப் பெரிதாக்கும்/மீட்டெடுக்கும்"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"சாளரத்தின் அளவைப் பெரிதாக்கும்/மீட்டெடுக்கும்"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"ஆப்ஸ் சாளரத்தைச் சிறிதாக்கும்"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"இயல்பாக அமைப்புகளைத் திறக்கும்"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"இந்த ஆப்ஸில் வலை இணைப்புகளைத் திறக்கும் வழிமுறையைத் தேர்வுசெய்யுங்கள்"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ஆப்ஸில்"</string> diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml index 8d12e5437c62..6a5d1abebd25 100644 --- a/libs/WindowManager/Shell/res/values-tr/strings.xml +++ b/libs/WindowManager/Shell/res/values-tr/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Solda %50"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Solda %30"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Sağda tam ekran"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Uygulamaların Yerini Değiştir"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Üstte tam ekran"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Üstte %70"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Üstte %50"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Geri yükle"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Sola tuttur"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Sağa tuttur"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Uygulama penceresini sola yeniden boyutlandır"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Uygulama penceresini sağa yeniden boyutlandır"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Pencereyi ekranı kaplayacak şekilde büyüt veya önceki boyutuna döndür"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Bölünmüş ekran moduna gir"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Masaüstü pencereleme moduna gir"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Pencereyi sola yeniden boyutlandır"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Pencereyi sağa yeniden boyutlandır"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Pencereyi ekranı kaplayacak şekilde büyüt veya önceki boyutuna döndür"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Pencereyi ekranı kaplayacak şekilde büyüt veya önceki boyutuna döndür"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Uygulama penceresini küçült"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Varsayılan olarak açma ayarları"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Bu uygulama için web bağlantılarının nasıl açılacağını seçin"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Uygulamada"</string> diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml index 66d8a62f6633..7f4e91d5dfc5 100644 --- a/libs/WindowManager/Shell/res/values-uk/strings.xml +++ b/libs/WindowManager/Shell/res/values-uk/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ліве вікно на 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ліве вікно на 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Праве вікно на весь екран"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Поміняти додатки місцями"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Верхнє вікно на весь екран"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Верхнє вікно на 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Верхнє вікно на 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Відновити"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Закріпити ліворуч"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Закріпити праворуч"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Змінити розмір вікна додатка ліворуч"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Змінити розмір вікна додатка праворуч"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Розгорнути вікно або відновити його розмір"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Увімкнути режим розділення екрана"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Увімкнути режим вікон для комп’ютера"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Змінити розмір вікна ліворуч"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Змінити розмір вікна праворуч"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Розгорнути вікно або відновити його розмір"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Розгорнути вікно або відновити його розмір"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Згорнути вікно додатка"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Налаштування \"Відкривати за умовчанням\""</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Виберіть, як відкривати вебпосилання в цьому додатку"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"У додатку"</string> diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml index 653ba0e66984..f461d4077087 100644 --- a/libs/WindowManager/Shell/res/values-ur/strings.xml +++ b/libs/WindowManager/Shell/res/values-ur/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"بائیں %50"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"بائیں %30"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"دائیں فل اسکرین"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"ایپس سویپ کریں"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"بالائی فل اسکرین"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"اوپر %70"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"اوپر %50"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"بحال کریں"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"دائیں منتقل کریں"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"بائیں منتقل کریں"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"دائیں طرف ایپ ونڈو کا سائز تبدیل کریں"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ایپ ونڈو کا سائز بائیں طرف تبدیل کریں"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ونڈو کا سائز زیادہ سے زیادہ یا بحال کریں"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"سپلٹ اسکرین موڈ میں داخل ہوں"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ڈیسک ٹاپ ونڈو وضع میں داخل ہوں"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"دائیں طرف ونڈو کا سائز تبدیل کریں"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ونڈو کا سائز بائیں طرف تبدیل کریں"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ونڈو کا سائز زیادہ سے زیادہ یا بحال کریں"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"ونڈو کا سائز زیادہ سے زیادہ یا بحال کریں"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"ایپ ونڈو کو چھوٹا کریں"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"بطور ڈیفالٹ ترتیبات کھولیں"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"اس ایپ کے لیے ویب لنکس کھولنے کا طریقہ منتخب کریں"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ایپ میں"</string> diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml index f1b728b1b64c..e7cacc345c2b 100644 --- a/libs/WindowManager/Shell/res/values-vi/strings.xml +++ b/libs/WindowManager/Shell/res/values-vi/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Trái 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Trái 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Toàn màn hình bên phải"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Hoán đổi ứng dụng"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Toàn màn hình phía trên"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Trên 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Trên 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Khôi phục"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Di chuyển nhanh sang trái"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Di chuyển nhanh sang phải"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Đổi kích thước và chuyển cửa sổ ứng dụng sang trái"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Đổi kích thước và chuyển cửa sổ ứng dụng sang phải"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Phóng to hoặc khôi phục kích thước cửa sổ"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Mở chế độ chia đôi màn hình"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Mở chế độ cửa sổ trên máy tính"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Đổi kích thước và chuyển cửa sổ sang trái"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Đổi kích thước và chuyển cửa sổ sang phải"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Phóng to hoặc khôi phục kích thước cửa sổ"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Phóng to hoặc khôi phục kích thước cửa sổ"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Thu nhỏ cửa sổ ứng dụng"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Mở các chế độ cài đặt theo mặc định"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Chọn cách mở đường liên kết trang web cho ứng dụng này"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Trong ứng dụng"</string> diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml index 543780844060..562a0ee09bd6 100644 --- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"左侧 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"左侧 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"右侧全屏"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"交换应用位置"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"顶部全屏"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"顶部 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"顶部 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"恢复"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"贴靠左侧"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"贴靠右侧"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"调整应用窗口大小并贴靠左侧"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"调整应用窗口大小并贴靠右侧"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"将窗口最大化或恢复大小"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"进入分屏模式"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"进入桌面设备窗口化模式"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"调整窗口大小并贴靠左侧"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"调整窗口大小并贴靠右侧"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"将窗口最大化或恢复大小"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"将窗口最大化或恢复大小"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"将应用窗口最小化"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"默认打开设置"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"选择如何打开此应用中的网页链接"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"在此应用内"</string> diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml index 938024d2cd1a..eecd9f21be57 100644 --- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"左邊 50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"左邊 30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"右邊全螢幕"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"切換應用程式"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"頂部全螢幕"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"頂部 70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"頂部 50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"還原"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"貼齊左邊"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"貼齊右邊"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"調整左邊應用程式視窗大小"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"調整右邊應用程式視窗大小"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"將視窗放到最大或者還原視窗大小"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"進入分割螢幕模式"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"進入桌面視窗模式"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"將視窗移去左邊調整大小"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"將視窗移去右邊調整大小"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"將視窗放到最大或者還原視窗大小"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"將視窗放到最大或者還原視窗大小"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"將應用程式視窗縮到最細"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"採用預設設定打開"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"選擇此應用程式開啟網絡連結的方式"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"在應用程式內"</string> diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml index 3a5a87d9868e..c157c193fa14 100644 --- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"以 50% 的螢幕空間顯示左側畫面"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"以 30% 的螢幕空間顯示左側畫面"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"以全螢幕顯示右側畫面"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"切換應用程式"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"以全螢幕顯示頂端畫面"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"以 70% 的螢幕空間顯示頂端畫面"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"以 50% 的螢幕空間顯示頂端畫面"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"還原"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"靠左對齊"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"靠右對齊"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"調整應用程式視窗大小並向左貼齊"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"調整應用程式視窗大小並向右貼齊"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"將視窗最大化或還原大小"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"進入分割畫面模式"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"進入電腦視窗化模式"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"調整應用程式視窗大小並向左貼齊"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"調整應用程式視窗大小並向右貼齊"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"將視窗最大化或還原大小"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"將視窗最大化或還原大小"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"將應用程式視窗最小化"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"開啟連結的預設設定"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"選擇如何開啟這個應用程式的網頁連結"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"使用應用程式"</string> diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml index cba8e048ea3d..a7ba6d21234d 100644 --- a/libs/WindowManager/Shell/res/values-zu/strings.xml +++ b/libs/WindowManager/Shell/res/values-zu/strings.xml @@ -43,8 +43,7 @@ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kwesokunxele ngo-50%"</string> <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kwesokunxele ngo-30%"</string> <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Isikrini esigcwele esingakwesokudla"</string> - <!-- no translation found for accessibility_action_divider_swap (7026003137401725787) --> - <skip /> + <string name="accessibility_action_divider_swap" msgid="7026003137401725787">"Shintsha ama-app"</string> <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Isikrini esigcwele esiphezulu"</string> <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Okuphezulu okungu-70%"</string> <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Okuphezulu okungu-50%"</string> @@ -143,26 +142,16 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Buyisela"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Chofoza kwesobunxele"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Chofoza kwesokudla"</string> - <!-- no translation found for desktop_mode_a11y_action_snap_left (2932955411661734668) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_snap_right (4577032451624261787) --> - <skip /> - <!-- no translation found for desktop_mode_a11y_action_maximize_restore (8026037983417986686) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_split_screen_mode_button_text (7182959681057464802) --> - <skip /> - <!-- no translation found for app_handle_menu_talkback_desktop_mode_button_text (1230110046930843630) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_left_text (500309467459084564) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_snap_right_text (7010831426654467163) --> - <skip /> - <!-- no translation found for maximize_menu_talkback_action_maximize_restore_text (4942610897847934859) --> - <skip /> - <!-- no translation found for maximize_button_talkback_action_maximize_restore_text (4122441323153198455) --> - <skip /> - <!-- no translation found for minimize_button_talkback_action_maximize_restore_text (8890767445425625935) --> - <skip /> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Shintsha usayizi we-app yewindi ngakwesokunxele"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Shintsha usayizi we-app yewindi ngakwesokudla"</string> + <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Khulisa noma buyisela usayizi wewindi"</string> + <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Faka imodi yokuhlukanisa isikrini"</string> + <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Faka imodi yokwenza iwindi yedeskithophu"</string> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Shintsha usayizi wewindi ngakwesokunxele"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Shintsha usayizi wewindi ngakwesokudla"</string> + <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Khulisa noma buyisela usayizi wewindi"</string> + <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Khulisa noma buyisela usayizi wewindi"</string> + <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"Nciphisa iwindi le-app"</string> <string name="open_by_default_settings_text" msgid="2526548548598185500">"Vula amasethingi ngokuzenzakalela"</string> <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Khetha indlela yokuvula amalinki ewebhu ale app"</string> <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Ku-app"</string> diff --git a/libs/WindowManager/Shell/res/values/attrs.xml b/libs/WindowManager/Shell/res/values/attrs.xml index fbb5caa508de..4ba0468a740d 100644 --- a/libs/WindowManager/Shell/res/values/attrs.xml +++ b/libs/WindowManager/Shell/res/values/attrs.xml @@ -23,4 +23,11 @@ <declare-styleable name="MessageState"> <attr name="state_task_focused" format="boolean"/> </declare-styleable> + + <declare-styleable name="HandleMenuActionButton"> + <attr name="android:text" format="string" /> + <attr name="android:textColor" format="color" /> + <attr name="android:src" format="reference" /> + <attr name="android:drawableTint" format="color" /> + </declare-styleable> </resources> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index e23d5725e9c3..e395341a5792 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -447,6 +447,17 @@ 80 dp for handle + 20 dp for room to grow on the sides when hovered. --> <dimen name="desktop_mode_fullscreen_decor_caption_width">100dp</dimen> + <!-- Horizontal padding for desktop mode caption in default unhovered untouched state. --> + <dimen name="desktop_mode_fullscreen_decor_caption_horizontal_padding_default">10dp</dimen> + + <!-- Horizontal padding for desktop mode caption when hovered. + 1/2 * (100 dp of total width - 80 dp for handle * 1.2 scaling factor). --> + <dimen name="desktop_mode_fullscreen_decor_caption_horizontal_padding_hovered">2dp</dimen> + + <!-- Horizontal padding for desktop mode caption when touched. + 1/2 * (100 dp of total width - 80 dp for handle * 0.85 scaling factor). --> + <dimen name="desktop_mode_fullscreen_decor_caption_horizontal_padding_touched">16dp</dimen> + <!-- Required empty space to be visible for partially offscreen tasks. --> <dimen name="freeform_required_visible_empty_space_in_header">48dp</dimen> @@ -570,7 +581,7 @@ <dimen name="desktop_mode_handle_menu_corner_radius">26dp</dimen> <!-- The radius of the caption menu icon. --> - <dimen name="desktop_mode_caption_icon_radius">24dp</dimen> + <dimen name="desktop_mode_caption_icon_radius">32dp</dimen> <!-- The radius of the caption menu shadow. --> <dimen name="desktop_mode_handle_menu_shadow_radius">2dp</dimen> diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml index 035004bfd322..637b47ab3ace 100644 --- a/libs/WindowManager/Shell/res/values/styles.xml +++ b/libs/WindowManager/Shell/res/values/styles.xml @@ -40,13 +40,11 @@ <item name="android:activityCloseExitAnimation">@anim/forced_resizable_exit</item> </style> - <style name="DesktopModeHandleMenuActionButtonLayout"> + <style name="DesktopModeHandleMenuActionButton"> <item name="android:layout_width">match_parent</item> <item name="android:layout_height">52dp</item> - <item name="android:layout_weight">1</item> - <item name="android:gravity">start|center_vertical</item> - <item name="android:paddingHorizontal">16dp</item> - <item name="android:background">?android:selectableItemBackground</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> + <item name="android:drawableTint">@androidprv:color/materialColorOnSurface</item> </style> <style name="DesktopModeHandleMenuActionButtonImage"> @@ -71,7 +69,6 @@ <style name="DesktopModeHandleMenuWindowingButton"> <item name="android:layout_width">48dp</item> <item name="android:layout_height">48dp</item> - <item name="android:padding">14dp</item> <item name="android:scaleType">fitCenter</item> <item name="android:background">?android:selectableItemBackgroundBorderless</item> </style> diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleBarLocation.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleBarLocation.kt index 481fc7fcb869..6acd9dbe8b91 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleBarLocation.kt +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/BubbleBarLocation.kt @@ -70,7 +70,8 @@ enum class BubbleBarLocation : Parcelable { UpdateSource.A11Y_ACTION_BAR, UpdateSource.A11Y_ACTION_BUBBLE, UpdateSource.A11Y_ACTION_EXP_VIEW, - UpdateSource.APP_ICON_DRAG + UpdateSource.APP_ICON_DRAG, + UpdateSource.DRAG_TASK, ) @Retention(AnnotationRetention.SOURCE) annotation class UpdateSource { @@ -95,6 +96,9 @@ enum class BubbleBarLocation : Parcelable { /** Location changed from dragging the application icon to the bubble bar */ const val APP_ICON_DRAG = 7 + + /** Location changed from dragging a running task to the bubble bar */ + const val DRAG_TASK = 8 } } } diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicy.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicy.kt index c545d3001cc7..126ab3d74689 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicy.kt +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicy.kt @@ -50,7 +50,7 @@ class DesktopModeCompatPolicy(private val context: Context) { numActivities: Int, isTopActivityNoDisplay: Boolean, isActivityStackTransparent: Boolean) = DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODALS_POLICY.isTrue && ((isSystemUiTask(packageName) - || isPartOfDefaultHomePackage(packageName) + || isPartOfDefaultHomePackageOrNoHomeAvailable(packageName) || isTransparentTask(isActivityStackTransparent, numActivities)) && !isTopActivityNoDisplay) @@ -85,10 +85,11 @@ class DesktopModeCompatPolicy(private val context: Context) { private fun isSystemUiTask(packageName: String?) = packageName == systemUiPackage /** - * Returns true if the tasks base activity is part of the default home package. + * Returns true if the tasks base activity is part of the default home package, or there is + * currently no default home package available. */ - private fun isPartOfDefaultHomePackage(packageName: String?) = - packageName != null && packageName == defaultHomePackage + private fun isPartOfDefaultHomePackageOrNoHomeAvailable(packageName: String?) = + defaultHomePackage == null || (packageName != null && packageName == defaultHomePackage) private fun isAnyForceConsumptionFlagsEnabled(): Boolean = DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS.isTrue diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java index 643c1506e4c2..00901a4d980d 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java @@ -226,6 +226,7 @@ public class DesktopModeStatus { return context.getResources().getBoolean(R.bool.config_canInternalDisplayHostDesktops); } + /** * Return {@code true} if desktop mode dev option should be shown on current device */ @@ -239,23 +240,22 @@ public class DesktopModeStatus { */ public static boolean canShowDesktopExperienceDevOption(@NonNull Context context) { return Flags.showDesktopExperienceDevOption() - && isInternalDisplayEligibleToHostDesktops(context); + && isDeviceEligibleForDesktopMode(context); } /** Returns if desktop mode dev option should be enabled if there is no user override. */ public static boolean shouldDevOptionBeEnabledByDefault(Context context) { - return isInternalDisplayEligibleToHostDesktops(context) - && Flags.enableDesktopWindowingMode(); + return isDeviceEligibleForDesktopMode(context) + && Flags.enableDesktopWindowingMode(); } /** * Return {@code true} if desktop mode is enabled and can be entered on the current device. */ public static boolean canEnterDesktopMode(@NonNull Context context) { - return (isInternalDisplayEligibleToHostDesktops(context) - && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE.isTrue() - && (isDesktopModeSupported(context) || !enforceDeviceRestrictions()) - || isDesktopModeEnabledByDevOption(context)); + return (isDeviceEligibleForDesktopMode(context) + && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE.isTrue()) + || isDesktopModeEnabledByDevOption(context); } /** @@ -323,25 +323,34 @@ public class DesktopModeStatus { } /** - * Return {@code true} if desktop sessions is unrestricted and can be host for the device's - * internal display. + * Return {@code true} if desktop mode is unrestricted and is supported on the device. */ - public static boolean isInternalDisplayEligibleToHostDesktops(@NonNull Context context) { - return !enforceDeviceRestrictions() || canInternalDisplayHostDesktops(context) || ( - Flags.enableDesktopModeThroughDevOption() && isDesktopModeDevOptionSupported( - context)); + public static boolean isDeviceEligibleForDesktopMode(@NonNull Context context) { + if (!enforceDeviceRestrictions()) { + return true; + } + final boolean desktopModeSupported = isDesktopModeSupported(context) + && canInternalDisplayHostDesktops(context); + final boolean desktopModeSupportedByDevOptions = + Flags.enableDesktopModeThroughDevOption() + && isDesktopModeDevOptionSupported(context); + return desktopModeSupported || desktopModeSupportedByDevOptions; } /** * Return {@code true} if the developer option for desktop mode is unrestricted and is supported * in the device. * - * Note that, if {@link #isInternalDisplayEligibleToHostDesktops(Context)} is true, then + * Note that, if {@link #isDeviceEligibleForDesktopMode(Context)} is true, then * {@link #isDeviceEligibleForDesktopModeDevOption(Context)} is also true. */ private static boolean isDeviceEligibleForDesktopModeDevOption(@NonNull Context context) { - return !enforceDeviceRestrictions() || isDesktopModeSupported(context) - || isDesktopModeDevOptionSupported(context); + if (!enforceDeviceRestrictions()) { + return true; + } + final boolean desktopModeSupported = isDesktopModeSupported(context) + && canInternalDisplayHostDesktops(context); + return desktopModeSupported || isDesktopModeDevOptionSupported(context); } /** 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 c7a0401c2b88..e44c8951df68 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 @@ -22,6 +22,7 @@ import static android.service.notification.NotificationListenerService.REASON_CA import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; +import static android.view.WindowManager.TRANSIT_CHANGE; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; @@ -844,6 +845,10 @@ public class BubbleController implements ConfigurationChangeListener, mLogger.log(onLeft ? BubbleLogger.Event.BUBBLE_BAR_MOVED_LEFT_APP_ICON_DROP : BubbleLogger.Event.BUBBLE_BAR_MOVED_RIGHT_APP_ICON_DROP); break; + case BubbleBarLocation.UpdateSource.DRAG_TASK: + mLogger.log(onLeft ? BubbleLogger.Event.BUBBLE_BAR_MOVED_LEFT_DRAG_TASK + : BubbleLogger.Event.BUBBLE_BAR_MOVED_RIGHT_DRAG_TASK); + break; } } @@ -1590,20 +1595,34 @@ public class BubbleController implements ConfigurationChangeListener, * Expands and selects a bubble created from a running task in a different mode. * * @param taskInfo the task. + * @param dragData optional information about the task when it is being dragged into a bubble */ - public void expandStackAndSelectBubble(ActivityManager.RunningTaskInfo taskInfo) { + public void expandStackAndSelectBubble(ActivityManager.RunningTaskInfo taskInfo, + @Nullable BubbleTransitions.DragData dragData) { if (!BubbleAnythingFlagHelper.enableBubbleToFullscreen()) return; Bubble b = mBubbleData.getOrCreateBubble(taskInfo); // Removes from overflow ProtoLog.v(WM_SHELL_BUBBLES, "expandStackAndSelectBubble - intent=%s", taskInfo.taskId); + BubbleBarLocation location = null; + if (dragData != null) { + location = + dragData.isReleasedOnLeft() ? BubbleBarLocation.LEFT : BubbleBarLocation.RIGHT; + } if (b.isInflated()) { - mBubbleData.setSelectedBubbleAndExpandStack(b); + mBubbleData.setSelectedBubbleAndExpandStack(b, location); + if (dragData != null && dragData.getPendingWct() != null) { + mTransitions.startTransition(TRANSIT_CHANGE, + dragData.getPendingWct(), /* handler= */ null); + } } else { + if (location != null) { + setBubbleBarLocation(location, BubbleBarLocation.UpdateSource.DRAG_TASK); + } b.enable(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE); // Lazy init stack view when a bubble is created ensureBubbleViewsAndWindowCreated(); mBubbleTransitions.startConvertToBubble(b, taskInfo, mExpandedViewManager, mBubbleTaskViewFactory, mBubblePositioner, mStackView, mLayerView, - mBubbleIconFactory, mInflateSynchronously); + mBubbleIconFactory, dragData, mInflateSynchronously); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java index 831f2271d500..a0c473173bf1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java @@ -156,6 +156,12 @@ public class BubbleLogger { @UiEvent(doc = "while bubble bar is expanded, switch to another/existing bubble") BUBBLE_BAR_BUBBLE_SWITCHED(1977), + @UiEvent(doc = "bubble bar moved to the left edge of the screen by dragging a task") + BUBBLE_BAR_MOVED_LEFT_DRAG_TASK(2146), + + @UiEvent(doc = "bubble bar moved to the right edge of the screen by dragging a task") + BUBBLE_BAR_MOVED_RIGHT_DRAG_TASK(2147), + // endregion ; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java deleted file mode 100644 index e47ac61a53dd..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * 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.bubbles; - -import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS; -import static android.app.ActivityTaskManager.INVALID_TASK_ID; -import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; -import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; - -import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES; - -import android.app.ActivityOptions; -import android.app.ActivityTaskManager; -import android.app.PendingIntent; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.graphics.Rect; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.Nullable; - -import com.android.internal.protolog.ProtoLog; -import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper; -import com.android.wm.shell.taskview.TaskView; - -/** - * Handles creating and updating the {@link TaskView} associated with a {@link Bubble}. - */ -public class BubbleTaskViewHelper { - - private static final String TAG = BubbleTaskViewHelper.class.getSimpleName(); - - /** - * Listener for users of {@link BubbleTaskViewHelper} to use to be notified of events - * on the task. - */ - public interface Listener { - - /** Called when the task is first created. */ - void onTaskCreated(); - - /** Called when the visibility of the task changes. */ - void onContentVisibilityChanged(boolean visible); - - /** Called when back is pressed on the task root. */ - void onBackPressed(); - - /** Called when task removal has started. */ - void onTaskRemovalStarted(); - } - - private final Context mContext; - private final BubbleExpandedViewManager mExpandedViewManager; - private final BubbleTaskViewHelper.Listener mListener; - private final View mParentView; - - @Nullable - private Bubble mBubble; - @Nullable - private PendingIntent mPendingIntent; - @Nullable - private TaskView mTaskView; - private int mTaskId = INVALID_TASK_ID; - - private final TaskView.Listener mTaskViewListener = new TaskView.Listener() { - private boolean mInitialized = false; - private boolean mDestroyed = false; - - @Override - public void onInitialized() { - ProtoLog.d(WM_SHELL_BUBBLES, "onInitialized: destroyed=%b initialized=%b bubble=%s", - mDestroyed, mInitialized, getBubbleKey()); - - if (mDestroyed || mInitialized) { - return; - } - - // Custom options so there is no activity transition animation - ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, - 0 /* enterResId */, 0 /* exitResId */); - - Rect launchBounds = new Rect(); - mTaskView.getBoundsOnScreen(launchBounds); - - // TODO: I notice inconsistencies in lifecycle - // Post to keep the lifecycle normal - // TODO - currently based on type, really it's what the "launch item" is. - mParentView.post(() -> { - ProtoLog.d(WM_SHELL_BUBBLES, "onInitialized: calling startActivity, bubble=%s", - getBubbleKey()); - try { - options.setTaskAlwaysOnTop(true); - options.setPendingIntentBackgroundActivityStartMode( - MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS); - final boolean isShortcutBubble = (mBubble.hasMetadataShortcutId() - || (mBubble.isShortcut() - && BubbleAnythingFlagHelper.enableCreateAnyBubble())); - if (mBubble.getPreparingTransition() != null) { - mBubble.getPreparingTransition().surfaceCreated(); - } else if (mBubble.isApp() || mBubble.isNote()) { - Context context = - mContext.createContextAsUser( - mBubble.getUser(), Context.CONTEXT_RESTRICTED); - Intent fillInIntent = null; - //first try get pending intent from the bubble - PendingIntent pi = mBubble.getPendingIntent(); - if (pi == null) { - // if null - create new one - pi = PendingIntent.getActivity( - context, - /* requestCode= */ 0, - mBubble.getIntent() - .addFlags(FLAG_ACTIVITY_MULTIPLE_TASK), - PendingIntent.FLAG_IMMUTABLE - | PendingIntent.FLAG_UPDATE_CURRENT, - /* options= */ null); - } else { - fillInIntent = new Intent(pi.getIntent()); - fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); - } - mTaskView.startActivity(pi, fillInIntent, options, launchBounds); - } else if (isShortcutBubble) { - options.setLaunchedFromBubble(true); - options.setApplyActivityFlagsForBubbles(true); - mTaskView.startShortcutActivity(mBubble.getShortcutInfo(), - options, launchBounds); - } else { - options.setLaunchedFromBubble(true); - if (mBubble != null) { - mBubble.setPendingIntentActive(); - } - final Intent fillInIntent = new Intent(); - // Apply flags to make behaviour match documentLaunchMode=always. - fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT); - fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); - mTaskView.startActivity(mPendingIntent, fillInIntent, options, - launchBounds); - } - } catch (RuntimeException e) { - // If there's a runtime exception here then there's something - // wrong with the intent, we can't really recover / try to populate - // the bubble again so we'll just remove it. - Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey() - + ", " + e.getMessage() + "; removing bubble"); - mExpandedViewManager.removeBubble( - getBubbleKey(), Bubbles.DISMISS_INVALID_INTENT); - } - mInitialized = true; - }); - } - - @Override - public void onReleased() { - mDestroyed = true; - } - - @Override - public void onTaskCreated(int taskId, ComponentName name) { - ProtoLog.d(WM_SHELL_BUBBLES, "onTaskCreated: taskId=%d bubble=%s", - taskId, getBubbleKey()); - // The taskId is saved to use for removeTask, preventing appearance in recent tasks. - mTaskId = taskId; - - if (mBubble != null && mBubble.isNote()) { - // Let the controller know sooner what the taskId is. - mExpandedViewManager.setNoteBubbleTaskId(mBubble.getKey(), mTaskId); - } - - // With the task org, the taskAppeared callback will only happen once the task has - // already drawn - mListener.onTaskCreated(); - } - - @Override - public void onTaskVisibilityChanged(int taskId, boolean visible) { - mListener.onContentVisibilityChanged(visible); - } - - @Override - public void onTaskRemovalStarted(int taskId) { - ProtoLog.d(WM_SHELL_BUBBLES, "onTaskRemovalStarted: taskId=%d bubble=%s", - taskId, getBubbleKey()); - if (mBubble != null) { - mExpandedViewManager.removeBubble(mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED); - } - if (mTaskView != null) { - mTaskView.release(); - ((ViewGroup) mParentView).removeView(mTaskView); - mTaskView = null; - } - mListener.onTaskRemovalStarted(); - } - - @Override - public void onBackPressedOnTaskRoot(int taskId) { - if (mTaskId == taskId && mExpandedViewManager.isStackExpanded()) { - mListener.onBackPressed(); - } - } - }; - - public BubbleTaskViewHelper(Context context, - BubbleExpandedViewManager expandedViewManager, - BubbleTaskViewHelper.Listener listener, - BubbleTaskView bubbleTaskView, - View parent) { - mContext = context; - mExpandedViewManager = expandedViewManager; - mListener = listener; - mParentView = parent; - mTaskView = bubbleTaskView.getTaskView(); - bubbleTaskView.setDelegateListener(mTaskViewListener); - if (bubbleTaskView.isCreated()) { - mTaskId = bubbleTaskView.getTaskId(); - mListener.onTaskCreated(); - } - } - - /** - * Sets the bubble or updates the bubble used to populate the view. - * - * @return true if the bubble is new, false if it was an update to the same bubble. - */ - public boolean update(Bubble bubble) { - boolean isNew = mBubble == null || didBackingContentChange(bubble); - mBubble = bubble; - if (isNew) { - mPendingIntent = mBubble.getPendingIntent(); - return true; - } - return false; - } - - /** Returns the bubble key associated with this view. */ - @Nullable - public String getBubbleKey() { - return mBubble != null ? mBubble.getKey() : null; - } - - /** Returns the TaskView associated with this view. */ - @Nullable - public TaskView getTaskView() { - return mTaskView; - } - - /** - * Returns the task id associated with the task in this view. If the task doesn't exist then - * {@link ActivityTaskManager#INVALID_TASK_ID}. - */ - public int getTaskId() { - return mTaskId; - } - - /** Returns whether the bubble set on the helper is valid to populate the task view. */ - public boolean isValidBubble() { - return mBubble != null && (mPendingIntent != null || mBubble.hasMetadataShortcutId()); - } - - // TODO (b/274980695): Is this still relevant? - /** - * Bubbles are backed by a pending intent or a shortcut, once the activity is - * started we never change it / restart it on notification updates -- unless the bubble's - * backing data switches. - * - * This indicates if the new bubble is backed by a different data source than what was - * previously shown here (e.g. previously a pending intent & now a shortcut). - * - * @param newBubble the bubble this view is being updated with. - * @return true if the backing content has changed. - */ - private boolean didBackingContentChange(Bubble newBubble) { - boolean prevWasIntentBased = mBubble != null && mPendingIntent != null; - boolean newIsIntentBased = newBubble.getPendingIntent() != null; - return prevWasIntentBased != newIsIntentBased; - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewListener.java new file mode 100644 index 000000000000..a38debb702dc --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewListener.java @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2025 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.bubbles; + +import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS; +import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; +import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; + +import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES; + +import android.app.ActivityOptions; +import android.app.ActivityTaskManager; +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.graphics.Rect; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.Nullable; + +import com.android.internal.protolog.ProtoLog; +import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper; +import com.android.wm.shell.taskview.TaskView; + +/** + * A listener that works with task views for bubbles, manages launching the appropriate + * content into the task view from the bubble and sends updates of task view events back to + * the parent view via {@link BubbleTaskViewListener.Callback}. + */ +public class BubbleTaskViewListener implements TaskView.Listener { + private static final String TAG = BubbleTaskViewListener.class.getSimpleName(); + + /** + * Callback to let the view parent of TaskView to be notified of different events. + */ + public interface Callback { + + /** Called when the task is first created. */ + void onTaskCreated(); + + /** Called when the visibility of the task changes. */ + void onContentVisibilityChanged(boolean visible); + + /** Called when back is pressed on the task root. */ + void onBackPressed(); + + /** Called when task removal has started. */ + void onTaskRemovalStarted(); + } + + private final Context mContext; + private final BubbleExpandedViewManager mExpandedViewManager; + private final BubbleTaskViewListener.Callback mCallback; + private final View mParentView; + + private Bubble mBubble; + @Nullable + private PendingIntent mPendingIntent; + private int mTaskId = INVALID_TASK_ID; + private TaskView mTaskView; + + private boolean mInitialized = false; + private boolean mDestroyed = false; + + public BubbleTaskViewListener(Context context, BubbleTaskView bubbleTaskView, View parentView, + BubbleExpandedViewManager manager, BubbleTaskViewListener.Callback callback) { + mContext = context; + mTaskView = bubbleTaskView.getTaskView(); + mParentView = parentView; + mExpandedViewManager = manager; + mCallback = callback; + bubbleTaskView.setDelegateListener(this); + if (bubbleTaskView.isCreated()) { + mTaskId = bubbleTaskView.getTaskId(); + callback.onTaskCreated(); + } + } + + @Override + public void onInitialized() { + ProtoLog.d(WM_SHELL_BUBBLES, "onInitialized: destroyed=%b initialized=%b bubble=%s", + mDestroyed, mInitialized, getBubbleKey()); + + if (mDestroyed || mInitialized) { + return; + } + + // Custom options so there is no activity transition animation + ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, + 0 /* enterResId */, 0 /* exitResId */); + + Rect launchBounds = new Rect(); + mTaskView.getBoundsOnScreen(launchBounds); + + // TODO: I notice inconsistencies in lifecycle + // Post to keep the lifecycle normal + // TODO - currently based on type, really it's what the "launch item" is. + mParentView.post(() -> { + ProtoLog.d(WM_SHELL_BUBBLES, "onInitialized: calling startActivity, bubble=%s", + getBubbleKey()); + try { + options.setTaskAlwaysOnTop(true); + options.setPendingIntentBackgroundActivityStartMode( + MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS); + final boolean isShortcutBubble = (mBubble.hasMetadataShortcutId() + || (mBubble.isShortcut() + && BubbleAnythingFlagHelper.enableCreateAnyBubble())); + if (mBubble.getPreparingTransition() != null) { + mBubble.getPreparingTransition().surfaceCreated(); + } else if (mBubble.isApp() || mBubble.isNote()) { + Context context = + mContext.createContextAsUser( + mBubble.getUser(), Context.CONTEXT_RESTRICTED); + Intent fillInIntent = null; + // First try get pending intent from the bubble + PendingIntent pi = mBubble.getPendingIntent(); + if (pi == null) { + // If null - create new one + pi = PendingIntent.getActivity( + context, + /* requestCode= */ 0, + mBubble.getIntent() + .addFlags(FLAG_ACTIVITY_MULTIPLE_TASK), + PendingIntent.FLAG_IMMUTABLE + | PendingIntent.FLAG_UPDATE_CURRENT, + /* options= */ null); + } else { + fillInIntent = new Intent(pi.getIntent()); + fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); + } + mTaskView.startActivity(pi, fillInIntent, options, launchBounds); + } else if (isShortcutBubble) { + options.setLaunchedFromBubble(true); + options.setApplyActivityFlagsForBubbles(true); + mTaskView.startShortcutActivity(mBubble.getShortcutInfo(), + options, launchBounds); + } else { + options.setLaunchedFromBubble(true); + if (mBubble != null) { + mBubble.setPendingIntentActive(); + } + final Intent fillInIntent = new Intent(); + // Apply flags to make behaviour match documentLaunchMode=always. + fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT); + fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); + mTaskView.startActivity(mPendingIntent, fillInIntent, options, + launchBounds); + } + } catch (RuntimeException e) { + // If there's a runtime exception here then there's something + // wrong with the intent, we can't really recover / try to populate + // the bubble again so we'll just remove it. + Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey() + + ", " + e.getMessage() + "; removing bubble"); + mExpandedViewManager.removeBubble( + getBubbleKey(), Bubbles.DISMISS_INVALID_INTENT); + } + mInitialized = true; + }); + } + + @Override + public void onReleased() { + mDestroyed = true; + } + + @Override + public void onTaskCreated(int taskId, ComponentName name) { + ProtoLog.d(WM_SHELL_BUBBLES, "onTaskCreated: taskId=%d bubble=%s", + taskId, getBubbleKey()); + // The taskId is saved to use for removeTask, preventing appearance in recent tasks. + mTaskId = taskId; + + if (mBubble != null && mBubble.isNote()) { + // Let the controller know sooner what the taskId is. + mExpandedViewManager.setNoteBubbleTaskId(mBubble.getKey(), mTaskId); + } + + // With the task org, the taskAppeared callback will only happen once the task has + // already drawn + mCallback.onTaskCreated(); + } + + @Override + public void onTaskVisibilityChanged(int taskId, boolean visible) { + mCallback.onContentVisibilityChanged(visible); + } + + @Override + public void onTaskRemovalStarted(int taskId) { + ProtoLog.d(WM_SHELL_BUBBLES, "onTaskRemovalStarted: taskId=%d bubble=%s", + taskId, getBubbleKey()); + if (mBubble != null) { + mExpandedViewManager.removeBubble(mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED); + } + if (mTaskView != null) { + mTaskView.release(); + ((ViewGroup) mParentView).removeView(mTaskView); + mTaskView = null; + } + mCallback.onTaskRemovalStarted(); + } + + @Override + public void onBackPressedOnTaskRoot(int taskId) { + if (mTaskId == taskId && mExpandedViewManager.isStackExpanded()) { + mCallback.onBackPressed(); + } + } + + /** + * Sets the bubble or updates the bubble used to populate the view. + * + * @return true if the bubble is new or if the launch content of the bubble changed from the + * previous bubble. + */ + public boolean setBubble(Bubble bubble) { + boolean isNew = mBubble == null || didBackingContentChange(bubble); + mBubble = bubble; + if (isNew) { + mPendingIntent = mBubble.getPendingIntent(); + } + return isNew; + } + + /** Returns the TaskView associated with this view. */ + @Nullable + public TaskView getTaskView() { + return mTaskView; + } + + /** + * Returns the task id associated with the task in this view. If the task doesn't exist then + * {@link ActivityTaskManager#INVALID_TASK_ID}. + */ + public int getTaskId() { + return mTaskId; + } + + private String getBubbleKey() { + return mBubble != null ? mBubble.getKey() : ""; + } + + // TODO (b/274980695): Is this still relevant? + /** + * Bubbles are backed by a pending intent or a shortcut, once the activity is + * started we never change it / restart it on notification updates -- unless the bubble's + * backing data switches. + * + * This indicates if the new bubble is backed by a different data source than what was + * previously shown here (e.g. previously a pending intent & now a shortcut). + * + * @param newBubble the bubble this view is being updated with. + * @return true if the backing content has changed. + */ + private boolean didBackingContentChange(Bubble newBubble) { + boolean prevWasIntentBased = mBubble != null && mPendingIntent != null; + boolean newIsIntentBased = newBubble.getPendingIntent() != null; + return prevWasIntentBased != newIsIntentBased; + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java index df8b4fd12540..a676f41baafe 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java @@ -22,6 +22,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.View.INVISIBLE; import static android.view.WindowManager.TRANSIT_CHANGE; +import static com.android.wm.shell.transition.Transitions.TRANSIT_CONVERT_TO_BUBBLE; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; @@ -92,10 +94,10 @@ public class BubbleTransitions { BubbleExpandedViewManager expandedViewManager, BubbleTaskViewFactory factory, BubblePositioner positioner, BubbleStackView stackView, BubbleBarLayerView layerView, BubbleIconFactory iconFactory, - boolean inflateSync) { + DragData dragData, boolean inflateSync) { return new ConvertToBubble(bubble, taskInfo, mContext, expandedViewManager, factory, positioner, stackView, layerView, iconFactory, - inflateSync); + dragData, inflateSync); } /** @@ -149,43 +151,92 @@ public class BubbleTransitions { } /** + * Information about the task when it is being dragged to a bubble + */ + public static class DragData { + private final Rect mBounds; + private final WindowContainerTransaction mPendingWct; + private final boolean mReleasedOnLeft; + + /** + * @param bounds bounds of the dragged task when the drag was released + * @param wct pending operations to be applied when finishing the drag + * @param releasedOnLeft true if the bubble was released in the left drop target + */ + public DragData(@Nullable Rect bounds, @Nullable WindowContainerTransaction wct, + boolean releasedOnLeft) { + mBounds = bounds; + mPendingWct = wct; + mReleasedOnLeft = releasedOnLeft; + } + + /** + * @return bounds of the dragged task when the drag was released + */ + @Nullable + public Rect getBounds() { + return mBounds; + } + + /** + * @return pending operations to be applied when finishing the drag + */ + @Nullable + public WindowContainerTransaction getPendingWct() { + return mPendingWct; + } + + /** + * @return true if the bubble was released in the left drop target + */ + public boolean isReleasedOnLeft() { + return mReleasedOnLeft; + } + } + + /** * BubbleTransition that coordinates the process of a non-bubble task becoming a bubble. The * steps are as follows: * * 1. Start inflating the bubble view * 2. Once inflated (but not-yet visible), tell WM to do the shell-transition. - * 3. Transition becomes ready, so notify Launcher - * 4. Launcher responds with showExpandedView which calls continueExpand() to make view visible - * 5. Surface is created which kicks off actual animation + * 3. When the transition becomes ready, notify Launcher in parallel + * 4. Wait for surface to be created + * 5. Once surface is ready, animate the task to a bubble * - * So, constructor -> onInflated -> startAnimation -> continueExpand -> surfaceCreated. + * While the animation is pending, we keep a reference to the pending transition in the bubble. + * This allows us to check in other parts of the code that this bubble will be shown via the + * transition animation. * - * continueExpand and surfaceCreated are set-up to happen in either order, though, to support - * UX/timing adjustments. + * startAnimation, continueExpand and surfaceCreated are set-up to happen in either order, + * to support UX/timing adjustments. */ @VisibleForTesting class ConvertToBubble implements Transitions.TransitionHandler, BubbleTransition { final BubbleBarLayerView mLayerView; Bubble mBubble; + @Nullable DragData mDragData; IBinder mTransition; Transitions.TransitionFinishCallback mFinishCb; WindowContainerTransaction mFinishWct = null; final Rect mStartBounds = new Rect(); SurfaceControl mSnapshot = null; TaskInfo mTaskInfo; - boolean mFinishedExpand = false; BubbleViewProvider mPriorBubble = null; + private final TransitionProgress mTransitionProgress = new TransitionProgress(); private SurfaceControl.Transaction mFinishT; private SurfaceControl mTaskLeash; ConvertToBubble(Bubble bubble, TaskInfo taskInfo, Context context, BubbleExpandedViewManager expandedViewManager, BubbleTaskViewFactory factory, BubblePositioner positioner, BubbleStackView stackView, - BubbleBarLayerView layerView, BubbleIconFactory iconFactory, boolean inflateSync) { + BubbleBarLayerView layerView, BubbleIconFactory iconFactory, + @Nullable DragData dragData, boolean inflateSync) { mBubble = bubble; mTaskInfo = taskInfo; mLayerView = layerView; + mDragData = dragData; mBubble.setInflateSynchronously(inflateSync); mBubble.setPreparingTransition(this); mBubble.inflate( @@ -208,6 +259,9 @@ public class BubbleTransitions { final Rect launchBounds = new Rect(); mLayerView.getExpandedViewRestBounds(launchBounds); WindowContainerTransaction wct = new WindowContainerTransaction(); + if (mDragData != null && mDragData.getPendingWct() != null) { + wct.merge(mDragData.getPendingWct(), true); + } if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) { if (mTaskInfo.getParentTaskId() != INVALID_TASK_ID) { wct.reparent(mTaskInfo.token, null, true); @@ -226,7 +280,7 @@ public class BubbleTransitions { state.mVisible = true; } mTaskViewTransitions.enqueueExternal(tv.getController(), () -> { - mTransition = mTransitions.startTransition(TRANSIT_CHANGE, wct, this); + mTransition = mTransitions.startTransition(TRANSIT_CONVERT_TO_BUBBLE, wct, this); return mTransition; }); } @@ -292,6 +346,11 @@ public class BubbleTransitions { } mFinishCb = finishCallback; + if (mDragData != null && mDragData.getBounds() != null) { + // Override start bounds with the dragged task bounds + mStartBounds.set(mDragData.getBounds()); + } + // Now update state (and talk to launcher) in parallel with snapshot stuff mBubbleData.notificationEntryUpdated(mBubble, /* suppressFlyout= */ true, /* showInShade= */ false); @@ -303,15 +362,22 @@ public class BubbleTransitions { mStartBounds.left - info.getRoot(0).getOffset().x, mStartBounds.top - info.getRoot(0).getOffset().y); startTransaction.setLayer(mSnapshot, Integer.MAX_VALUE); + + BubbleBarExpandedView bbev = mBubble.getBubbleBarExpandedView(); + if (bbev != null) { + // Corners get reset during the animation. Add them back + startTransaction.setCornerRadius(mSnapshot, bbev.getRestingCornerRadius()); + } + startTransaction.apply(); mTaskViewTransitions.onExternalDone(transition); + mTransitionProgress.setTransitionReady(); + startExpandAnim(); return true; } - @Override - public void continueExpand() { - mFinishedExpand = true; + private void startExpandAnim() { final boolean animate = mLayerView.canExpandView(mBubble); if (animate) { mPriorBubble = mLayerView.prepareConvertedView(mBubble); @@ -322,19 +388,25 @@ public class BubbleTransitions { mLayerView.removeView(priorView); mPriorBubble = null; } - if (!animate || mBubble.getTaskView().getSurfaceControl() != null) { + if (!animate || mTransitionProgress.isReadyToAnimate()) { playAnimation(animate); } } @Override + public void continueExpand() { + mTransitionProgress.setReadyToExpand(); + } + + @Override public void surfaceCreated() { + mTransitionProgress.setSurfaceReady(); mMainExecutor.execute(() -> { final TaskViewTaskController tvc = mBubble.getTaskView().getController(); final TaskViewRepository.TaskViewState state = mRepository.byTaskView(tvc); if (state == null) return; state.mVisible = true; - if (mFinishedExpand) { + if (mTransitionProgress.isReadyToAnimate()) { playAnimation(true /* animate */); } }); @@ -350,9 +422,6 @@ public class BubbleTransitions { mFinishWct = null; } - // Preparation is complete. - mBubble.setPreparingTransition(null); - if (animate) { mLayerView.animateConvert(startT, mStartBounds, mSnapshot, mTaskLeash, () -> { mFinishCb.onTransitionFinished(mFinishWct); @@ -364,6 +433,42 @@ public class BubbleTransitions { mFinishCb = null; } } + + /** + * Keeps track of internal state of different steps of this BubbleTransition. + */ + private class TransitionProgress { + private boolean mTransitionReady; + private boolean mReadyToExpand; + private boolean mSurfaceReady; + + void setTransitionReady() { + mTransitionReady = true; + onUpdate(); + } + + void setReadyToExpand() { + mReadyToExpand = true; + onUpdate(); + } + + void setSurfaceReady() { + mSurfaceReady = true; + onUpdate(); + } + + boolean isReadyToAnimate() { + // Animation only depends on transition and surface state + return mTransitionReady && mSurfaceReady; + } + + private void onUpdate() { + if (mTransitionReady && mReadyToExpand && mSurfaceReady) { + // Clear the transition from bubble when all the steps are ready + mBubble.setPreparingTransition(null); + } + } + } } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java index 6798a88a6da7..d93dbc3c15d9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java @@ -43,9 +43,10 @@ import com.android.wm.shell.bubbles.BubbleLogger; import com.android.wm.shell.bubbles.BubbleOverflowContainerView; import com.android.wm.shell.bubbles.BubblePositioner; import com.android.wm.shell.bubbles.BubbleTaskView; -import com.android.wm.shell.bubbles.BubbleTaskViewHelper; +import com.android.wm.shell.bubbles.BubbleTaskViewListener; import com.android.wm.shell.bubbles.Bubbles; import com.android.wm.shell.bubbles.RegionSamplingProvider; +import com.android.wm.shell.dagger.HasWMComponent; import com.android.wm.shell.shared.bubbles.BubbleBarLocation; import com.android.wm.shell.shared.handles.RegionSamplingHelper; import com.android.wm.shell.taskview.TaskView; @@ -56,7 +57,7 @@ import java.util.function.Supplier; import javax.inject.Inject; /** Expanded view of a bubble when it's part of the bubble bar. */ -public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskViewHelper.Listener { +public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskViewListener.Callback { /** * The expanded view listener notifying the {@link BubbleBarLayerView} about the internal * actions and events @@ -110,7 +111,7 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView private BubbleExpandedViewManager mManager; private BubblePositioner mPositioner; private boolean mIsOverflow; - private BubbleTaskViewHelper mBubbleTaskViewHelper; + private BubbleTaskViewListener mBubbleTaskViewListener; private BubbleBarMenuViewController mMenuViewController; @Nullable private Supplier<Rect> mLayerBoundsSupplier; @@ -205,6 +206,9 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView protected void onFinishInflate() { super.onFinishInflate(); Context context = getContext(); + if (context instanceof HasWMComponent) { + ((HasWMComponent) context).getWMComponent().inject(this); + } setElevation(getResources().getDimensionPixelSize(R.dimen.bubble_elevation)); mCaptionHeight = context.getResources().getDimensionPixelSize( R.dimen.bubble_bar_expanded_view_caption_height); @@ -246,9 +250,10 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView mHandleView.setVisibility(View.GONE); } else { mTaskView = bubbleTaskView.getTaskView(); - mBubbleTaskViewHelper = new BubbleTaskViewHelper(mContext, expandedViewManager, - /* listener= */ this, bubbleTaskView, - /* viewParent= */ this); + mBubbleTaskViewListener = new BubbleTaskViewListener(mContext, bubbleTaskView, + /* viewParent= */ this, + expandedViewManager, + /* callback= */ this); // if the task view is already attached to a parent we need to remove it if (mTaskView.getParent() != null) { @@ -535,13 +540,15 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView /** Updates the bubble shown in the expanded view. */ public void update(Bubble bubble) { mBubble = bubble; - mBubbleTaskViewHelper.update(bubble); + mBubbleTaskViewListener.setBubble(bubble); mMenuViewController.updateMenu(bubble); } /** The task id of the activity shown in the task view, if it exists. */ public int getTaskId() { - return mBubbleTaskViewHelper != null ? mBubbleTaskViewHelper.getTaskId() : INVALID_TASK_ID; + return mBubbleTaskViewListener != null + ? mBubbleTaskViewListener.getTaskId() + : INVALID_TASK_ID; } /** Sets layer bounds supplier used for obscured touchable region of task view */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java index c10c2c905c97..c6afc313b239 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java @@ -81,8 +81,8 @@ public class PipDesktopState { return false; } - /** Returns whether PiP is exiting while we're in a Desktop Mode session. */ - private boolean isPipExitingToDesktopMode() { + /** Returns whether PiP is active in a display that is in active Desktop Mode session. */ + public boolean isPipInDesktopMode() { // Early return if PiP in Desktop Windowing is not supported. if (!isDesktopWindowingPipEnabled()) { return false; @@ -137,7 +137,7 @@ public class PipDesktopState { // 1) If the display windowing mode is freeform, set windowing mode to UNDEFINED so it will // resolve the windowing mode to the display's windowing mode. // 2) If the display windowing mode is not FREEFORM, set windowing mode to FREEFORM. - if (isPipExitingToDesktopMode()) { + if (isPipInDesktopMode()) { if (isDisplayInFreeform()) { return WINDOWING_MODE_UNDEFINED; } else { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java index aebd94fc173a..34d840eed3f0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java @@ -92,7 +92,7 @@ public class TvWMShellModule { MultiInstanceHelper multiInstanceHelper, SplitState splitState, @ShellMainThread ShellExecutor mainExecutor, - Handler mainHandler, + @ShellMainThread Handler mainHandler, SystemWindows systemWindows) { return new TvSplitScreenController(context, shellInit, shellCommandHandler, shellController, shellTaskOrganizer, syncQueue, rootTDAOrganizer, displayController, 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 b6012378e4d4..35475c7ee4ce 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 @@ -134,6 +134,7 @@ import com.android.wm.shell.recents.RecentsTransitionHandler; import com.android.wm.shell.shared.TransactionPool; import com.android.wm.shell.shared.annotations.ShellAnimationThread; import com.android.wm.shell.shared.annotations.ShellBackgroundThread; +import com.android.wm.shell.shared.annotations.ShellDesktopThread; import com.android.wm.shell.shared.annotations.ShellMainThread; import com.android.wm.shell.shared.desktopmode.DesktopModeCompatPolicy; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; @@ -750,6 +751,7 @@ public abstract class WMShellModule { MultiInstanceHelper multiInstanceHelper, @ShellMainThread ShellExecutor mainExecutor, @ShellMainThread Handler mainHandler, + @ShellDesktopThread ShellExecutor desktopExecutor, Optional<DesktopTasksLimiter> desktopTasksLimiter, Optional<RecentTasksController> recentTasksController, InteractionJankMonitor interactionJankMonitor, @@ -789,6 +791,7 @@ public abstract class WMShellModule { recentsTransitionHandler, multiInstanceHelper, mainExecutor, + desktopExecutor, desktopTasksLimiter, recentTasksController.orElse(null), interactionJankMonitor, @@ -915,14 +918,15 @@ public abstract class WMShellModule { Transitions transitions, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, @DynamicOverride DesktopUserRepositories desktopUserRepositories, - InteractionJankMonitor interactionJankMonitor) { + InteractionJankMonitor interactionJankMonitor, + Optional<BubbleController> bubbleController) { return ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS_BUGFIX.isTrue() ? new SpringDragToDesktopTransitionHandler( context, transitions, rootTaskDisplayAreaOrganizer, desktopUserRepositories, - interactionJankMonitor) + interactionJankMonitor, bubbleController) : new DefaultDragToDesktopTransitionHandler( context, transitions, rootTaskDisplayAreaOrganizer, desktopUserRepositories, - interactionJankMonitor); + interactionJankMonitor, bubbleController); } @WMSingleton @@ -1306,7 +1310,8 @@ public abstract class WMShellModule { WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository, DesktopWindowingEducationTooltipController desktopWindowingEducationTooltipController, @ShellMainThread CoroutineScope applicationScope, - @ShellBackgroundThread MainCoroutineDispatcher backgroundDispatcher) { + @ShellBackgroundThread MainCoroutineDispatcher backgroundDispatcher, + DesktopModeUiEventLogger desktopModeUiEventLogger) { return new AppHandleEducationController( context, appHandleEducationFilter, @@ -1314,7 +1319,8 @@ public abstract class WMShellModule { windowDecorCaptionHandleRepository, desktopWindowingEducationTooltipController, applicationScope, - backgroundDispatcher); + backgroundDispatcher, + desktopModeUiEventLogger); } @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 e7c76bbd91b2..7d80ee5f3bb6 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 @@ -174,6 +174,7 @@ public abstract class Pip2Module { @NonNull PipScheduler pipScheduler, @NonNull SizeSpecSource sizeSpecSource, @NonNull PipDisplayLayoutState pipDisplayLayoutState, + PipDesktopState pipDesktopState, DisplayController displayController, PipMotionHelper pipMotionHelper, FloatingContentCoordinator floatingContentCoordinator, @@ -182,8 +183,8 @@ public abstract class Pip2Module { Optional<PipPerfHintController> pipPerfHintControllerOptional) { return new PipTouchHandler(context, shellInit, shellCommandHandler, menuPhoneController, pipBoundsAlgorithm, pipBoundsState, pipTransitionState, pipScheduler, - sizeSpecSource, pipDisplayLayoutState, displayController, pipMotionHelper, - floatingContentCoordinator, pipUiEventLogger, mainExecutor, + sizeSpecSource, pipDisplayLayoutState, pipDesktopState, displayController, + pipMotionHelper, floatingContentCoordinator, pipUiEventLogger, mainExecutor, pipPerfHintControllerOptional); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt index c9b3ec0d3a11..1f7edb413908 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt @@ -71,9 +71,31 @@ class DesktopMixedTransitionHandler( wct: WindowContainerTransaction?, ) = freeformTaskTransitionHandler.startWindowingModeTransition(targetWindowingMode, wct) - /** Delegates starting minimized mode transition to [FreeformTaskTransitionHandler]. */ - override fun startMinimizedModeTransition(wct: WindowContainerTransaction?): IBinder = - freeformTaskTransitionHandler.startMinimizedModeTransition(wct) + /** + * Starts a minimize transition for [taskId], with [isLastTask] which is true if the task going + * to be minimized is the last visible task. + */ + override fun startMinimizedModeTransition( + wct: WindowContainerTransaction?, + taskId: Int, + isLastTask: Boolean, + ): IBinder { + if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_EXIT_BY_MINIMIZE_TRANSITION_BUGFIX.isTrue) { + return freeformTaskTransitionHandler.startMinimizedModeTransition( + wct, + taskId, + isLastTask, + ) + } + requireNotNull(wct) + return transitions + .startTransition(Transitions.TRANSIT_MINIMIZE, wct, /* handler= */ this) + .also { transition -> + pendingMixedTransitions.add( + PendingMixedTransition.Minimize(transition, taskId, isLastTask) + ) + } + } /** Delegates starting PiP transition to [FreeformTaskTransitionHandler]. */ override fun startPipTransition(wct: WindowContainerTransaction?): IBinder = @@ -298,7 +320,15 @@ class DesktopMixedTransitionHandler( finishTransaction: SurfaceControl.Transaction, finishCallback: TransitionFinishCallback, ): Boolean { - if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue) return false + val shouldAnimate = + if (info.type == Transitions.TRANSIT_MINIMIZE) { + DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_EXIT_BY_MINIMIZE_TRANSITION_BUGFIX.isTrue + } else { + DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue + } + if (!shouldAnimate) { + return false + } val minimizeChange = findTaskChange(info, pending.minimizingTask) if (minimizeChange == null) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLogger.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLogger.kt index b96b9d2adddf..b9cb32d8a14f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLogger.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUiEventLogger.kt @@ -149,7 +149,25 @@ class DesktopModeUiEventLogger( @UiEvent(doc = "Enter multi-instance by using the New Window button") DESKTOP_WINDOW_MULTI_INSTANCE_NEW_WINDOW_CLICK(2069), @UiEvent(doc = "Enter multi-instance by clicking an icon in the Manage Windows menu") - DESKTOP_WINDOW_MULTI_INSTANCE_MANAGE_WINDOWS_ICON_CLICK(2070); + DESKTOP_WINDOW_MULTI_INSTANCE_MANAGE_WINDOWS_ICON_CLICK(2070), + @UiEvent(doc = "Education tooltip on the app handle is shown") + APP_HANDLE_EDUCATION_TOOLTIP_SHOWN(2097), + @UiEvent(doc = "Education tooltip on the app handle is clicked") + APP_HANDLE_EDUCATION_TOOLTIP_CLICKED(2098), + @UiEvent(doc = "Education tooltip on the app handle is dismissed by the user") + APP_HANDLE_EDUCATION_TOOLTIP_DISMISSED(2099), + @UiEvent(doc = "Enter desktop mode education tooltip on the app handle menu is shown") + ENTER_DESKTOP_MODE_EDUCATION_TOOLTIP_SHOWN(2100), + @UiEvent(doc = "Enter desktop mode education tooltip on the app handle menu is clicked") + ENTER_DESKTOP_MODE_EDUCATION_TOOLTIP_CLICKED(2101), + @UiEvent(doc = "Enter desktop mode education tooltip is dismissed by the user") + ENTER_DESKTOP_MODE_EDUCATION_TOOLTIP_DISMISSED(2102), + @UiEvent(doc = "Exit desktop mode education tooltip on the app header menu is shown") + EXIT_DESKTOP_MODE_EDUCATION_TOOLTIP_SHOWN(2103), + @UiEvent(doc = "Exit desktop mode education tooltip on the app header menu is clicked") + EXIT_DESKTOP_MODE_EDUCATION_TOOLTIP_CLICKED(2104), + @UiEvent(doc = "Exit desktop mode education tooltip is dismissed by the user") + EXIT_DESKTOP_MODE_EDUCATION_TOOLTIP_DISMISSED(2105); override fun getId(): Int = mId } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java index 27aed17762ff..aecbf1a23cb2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java @@ -18,9 +18,6 @@ package com.android.wm.shell.desktopmode; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; -import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; -import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.NO_INDICATOR; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR; @@ -28,37 +25,27 @@ import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.Indica import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.RectEvaluator; -import android.animation.ValueAnimator; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.content.Context; -import android.content.res.Resources; -import android.graphics.PixelFormat; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region; -import android.graphics.drawable.LayerDrawable; -import android.util.DisplayMetrics; import android.view.SurfaceControl; -import android.view.SurfaceControlViewHost; -import android.view.View; -import android.view.WindowManager; -import android.view.WindowlessWindowManager; -import android.view.animation.DecelerateInterpolator; +import android.window.DesktopModeFlags; import androidx.annotation.VisibleForTesting; import com.android.internal.policy.SystemBarUtils; -import com.android.window.flags.Flags; import com.android.wm.shell.R; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; +import com.android.wm.shell.shared.annotations.ShellDesktopThread; +import com.android.wm.shell.shared.annotations.ShellMainThread; import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper; import com.android.wm.shell.shared.bubbles.BubbleDropTargetBoundsProvider; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; @@ -115,37 +102,54 @@ public class DesktopModeVisualIndicator { } } + private final VisualIndicatorViewContainer mVisualIndicatorViewContainer; + private final Context mContext; private final DisplayController mDisplayController; - private final RootTaskDisplayAreaOrganizer mRootTdaOrganizer; private final ActivityManager.RunningTaskInfo mTaskInfo; - private final SurfaceControl mTaskSurface; - private final @Nullable BubbleDropTargetBoundsProvider mBubbleBoundsProvider; - private SurfaceControl mLeash; - - private final SyncTransactionQueue mSyncQueue; - private SurfaceControlViewHost mViewHost; - private View mView; private IndicatorType mCurrentType; - private DragStartState mDragStartState; - private boolean mIsReleased; + private final DragStartState mDragStartState; - public DesktopModeVisualIndicator(SyncTransactionQueue syncQueue, + public DesktopModeVisualIndicator(@ShellDesktopThread ShellExecutor desktopExecutor, + @ShellMainThread ShellExecutor mainExecutor, + SyncTransactionQueue syncQueue, ActivityManager.RunningTaskInfo taskInfo, DisplayController displayController, Context context, SurfaceControl taskSurface, RootTaskDisplayAreaOrganizer taskDisplayAreaOrganizer, DragStartState dragStartState, @Nullable BubbleDropTargetBoundsProvider bubbleBoundsProvider) { - mSyncQueue = syncQueue; + SurfaceControl.Builder builder = new SurfaceControl.Builder(); + taskDisplayAreaOrganizer.attachToDisplayArea(taskInfo.displayId, builder); + mVisualIndicatorViewContainer = new VisualIndicatorViewContainer( + DesktopModeFlags.ENABLE_DESKTOP_INDICATOR_IN_SEPARATE_THREAD_BUGFIX.isTrue() + ? desktopExecutor : mainExecutor, + mainExecutor, builder, syncQueue, bubbleBoundsProvider); mTaskInfo = taskInfo; mDisplayController = displayController; mContext = context; - mTaskSurface = taskSurface; - mRootTdaOrganizer = taskDisplayAreaOrganizer; - mBubbleBoundsProvider = bubbleBoundsProvider; mCurrentType = NO_INDICATOR; mDragStartState = dragStartState; + mVisualIndicatorViewContainer.createView( + mContext, + mDisplayController.getDisplay(mTaskInfo.displayId), + mDisplayController.getDisplayLayout(mTaskInfo.displayId), + mTaskInfo, + taskSurface + ); + } + + /** Start the fade out animation, running the callback on the main thread once it is done. */ + public void fadeOutIndicator( + @NonNull Runnable callback) { + mVisualIndicatorViewContainer.fadeOutIndicator( + mDisplayController.getDisplayLayout(mTaskInfo.displayId), mCurrentType, callback + ); + } + + /** Release the visual indicator view and its viewhost. */ + public void releaseVisualIndicator() { + mVisualIndicatorViewContainer.releaseVisualIndicator(); } /** @@ -202,7 +206,10 @@ public class DesktopModeVisualIndicator { } } if (mDragStartState != DragStartState.DRAGGED_INTENT) { - transitionIndicator(result); + mVisualIndicatorViewContainer.transitionIndicator( + mTaskInfo, mDisplayController, mCurrentType, result + ); + mCurrentType = result; } return result; } @@ -283,338 +290,8 @@ public class DesktopModeVisualIndicator { layout.width(), layout.height()); } - /** - * Create a fullscreen indicator with no animation - */ - private void createView() { - if (mIsReleased) return; - final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - final Resources resources = mContext.getResources(); - final DisplayMetrics metrics = resources.getDisplayMetrics(); - final int screenWidth; - final int screenHeight; - if (Flags.enableBugFixesForSecondaryDisplay()) { - final DisplayLayout displayLayout = - mDisplayController.getDisplayLayout(mTaskInfo.displayId); - screenWidth = displayLayout.width(); - screenHeight = displayLayout.height(); - } else { - screenWidth = metrics.widthPixels; - screenHeight = metrics.heightPixels; - } - mView = new View(mContext); - final SurfaceControl.Builder builder = new SurfaceControl.Builder(); - mRootTdaOrganizer.attachToDisplayArea(mTaskInfo.displayId, builder); - mLeash = builder - .setName("Desktop Mode Visual Indicator") - .setContainerLayer() - .setCallsite("DesktopModeVisualIndicator.createView") - .build(); - t.show(mLeash); - final WindowManager.LayoutParams lp = - new WindowManager.LayoutParams(screenWidth, screenHeight, TYPE_APPLICATION, - FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT); - lp.setTitle("Desktop Mode Visual Indicator"); - lp.setTrustedOverlay(); - lp.inputFeatures |= INPUT_FEATURE_NO_INPUT_CHANNEL; - final WindowlessWindowManager windowManager = new WindowlessWindowManager( - mTaskInfo.configuration, mLeash, - /* hostInputToken= */ null); - mViewHost = new SurfaceControlViewHost(mContext, - mDisplayController.getDisplay(mTaskInfo.displayId), windowManager, - "DesktopModeVisualIndicator"); - mViewHost.setView(mView, lp); - // We want this indicator to be behind the dragged task, but in front of all others. - t.setRelativeLayer(mLeash, mTaskSurface, -1); - - mSyncQueue.runInSync(transaction -> { - transaction.merge(t); - t.close(); - }); - } - @VisibleForTesting Rect getIndicatorBounds() { - return mView.getBackground().getBounds(); - } - - /** - * Fade indicator in as provided type. Animator fades it in while expanding the bounds outwards. - */ - private void fadeInIndicator(IndicatorType type) { - mView.setBackgroundResource(R.drawable.desktop_windowing_transition_background); - final VisualIndicatorAnimator animator = VisualIndicatorAnimator - .fadeBoundsIn(mView, type, - mDisplayController.getDisplayLayout(mTaskInfo.displayId), - mBubbleBoundsProvider); - animator.start(); - mCurrentType = type; - } - - /** - * Fade out indicator without fully releasing it. Animator fades it out while shrinking bounds. - * - * @param finishCallback called when animation ends or gets cancelled - */ - void fadeOutIndicator(@Nullable Runnable finishCallback) { - if (mCurrentType == NO_INDICATOR) { - // In rare cases, fade out can be requested before the indicator has determined its - // initial type and started animating in. In this case, no animator is needed. - finishCallback.run(); - return; - } - final VisualIndicatorAnimator animator = VisualIndicatorAnimator - .fadeBoundsOut(mView, mCurrentType, - mDisplayController.getDisplayLayout(mTaskInfo.displayId), - mBubbleBoundsProvider); - animator.start(); - if (finishCallback != null) { - animator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - finishCallback.run(); - } - }); - } - mCurrentType = NO_INDICATOR; - } - - /** - * Takes existing indicator and animates it to bounds reflecting a new indicator type. - */ - private void transitionIndicator(IndicatorType newType) { - if (mCurrentType == newType) return; - if (mView == null) { - createView(); - } - if (mCurrentType == NO_INDICATOR) { - fadeInIndicator(newType); - } else if (newType == NO_INDICATOR) { - fadeOutIndicator(/* finishCallback= */ null); - } else { - final VisualIndicatorAnimator animator = VisualIndicatorAnimator.animateIndicatorType( - mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId), mCurrentType, - newType, mBubbleBoundsProvider); - mCurrentType = newType; - animator.start(); - } - } - - /** - * Release the indicator and its components when it is no longer needed. - */ - public void releaseVisualIndicator(SurfaceControl.Transaction t) { - mIsReleased = true; - if (mViewHost == null) return; - if (mViewHost != null) { - mViewHost.release(); - mViewHost = null; - } - - if (mLeash != null) { - t.remove(mLeash); - mLeash = null; - } - } - - /** - * Animator for Desktop Mode transitions which supports bounds and alpha animation. - */ - private static class VisualIndicatorAnimator extends ValueAnimator { - private static final int FULLSCREEN_INDICATOR_DURATION = 200; - private static final float FULLSCREEN_SCALE_ADJUSTMENT_PERCENT = 0.015f; - private static final float INDICATOR_FINAL_OPACITY = 0.35f; - private static final int MAXIMUM_OPACITY = 255; - - /** - * Determines how this animator will interact with the view's alpha: - * Fade in, fade out, or no change to alpha - */ - private enum AlphaAnimType { - ALPHA_FADE_IN_ANIM, ALPHA_FADE_OUT_ANIM, ALPHA_NO_CHANGE_ANIM - } - - private final View mView; - private final Rect mStartBounds; - private final Rect mEndBounds; - private final RectEvaluator mRectEvaluator; - - private VisualIndicatorAnimator(View view, Rect startBounds, - Rect endBounds) { - mView = view; - mStartBounds = new Rect(startBounds); - mEndBounds = endBounds; - setFloatValues(0, 1); - mRectEvaluator = new RectEvaluator(new Rect()); - } - - private static VisualIndicatorAnimator fadeBoundsIn( - @NonNull View view, IndicatorType type, @NonNull DisplayLayout displayLayout, - @Nullable BubbleDropTargetBoundsProvider bubbleBoundsProvider) { - final Rect endBounds = getIndicatorBounds(displayLayout, type, bubbleBoundsProvider); - final Rect startBounds = getMinBounds(endBounds); - view.getBackground().setBounds(startBounds); - - final VisualIndicatorAnimator animator = new VisualIndicatorAnimator( - view, startBounds, endBounds); - animator.setInterpolator(new DecelerateInterpolator()); - setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_FADE_IN_ANIM); - return animator; - } - - private static VisualIndicatorAnimator fadeBoundsOut( - @NonNull View view, IndicatorType type, @NonNull DisplayLayout displayLayout, - @Nullable BubbleDropTargetBoundsProvider bubbleBoundsProvider) { - final Rect startBounds = getIndicatorBounds(displayLayout, type, bubbleBoundsProvider); - final Rect endBounds = getMinBounds(startBounds); - view.getBackground().setBounds(startBounds); - - final VisualIndicatorAnimator animator = new VisualIndicatorAnimator( - view, startBounds, endBounds); - animator.setInterpolator(new DecelerateInterpolator()); - setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_FADE_OUT_ANIM); - return animator; - } - - /** - * Create animator for visual indicator changing type (i.e., fullscreen to freeform, - * freeform to split, etc.) - * - * @param view the view for this indicator - * @param displayLayout information about the display the transitioning task is - * currently on - * @param origType the original indicator type - * @param newType the new indicator type - * @param bubbleBoundsProvider provides bounds for bubbles indicators - */ - private static VisualIndicatorAnimator animateIndicatorType(@NonNull View view, - @NonNull DisplayLayout displayLayout, IndicatorType origType, IndicatorType newType, - @Nullable BubbleDropTargetBoundsProvider bubbleBoundsProvider) { - final Rect startBounds = getIndicatorBounds(displayLayout, origType, - bubbleBoundsProvider); - final Rect endBounds = getIndicatorBounds(displayLayout, newType, bubbleBoundsProvider); - final VisualIndicatorAnimator animator = new VisualIndicatorAnimator( - view, startBounds, endBounds); - animator.setInterpolator(new DecelerateInterpolator()); - setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_NO_CHANGE_ANIM); - return animator; - } - - /** Calculates the bounds the indicator should have when fully faded in. */ - private static Rect getIndicatorBounds(DisplayLayout layout, IndicatorType type, - @Nullable BubbleDropTargetBoundsProvider bubbleBoundsProvider) { - final Rect desktopStableBounds = new Rect(); - layout.getStableBounds(desktopStableBounds); - final int padding = desktopStableBounds.top; - switch (type) { - case TO_FULLSCREEN_INDICATOR: - desktopStableBounds.top += padding; - desktopStableBounds.bottom -= padding; - desktopStableBounds.left += padding; - desktopStableBounds.right -= padding; - return desktopStableBounds; - case TO_DESKTOP_INDICATOR: - final float adjustmentPercentage = 1f - - DesktopTasksController.DESKTOP_MODE_INITIAL_BOUNDS_SCALE; - return new Rect((int) (adjustmentPercentage * desktopStableBounds.width() / 2), - (int) (adjustmentPercentage * desktopStableBounds.height() / 2), - (int) (desktopStableBounds.width() - - (adjustmentPercentage * desktopStableBounds.width() / 2)), - (int) (desktopStableBounds.height() - - (adjustmentPercentage * desktopStableBounds.height() / 2))); - case TO_SPLIT_LEFT_INDICATOR: - return new Rect(padding, padding, - desktopStableBounds.width() / 2 - padding, - desktopStableBounds.height()); - case TO_SPLIT_RIGHT_INDICATOR: - return new Rect(desktopStableBounds.width() / 2 + padding, padding, - desktopStableBounds.width() - padding, - desktopStableBounds.height()); - case TO_BUBBLE_LEFT_INDICATOR: - if (bubbleBoundsProvider == null) { - return new Rect(); - } - return bubbleBoundsProvider.getBubbleBarExpandedViewDropTargetBounds( - /* onLeft= */ true); - case TO_BUBBLE_RIGHT_INDICATOR: - if (bubbleBoundsProvider == null) { - return new Rect(); - } - return bubbleBoundsProvider.getBubbleBarExpandedViewDropTargetBounds( - /* onLeft= */ false); - default: - throw new IllegalArgumentException("Invalid indicator type provided."); - } - } - - /** - * Add necessary listener for animation of indicator - */ - private static void setupIndicatorAnimation(@NonNull VisualIndicatorAnimator animator, - AlphaAnimType animType) { - animator.addUpdateListener(a -> { - if (animator.mView != null) { - animator.updateBounds(a.getAnimatedFraction(), animator.mView); - if (animType == AlphaAnimType.ALPHA_FADE_IN_ANIM) { - animator.updateIndicatorAlpha(a.getAnimatedFraction(), animator.mView); - } else if (animType == AlphaAnimType.ALPHA_FADE_OUT_ANIM) { - animator.updateIndicatorAlpha(1 - a.getAnimatedFraction(), animator.mView); - } - } else { - animator.cancel(); - } - }); - animator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - animator.mView.getBackground().setBounds(animator.mEndBounds); - } - }); - animator.setDuration(FULLSCREEN_INDICATOR_DURATION); - } - - /** - * Update bounds of view based on current animation fraction. - * Use of delta is to animate bounds independently, in case we need to - * run multiple animations simultaneously. - * - * @param fraction fraction to use, compared against previous fraction - * @param view the view to update - */ - private void updateBounds(float fraction, View view) { - if (mStartBounds.equals(mEndBounds)) { - return; - } - final Rect currentBounds = mRectEvaluator.evaluate(fraction, mStartBounds, mEndBounds); - view.getBackground().setBounds(currentBounds); - } - - /** - * Fade in the fullscreen indicator - * - * @param fraction current animation fraction - */ - private void updateIndicatorAlpha(float fraction, View view) { - final LayerDrawable drawable = (LayerDrawable) view.getBackground(); - drawable.findDrawableByLayerId(R.id.indicator_stroke) - .setAlpha((int) (MAXIMUM_OPACITY * fraction)); - drawable.findDrawableByLayerId(R.id.indicator_solid) - .setAlpha((int) (MAXIMUM_OPACITY * fraction * INDICATOR_FINAL_OPACITY)); - } - - /** - * Return the minimum bounds of a visual indicator, to be used at the end of fading out - * and the start of fading in. - */ - private static Rect getMinBounds(Rect maxBounds) { - return new Rect((int) (maxBounds.left - + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.width())), - (int) (maxBounds.top - + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.height())), - (int) (maxBounds.right - - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.width())), - (int) (maxBounds.bottom - - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.height()))); - } + return mVisualIndicatorViewContainer.getIndicatorBounds(); } } 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 531304d6922a..bbf00104711f 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 @@ -116,6 +116,7 @@ import com.android.wm.shell.recents.RecentsTransitionStateListener.RecentsTransi import com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_NOT_RUNNING import com.android.wm.shell.shared.TransitionUtil import com.android.wm.shell.shared.annotations.ExternalThread +import com.android.wm.shell.shared.annotations.ShellDesktopThread import com.android.wm.shell.shared.annotations.ShellMainThread import com.android.wm.shell.shared.desktopmode.DesktopModeCompatPolicy import com.android.wm.shell.shared.desktopmode.DesktopModeStatus @@ -176,6 +177,7 @@ class DesktopTasksController( private val recentsTransitionHandler: RecentsTransitionHandler, private val multiInstanceHelper: MultiInstanceHelper, @ShellMainThread private val mainExecutor: ShellExecutor, + @ShellDesktopThread private val desktopExecutor: ShellExecutor, private val desktopTasksLimiter: Optional<DesktopTasksLimiter>, private val recentTasksController: RecentTasksController?, private val interactionJankMonitor: InteractionJankMonitor, @@ -202,26 +204,19 @@ class DesktopTasksController( private var userId: Int private val desktopModeShellCommandHandler: DesktopModeShellCommandHandler = DesktopModeShellCommandHandler(this) - private val mOnAnimationFinishedCallback = - Consumer<SurfaceControl.Transaction> { t: SurfaceControl.Transaction -> - visualIndicator?.releaseVisualIndicator(t) - visualIndicator = null - } + private val mOnAnimationFinishedCallback = { releaseVisualIndicator() } private val dragToDesktopStateListener = object : DragToDesktopStateListener { - override fun onCommitToDesktopAnimationStart(tx: SurfaceControl.Transaction) { - removeVisualIndicator(tx) + override fun onCommitToDesktopAnimationStart() { + removeVisualIndicator() } - override fun onCancelToDesktopAnimationEnd(tx: SurfaceControl.Transaction) { - removeVisualIndicator(tx) + override fun onCancelToDesktopAnimationEnd() { + removeVisualIndicator() } - private fun removeVisualIndicator(tx: SurfaceControl.Transaction) { - visualIndicator?.fadeOutIndicator { - visualIndicator?.releaseVisualIndicator(tx) - visualIndicator = null - } + private fun removeVisualIndicator() { + visualIndicator?.fadeOutIndicator { releaseVisualIndicator() } } } @@ -838,6 +833,7 @@ class DesktopTasksController( val taskId = taskInfo.taskId val displayId = taskInfo.displayId val wct = WindowContainerTransaction() + desktopTilingDecorViewModel.removeTaskIfTiled(displayId, taskId) performDesktopExitCleanupIfNeeded(taskId, displayId, wct, forceToFullscreen = false) // Notify immersive handler as it might need to exit immersive state. val exitResult = @@ -848,7 +844,9 @@ class DesktopTasksController( ) wct.reorder(taskInfo.token, false) - val transition = freeformTaskTransitionStarter.startMinimizedModeTransition(wct) + val isLastTask = taskRepository.isOnlyVisibleNonClosingTask(taskId, displayId) + val transition: IBinder = + freeformTaskTransitionStarter.startMinimizedModeTransition(wct, taskId, isLastTask) desktopTasksLimiter.ifPresent { it.addPendingMinimizeChange( transition = transition, @@ -1773,13 +1771,8 @@ class DesktopTasksController( } fun releaseVisualIndicator() { - val t = SurfaceControl.Transaction() - visualIndicator?.releaseVisualIndicator(t) + visualIndicator?.releaseVisualIndicator() visualIndicator = null - syncQueue.runInSync { transaction -> - transaction.merge(t) - t.close() - } } override fun getContext(): Context = context @@ -1999,6 +1992,9 @@ class DesktopTasksController( splitPosition, options.toBundle(), /* hideTaskToken= */ null, + if (enableFlexibleSplit()) + splitScreenController.determineNewInstanceIndex(callingTask) + else SPLIT_INDEX_UNDEFINED, ) } } @@ -2689,15 +2685,22 @@ class DesktopTasksController( } /** Requests a task be transitioned from whatever mode it's in to a bubble. */ - fun requestFloat(taskInfo: RunningTaskInfo) { + @JvmOverloads + fun requestFloat(taskInfo: RunningTaskInfo, left: Boolean? = null) { val isDragging = dragToDesktopTransitionHandler.inProgress val shouldRequestFloat = taskInfo.isFullscreen || taskInfo.isFreeform || isDragging || taskInfo.isMultiWindow if (!shouldRequestFloat) return if (isDragging) { releaseVisualIndicator() + val cancelState = + if (left == true) DragToDesktopTransitionHandler.CancelState.CANCEL_BUBBLE_LEFT + else DragToDesktopTransitionHandler.CancelState.CANCEL_BUBBLE_RIGHT + dragToDesktopTransitionHandler.cancelDragToDesktopTransition(cancelState) } else { - bubbleController.ifPresent { it.expandStackAndSelectBubble(taskInfo) } + bubbleController.ifPresent { + it.expandStackAndSelectBubble(taskInfo, /* dragData= */ null) + } } } @@ -2750,6 +2753,8 @@ class DesktopTasksController( val indicator = visualIndicator ?: DesktopModeVisualIndicator( + desktopExecutor, + mainExecutor, syncQueue, taskInfo, displayController, @@ -2975,10 +2980,11 @@ class DesktopTasksController( ) requestSplit(taskInfo, leftOrTop = false) } - IndicatorType.TO_BUBBLE_LEFT_INDICATOR, + IndicatorType.TO_BUBBLE_LEFT_INDICATOR -> { + requestFloat(taskInfo, left = true) + } IndicatorType.TO_BUBBLE_RIGHT_INDICATOR -> { - // TODO(b/388851898): move to bubble - cancelDragToDesktop(taskInfo) + requestFloat(taskInfo, left = false) } } return indicatorType diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt index 8194d3cab445..aaecf8c2d727 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt @@ -37,6 +37,8 @@ import com.android.internal.jank.InteractionJankMonitor import com.android.internal.protolog.ProtoLog import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.animation.FloatProperties +import com.android.wm.shell.bubbles.BubbleController +import com.android.wm.shell.bubbles.BubbleTransitions import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP @@ -49,10 +51,12 @@ import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UND import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition import com.android.wm.shell.splitscreen.SplitScreenController import com.android.wm.shell.transition.Transitions +import com.android.wm.shell.transition.Transitions.TRANSIT_CONVERT_TO_BUBBLE import com.android.wm.shell.transition.Transitions.TransitionHandler import com.android.wm.shell.windowdecor.MoveToDesktopAnimator import com.android.wm.shell.windowdecor.MoveToDesktopAnimator.Companion.DRAG_FREEFORM_SCALE import com.android.wm.shell.windowdecor.OnTaskResizeAnimationListener +import java.util.Optional import java.util.function.Supplier import kotlin.math.max @@ -72,6 +76,7 @@ sealed class DragToDesktopTransitionHandler( private val taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, private val desktopUserRepositories: DesktopUserRepositories, protected val interactionJankMonitor: InteractionJankMonitor, + private val bubbleController: Optional<BubbleController>, protected val transactionSupplier: Supplier<SurfaceControl.Transaction>, ) : TransitionHandler { @@ -241,6 +246,20 @@ sealed class DragToDesktopTransitionHandler( state.startTransitionFinishCb?.onTransitionFinished(/* wct= */ null) requestSplitFromScaledTask(splitPosition, wct) clearState() + } else if ( + state.draggedTaskChange != null && + (cancelState == CancelState.CANCEL_BUBBLE_LEFT || + cancelState == CancelState.CANCEL_BUBBLE_RIGHT) + ) { + if (!bubbleController.isPresent) { + startCancelAnimation() + } else { + // Animation is handled by BubbleController + val wct = WindowContainerTransaction() + restoreWindowOrder(wct, state) + val onLeft = cancelState == CancelState.CANCEL_BUBBLE_LEFT + requestBubbleFromScaledTask(wct, onLeft) + } } else { // There's no dragged task, this can happen when the "cancel" happened too quickly // before the "start" transition is even ready (like on a fling gesture). The @@ -258,20 +277,25 @@ sealed class DragToDesktopTransitionHandler( ) { val state = requireTransitionState() val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null taskInfo") + val animatedTaskBounds = getAnimatedTaskBounds() + requestSplitSelect(wct, taskInfo, splitPosition, animatedTaskBounds) + } + + private fun getAnimatedTaskBounds(): Rect { + val state = requireTransitionState() + val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null taskInfo") val taskBounds = Rect(taskInfo.configuration.windowConfiguration.bounds) val taskScale = state.dragAnimator.scale val scaledWidth = taskBounds.width() * taskScale val scaledHeight = taskBounds.height() * taskScale val dragPosition = PointF(state.dragAnimator.position) state.dragAnimator.cancelAnimator() - val animatedTaskBounds = - Rect( - dragPosition.x.toInt(), - dragPosition.y.toInt(), - (dragPosition.x + scaledWidth).toInt(), - (dragPosition.y + scaledHeight).toInt(), - ) - requestSplitSelect(wct, taskInfo, splitPosition, animatedTaskBounds) + return Rect( + dragPosition.x.toInt(), + dragPosition.y.toInt(), + (dragPosition.x + scaledWidth).toInt(), + (dragPosition.y + scaledHeight).toInt(), + ) } private fun requestSplitSelect( @@ -294,6 +318,29 @@ sealed class DragToDesktopTransitionHandler( splitScreenController.requestEnterSplitSelect(taskInfo, wct, splitPosition, taskBounds) } + private fun requestBubbleFromScaledTask(wct: WindowContainerTransaction, onLeft: Boolean) { + // TODO(b/391928049): update density once we can drag from desktop to bubble + val state = requireTransitionState() + val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null taskInfo") + val taskBounds = getAnimatedTaskBounds() + state.dragAnimator.cancelAnimator() + requestBubble(wct, taskInfo, onLeft, taskBounds) + } + + private fun requestBubble( + wct: WindowContainerTransaction, + taskInfo: RunningTaskInfo, + onLeft: Boolean, + taskBounds: Rect = Rect(taskInfo.configuration.windowConfiguration.bounds), + ) { + val controller = + bubbleController.orElseThrow { IllegalStateException("BubbleController not set") } + controller.expandStackAndSelectBubble( + taskInfo, + BubbleTransitions.DragData(taskBounds, wct, onLeft), + ) + } + override fun startAnimation( transition: IBinder, info: TransitionInfo, @@ -446,6 +493,16 @@ sealed class DragToDesktopTransitionHandler( state.startTransitionFinishTransaction?.apply() state.startTransitionFinishCb?.onTransitionFinished(/* wct= */ null) requestSplitSelect(wct, taskInfo, splitPosition) + } else if ( + state.cancelState == CancelState.CANCEL_BUBBLE_LEFT || + state.cancelState == CancelState.CANCEL_BUBBLE_RIGHT + ) { + val taskInfo = + state.draggedTaskChange?.taskInfo ?: error("Expected non-null task info.") + val wct = WindowContainerTransaction() + restoreWindowOrder(wct) + val onLeft = state.cancelState == CancelState.CANCEL_BUBBLE_LEFT + requestBubble(wct, taskInfo, onLeft) } return true } @@ -476,6 +533,13 @@ sealed class DragToDesktopTransitionHandler( clearState() return } + // In case of bubble animation, finish the initial desktop drag animation, but keep the + // current animation running and have bubbles take over + if (info.type == TRANSIT_CONVERT_TO_BUBBLE) { + state.startTransitionFinishCb?.onTransitionFinished(/* wct= */ null) + clearState() + return + } val isCancelTransition = info.type == TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP && transition == state.cancelTransitionToken && @@ -582,7 +646,7 @@ sealed class DragToDesktopTransitionHandler( startPosition.y.toInt() + unscaledStartHeight, ) - dragToDesktopStateListener?.onCommitToDesktopAnimationStart(startTransaction) + dragToDesktopStateListener?.onCommitToDesktopAnimationStart() // Accept the merge by applying the merging transaction (applied by #showResizeVeil) // and finish callback. Show the veil and position the task at the first frame before // starting the final animation. @@ -713,7 +777,7 @@ sealed class DragToDesktopTransitionHandler( addListener( object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { - dragToDesktopStateListener?.onCancelToDesktopAnimationEnd(tx) + dragToDesktopStateListener?.onCancelToDesktopAnimationEnd() // Start the cancel transition to restore order. startCancelDragToDesktopTransition() } @@ -806,9 +870,9 @@ sealed class DragToDesktopTransitionHandler( ) interface DragToDesktopStateListener { - fun onCommitToDesktopAnimationStart(tx: SurfaceControl.Transaction) + fun onCommitToDesktopAnimationStart() - fun onCancelToDesktopAnimationEnd(tx: SurfaceControl.Transaction) + fun onCancelToDesktopAnimationEnd() } sealed class TransitionState { @@ -869,6 +933,10 @@ sealed class DragToDesktopTransitionHandler( CANCEL_SPLIT_LEFT, /** A cancel event where the task will request to enter split on the right side. */ CANCEL_SPLIT_RIGHT, + /** A cancel event where the task will request to bubble on the left side. */ + CANCEL_BUBBLE_LEFT, + /** A cancel event where the task will request to bubble on the right side. */ + CANCEL_BUBBLE_RIGHT, } companion object { @@ -887,6 +955,7 @@ constructor( taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, desktopUserRepositories: DesktopUserRepositories, interactionJankMonitor: InteractionJankMonitor, + bubbleController: Optional<BubbleController>, transactionSupplier: Supplier<SurfaceControl.Transaction> = Supplier { SurfaceControl.Transaction() }, @@ -897,6 +966,7 @@ constructor( taskDisplayAreaOrganizer, desktopUserRepositories, interactionJankMonitor, + bubbleController, transactionSupplier, ) { @@ -925,6 +995,7 @@ constructor( taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, desktopUserRepositories: DesktopUserRepositories, interactionJankMonitor: InteractionJankMonitor, + bubbleController: Optional<BubbleController>, transactionSupplier: Supplier<SurfaceControl.Transaction> = Supplier { SurfaceControl.Transaction() }, @@ -935,6 +1006,7 @@ constructor( taskDisplayAreaOrganizer, desktopUserRepositories, interactionJankMonitor, + bubbleController, transactionSupplier, ) { @@ -1013,7 +1085,7 @@ constructor( val startBoundsWithOffset = Rect(startBounds).apply { offset(startPosition.x.toInt(), startPosition.y.toInt()) } - dragToDesktopStateListener?.onCommitToDesktopAnimationStart(startTransaction) + dragToDesktopStateListener?.onCommitToDesktopAnimationStart() // Accept the merge by applying the merging transaction (applied by #showResizeVeil) // and finish callback. Show the veil and position the task at the first frame before // starting the final animation. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java index f7f87ed63003..5ae1fca73d4e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java @@ -50,9 +50,11 @@ import com.android.wm.shell.shared.annotations.ShellMainThread; import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource; import com.android.wm.shell.transition.Transitions; +import kotlin.Unit; +import kotlin.jvm.functions.Function0; + import java.util.ArrayList; import java.util.List; -import java.util.function.Consumer; import java.util.function.Supplier; @@ -69,7 +71,7 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH @ShellMainThread private final Handler mHandler; private final List<IBinder> mPendingTransitionTokens = new ArrayList<>(); - private Consumer<SurfaceControl.Transaction> mOnAnimationFinishedCallback; + private Function0<Unit> mOnAnimationFinishedCallback; private final Supplier<SurfaceControl.Transaction> mTransactionSupplier; private Point mPosition; @@ -106,7 +108,7 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH */ public void startTransition(@NonNull DesktopModeTransitionSource transitionSource, @NonNull WindowContainerTransaction wct, Point position, - Consumer<SurfaceControl.Transaction> onAnimationEndCallback) { + Function0<Unit> onAnimationEndCallback) { mPosition = position; mOnAnimationFinishedCallback = onAnimationEndCallback; final IBinder token = mTransitions.startTransition(getExitTransitionType(transitionSource), @@ -192,7 +194,7 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH @Override public void onAnimationEnd(Animator animation) { if (mOnAnimationFinishedCallback != null) { - mOnAnimationFinishedCallback.accept(finishT); + mOnAnimationFinishedCallback.invoke(); } mInteractionJankMonitor.end(Cuj.CUJ_DESKTOP_MODE_EXIT_MODE); mTransitions.getMainExecutor().execute( diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainer.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainer.kt new file mode 100644 index 000000000000..2317274dbbf0 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainer.kt @@ -0,0 +1,491 @@ +/* + * Copyright (C) 2025 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.desktopmode + +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.RectEvaluator +import android.animation.ValueAnimator +import android.app.ActivityManager +import android.content.Context +import android.graphics.PixelFormat +import android.graphics.Rect +import android.graphics.drawable.LayerDrawable +import android.view.Display +import android.view.SurfaceControl +import android.view.SurfaceControlViewHost +import android.view.View +import android.view.WindowManager +import android.view.WindowlessWindowManager +import android.view.animation.DecelerateInterpolator +import com.android.internal.annotations.VisibleForTesting +import com.android.window.flags.Flags +import com.android.wm.shell.R +import com.android.wm.shell.common.DisplayController +import com.android.wm.shell.common.DisplayLayout +import com.android.wm.shell.common.ShellExecutor +import com.android.wm.shell.common.SyncTransactionQueue +import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType +import com.android.wm.shell.shared.annotations.ShellDesktopThread +import com.android.wm.shell.shared.annotations.ShellMainThread +import com.android.wm.shell.shared.bubbles.BubbleDropTargetBoundsProvider +import com.android.wm.shell.windowdecor.WindowDecoration.SurfaceControlViewHostFactory + +/** + * Container for the view / viewhost of the indicator, ensuring it is created / animated off the + * main thread. + */ +@VisibleForTesting +class VisualIndicatorViewContainer +@JvmOverloads +constructor( + @ShellDesktopThread private val desktopExecutor: ShellExecutor, + @ShellMainThread private val mainExecutor: ShellExecutor, + private val indicatorBuilder: SurfaceControl.Builder, + private val syncQueue: SyncTransactionQueue, + private val surfaceControlViewHostFactory: SurfaceControlViewHostFactory = + object : SurfaceControlViewHostFactory {}, + private val bubbleBoundsProvider: BubbleDropTargetBoundsProvider?, +) { + @VisibleForTesting var indicatorView: View? = null + private var indicatorViewHost: SurfaceControlViewHost? = null + // Below variables and the SyncTransactionQueue are the only variables that should + // be accessed from shell main thread. Everything else should be used exclusively + // from the desktop thread. + private var indicatorLeash: SurfaceControl? = null + private var isReleased = false + + /** Create a fullscreen indicator with no animation */ + @ShellMainThread + fun createView( + context: Context, + display: Display, + layout: DisplayLayout, + taskInfo: ActivityManager.RunningTaskInfo, + taskSurface: SurfaceControl, + ) { + if (isReleased) return + desktopExecutor.execute { + val resources = context.resources + val metrics = resources.displayMetrics + val screenWidth: Int + val screenHeight: Int + if (Flags.enableBugFixesForSecondaryDisplay()) { + screenWidth = layout.width() + screenHeight = layout.height() + } else { + screenWidth = metrics.widthPixels + screenHeight = metrics.heightPixels + } + indicatorView = View(context) + val leash = + indicatorBuilder + .setName("Desktop Mode Visual Indicator") + .setContainerLayer() + .setCallsite("DesktopModeVisualIndicator.createView") + .build() + val lp = + WindowManager.LayoutParams( + screenWidth, + screenHeight, + WindowManager.LayoutParams.TYPE_APPLICATION, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + PixelFormat.TRANSPARENT, + ) + lp.title = "Desktop Mode Visual Indicator" + lp.setTrustedOverlay() + lp.inputFeatures = + lp.inputFeatures or WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL + val windowManager = + WindowlessWindowManager( + taskInfo.configuration, + leash, + /* hostInputTransferToken= */ null, + ) + indicatorViewHost = + surfaceControlViewHostFactory.create( + context, + display, + windowManager, + "VisualIndicatorViewContainer", + ) + indicatorView?.let { indicatorViewHost?.setView(it, lp) } + showIndicator(taskSurface, leash) + } + } + + private fun showIndicator(taskSurface: SurfaceControl, leash: SurfaceControl) { + mainExecutor.execute { + indicatorLeash = leash + val t = SurfaceControl.Transaction() + t.show(indicatorLeash) + // We want this indicator to be behind the dragged task, but in front of all others. + t.setRelativeLayer(indicatorLeash, taskSurface, -1) + syncQueue.runInSync { transaction: SurfaceControl.Transaction -> + transaction.merge(t) + t.close() + } + } + } + + @VisibleForTesting + fun getIndicatorBounds(): Rect { + return indicatorView?.background?.getBounds() ?: Rect() + } + + /** + * Takes existing indicator and animates it to bounds reflecting a new indicator type. Should + * only be called from the main thread. + */ + @ShellMainThread + fun transitionIndicator( + taskInfo: ActivityManager.RunningTaskInfo, + displayController: DisplayController, + currentType: IndicatorType, + newType: IndicatorType, + ) { + if (currentType == newType || isReleased) return + desktopExecutor.execute { + val layout = + displayController.getDisplayLayout(taskInfo.displayId) + ?: error("Expected to find DisplayLayout for taskId${taskInfo.taskId}.") + if (currentType == IndicatorType.NO_INDICATOR) { + fadeInIndicator(layout, newType) + } else if (newType == IndicatorType.NO_INDICATOR) { + fadeOutIndicator(layout, currentType, /* finishCallback= */ null) + } else { + val animStartType = IndicatorType.valueOf(currentType.name) + val animator = + indicatorView?.let { + VisualIndicatorAnimator.animateIndicatorType( + it, + layout, + animStartType, + newType, + bubbleBoundsProvider, + ) + } ?: return@execute + animator.start() + } + } + } + + /** + * Fade indicator in as provided type. Animator fades it in while expanding the bounds outwards. + */ + @VisibleForTesting + fun fadeInIndicator(layout: DisplayLayout, type: IndicatorType) { + desktopExecutor.assertCurrentThread() + indicatorView?.let { + it.setBackgroundResource(R.drawable.desktop_windowing_transition_background) + val animator = + VisualIndicatorAnimator.fadeBoundsIn(it, type, layout, bubbleBoundsProvider) + animator.start() + } + } + + /** + * Fade out indicator without fully releasing it. Animator fades it out while shrinking bounds. + * + * @param finishCallback called when animation ends or gets cancelled + */ + fun fadeOutIndicator( + layout: DisplayLayout, + currentType: IndicatorType, + finishCallback: Runnable?, + ) { + if (currentType == IndicatorType.NO_INDICATOR) { + // In rare cases, fade out can be requested before the indicator has determined its + // initial type and started animating in. In this case, no animator is needed. + finishCallback?.run() + return + } + desktopExecutor.execute { + indicatorView?.let { + val animStartType = IndicatorType.valueOf(currentType.name) + val animator = + VisualIndicatorAnimator.fadeBoundsOut( + it, + animStartType, + layout, + bubbleBoundsProvider, + ) + animator.addListener( + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + if (finishCallback != null) { + mainExecutor.execute(finishCallback) + } + } + } + ) + animator.start() + } + } + } + + /** Release the indicator and its components when it is no longer needed. */ + @ShellMainThread + fun releaseVisualIndicator() { + if (isReleased) return + desktopExecutor.execute { + indicatorViewHost?.release() + indicatorViewHost = null + } + indicatorLeash?.let { + val tx = SurfaceControl.Transaction() + tx.remove(it) + indicatorLeash = null + syncQueue.runInSync { transaction: SurfaceControl.Transaction -> + transaction.merge(tx) + tx.close() + } + } + isReleased = true + } + + /** + * Animator for Desktop Mode transitions which supports bounds and alpha animation. Functions + * should only be called from the desktop executor. + */ + @VisibleForTesting + class VisualIndicatorAnimator(view: View, startBounds: Rect, endBounds: Rect) : + ValueAnimator() { + /** + * Determines how this animator will interact with the view's alpha: Fade in, fade out, or + * no change to alpha + */ + private enum class AlphaAnimType { + ALPHA_FADE_IN_ANIM, + ALPHA_FADE_OUT_ANIM, + ALPHA_NO_CHANGE_ANIM, + } + + private val indicatorView: View = view + @VisibleForTesting val indicatorStartBounds = Rect(startBounds) + @VisibleForTesting val indicatorEndBounds = endBounds + private val mRectEvaluator: RectEvaluator + + init { + setFloatValues(0f, 1f) + mRectEvaluator = RectEvaluator(Rect()) + } + + /** + * Update bounds of view based on current animation fraction. Use of delta is to animate + * bounds independently, in case we need to run multiple animations simultaneously. + * + * @param fraction fraction to use, compared against previous fraction + * @param view the view to update + */ + @ShellDesktopThread + private fun updateBounds(fraction: Float, view: View?) { + if (indicatorStartBounds == indicatorEndBounds) { + return + } + val currentBounds = + mRectEvaluator.evaluate(fraction, indicatorStartBounds, indicatorEndBounds) + view?.background?.bounds = currentBounds + } + + /** + * Fade in the fullscreen indicator + * + * @param fraction current animation fraction + */ + @ShellDesktopThread + private fun updateIndicatorAlpha(fraction: Float, view: View?) { + val drawable = view?.background as LayerDrawable + drawable.findDrawableByLayerId(R.id.indicator_stroke).alpha = + (MAXIMUM_OPACITY * fraction).toInt() + drawable.findDrawableByLayerId(R.id.indicator_solid).alpha = + (MAXIMUM_OPACITY * fraction * INDICATOR_FINAL_OPACITY).toInt() + } + + companion object { + private const val FULLSCREEN_INDICATOR_DURATION = 200 + private const val FULLSCREEN_SCALE_ADJUSTMENT_PERCENT = 0.015f + private const val INDICATOR_FINAL_OPACITY = 0.35f + private const val MAXIMUM_OPACITY = 255 + + @ShellDesktopThread + fun fadeBoundsIn( + view: View, + type: IndicatorType, + displayLayout: DisplayLayout, + bubbleBoundsProvider: BubbleDropTargetBoundsProvider?, + ): VisualIndicatorAnimator { + val endBounds = getIndicatorBounds(displayLayout, type, bubbleBoundsProvider) + val startBounds = getMinBounds(endBounds) + view.background.bounds = startBounds + + val animator = VisualIndicatorAnimator(view, startBounds, endBounds) + animator.interpolator = DecelerateInterpolator() + setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_FADE_IN_ANIM) + return animator + } + + @ShellDesktopThread + fun fadeBoundsOut( + view: View, + type: IndicatorType, + displayLayout: DisplayLayout, + bubbleBoundsProvider: BubbleDropTargetBoundsProvider?, + ): VisualIndicatorAnimator { + val startBounds = getIndicatorBounds(displayLayout, type, bubbleBoundsProvider) + val endBounds = getMinBounds(startBounds) + view.background.bounds = startBounds + + val animator = VisualIndicatorAnimator(view, startBounds, endBounds) + animator.interpolator = DecelerateInterpolator() + setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_FADE_OUT_ANIM) + return animator + } + + /** + * Create animator for visual indicator changing type (i.e., fullscreen to freeform, + * freeform to split, etc.) + * + * @param view the view for this indicator + * @param displayLayout information about the display the transitioning task is + * currently on + * @param origType the original indicator type + * @param newType the new indicator type + * @param desktopExecutor: the executor for the ShellDesktopThread; should be the only + * thread this function runs on + */ + @ShellDesktopThread + fun animateIndicatorType( + view: View, + displayLayout: DisplayLayout, + origType: IndicatorType, + newType: IndicatorType, + bubbleBoundsProvider: BubbleDropTargetBoundsProvider?, + ): VisualIndicatorAnimator { + val startBounds = getIndicatorBounds(displayLayout, origType, bubbleBoundsProvider) + val endBounds = getIndicatorBounds(displayLayout, newType, bubbleBoundsProvider) + val animator = VisualIndicatorAnimator(view, startBounds, endBounds) + animator.interpolator = DecelerateInterpolator() + setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_NO_CHANGE_ANIM) + return animator + } + + /** Calculates the bounds the indicator should have when fully faded in. */ + private fun getIndicatorBounds( + layout: DisplayLayout, + type: IndicatorType, + bubbleBoundsProvider: BubbleDropTargetBoundsProvider?, + ): Rect { + val desktopStableBounds = Rect() + layout.getStableBounds(desktopStableBounds) + val padding = desktopStableBounds.top + when (type) { + IndicatorType.TO_FULLSCREEN_INDICATOR -> { + desktopStableBounds.top += padding + desktopStableBounds.bottom -= padding + desktopStableBounds.left += padding + desktopStableBounds.right -= padding + return desktopStableBounds + } + + IndicatorType.TO_DESKTOP_INDICATOR -> { + val adjustmentPercentage = + (1f - DesktopTasksController.DESKTOP_MODE_INITIAL_BOUNDS_SCALE) + return Rect( + (adjustmentPercentage * desktopStableBounds.width() / 2).toInt(), + (adjustmentPercentage * desktopStableBounds.height() / 2).toInt(), + (desktopStableBounds.width() - + (adjustmentPercentage * desktopStableBounds.width() / 2)) + .toInt(), + (desktopStableBounds.height() - + (adjustmentPercentage * desktopStableBounds.height() / 2)) + .toInt(), + ) + } + + IndicatorType.TO_SPLIT_LEFT_INDICATOR -> + return Rect( + padding, + padding, + desktopStableBounds.width() / 2 - padding, + desktopStableBounds.height(), + ) + + IndicatorType.TO_SPLIT_RIGHT_INDICATOR -> + return Rect( + desktopStableBounds.width() / 2 + padding, + padding, + desktopStableBounds.width() - padding, + desktopStableBounds.height(), + ) + IndicatorType.TO_BUBBLE_LEFT_INDICATOR -> + return bubbleBoundsProvider?.getBubbleBarExpandedViewDropTargetBounds( + /* onLeft= */ true + ) ?: Rect() + IndicatorType.TO_BUBBLE_RIGHT_INDICATOR -> + return bubbleBoundsProvider?.getBubbleBarExpandedViewDropTargetBounds( + /* onLeft= */ false + ) ?: Rect() + else -> throw IllegalArgumentException("Invalid indicator type provided.") + } + } + + /** Add necessary listener for animation of indicator */ + private fun setupIndicatorAnimation( + animator: VisualIndicatorAnimator, + animType: AlphaAnimType, + ) { + animator.addUpdateListener { a: ValueAnimator -> + animator.updateBounds(a.animatedFraction, animator.indicatorView) + if (animType == AlphaAnimType.ALPHA_FADE_IN_ANIM) { + animator.updateIndicatorAlpha(a.animatedFraction, animator.indicatorView) + } else if (animType == AlphaAnimType.ALPHA_FADE_OUT_ANIM) { + animator.updateIndicatorAlpha( + 1 - a.animatedFraction, + animator.indicatorView, + ) + } + } + animator.addListener( + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + animator.indicatorView.background.bounds = animator.indicatorEndBounds + } + } + ) + animator.setDuration(FULLSCREEN_INDICATOR_DURATION.toLong()) + } + + /** + * Return the minimum bounds of a visual indicator, to be used at the end of fading out + * and the start of fading in. + */ + private fun getMinBounds(maxBounds: Rect): Rect { + return Rect( + (maxBounds.left + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.width())) + .toInt(), + (maxBounds.top + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.height())) + .toInt(), + (maxBounds.right - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.width())) + .toInt(), + (maxBounds.bottom - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * maxBounds.height())) + .toInt(), + ) + } + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt index 5d8355625b94..f66451462e43 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt @@ -26,6 +26,8 @@ import android.view.View.LAYOUT_DIRECTION_RTL import com.android.window.flags.Flags import com.android.wm.shell.R import com.android.wm.shell.desktopmode.CaptionState +import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger +import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.DesktopUiEventEnum import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository import com.android.wm.shell.desktopmode.education.data.AppHandleEducationDatastoreRepository import com.android.wm.shell.shared.annotations.ShellBackgroundThread @@ -62,6 +64,7 @@ class AppHandleEducationController( private val windowingEducationViewController: DesktopWindowingEducationTooltipController, @ShellMainThread private val applicationCoroutineScope: CoroutineScope, @ShellBackgroundThread private val backgroundDispatcher: MainCoroutineDispatcher, + private val desktopModeUiEventLogger: DesktopModeUiEventLogger, ) { private lateinit var openHandleMenuCallback: (Int) -> Unit private lateinit var toDesktopModeCallback: (Int, DesktopModeTransitionSource) -> Unit @@ -171,6 +174,7 @@ class AppHandleEducationController( private fun showEducation(captionState: CaptionState) { val appHandleBounds = (captionState as CaptionState.AppHandle).globalAppHandleBounds + val taskInfo = captionState.runningTaskInfo val tooltipGlobalCoordinates = Point(appHandleBounds.left + appHandleBounds.width() / 2, appHandleBounds.bottom) // Populate information important to inflate app handle education tooltip. @@ -188,22 +192,34 @@ class AppHandleEducationController( arrowDirection = DesktopWindowingEducationTooltipController.TooltipArrowDirection.UP, onEducationClickAction = { - openHandleMenuCallback(captionState.runningTaskInfo.taskId) + openHandleMenuCallback(taskInfo.taskId) + desktopModeUiEventLogger.log( + taskInfo, + DesktopUiEventEnum.APP_HANDLE_EDUCATION_TOOLTIP_CLICKED, + ) }, onDismissAction = { - // TODO: b/341320146 - Log previous tooltip was dismissed + desktopModeUiEventLogger.log( + taskInfo, + DesktopUiEventEnum.APP_HANDLE_EDUCATION_TOOLTIP_DISMISSED, + ) }, ) windowingEducationViewController.showEducationTooltip( tooltipViewConfig = appHandleTooltipConfig, - taskId = captionState.runningTaskInfo.taskId, + taskId = taskInfo.taskId, + ) + desktopModeUiEventLogger.log( + taskInfo, + DesktopUiEventEnum.APP_HANDLE_EDUCATION_TOOLTIP_SHOWN, ) } /** Show tooltip that points to windowing image button in app handle menu */ private suspend fun showWindowingImageButtonTooltip(captionState: CaptionState.AppHandle) { val appInfoPillHeight = getSize(R.dimen.desktop_mode_handle_menu_app_info_pill_height) + val taskInfo = captionState.runningTaskInfo val windowingOptionPillHeight = getSize(R.dimen.desktop_mode_handle_menu_windowing_pill_height) val appHandleMenuWidth = @@ -245,24 +261,36 @@ class AppHandleEducationController( DesktopWindowingEducationTooltipController.TooltipArrowDirection.HORIZONTAL, onEducationClickAction = { toDesktopModeCallback( - captionState.runningTaskInfo.taskId, + taskInfo.taskId, DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON, ) + desktopModeUiEventLogger.log( + taskInfo, + DesktopUiEventEnum.ENTER_DESKTOP_MODE_EDUCATION_TOOLTIP_CLICKED, + ) }, onDismissAction = { - // TODO: b/341320146 - Log previous tooltip was dismissed + desktopModeUiEventLogger.log( + taskInfo, + DesktopUiEventEnum.ENTER_DESKTOP_MODE_EDUCATION_TOOLTIP_DISMISSED, + ) }, ) windowingEducationViewController.showEducationTooltip( - taskId = captionState.runningTaskInfo.taskId, + taskId = taskInfo.taskId, tooltipViewConfig = windowingImageButtonTooltipConfig, ) + desktopModeUiEventLogger.log( + taskInfo, + DesktopUiEventEnum.ENTER_DESKTOP_MODE_EDUCATION_TOOLTIP_SHOWN, + ) } /** Show tooltip that points to app chip button and educates user on how to exit desktop mode */ private suspend fun showExitWindowingTooltip(captionState: CaptionState.AppHeader) { val globalAppChipBounds = captionState.globalAppChipBounds + val taskInfo = captionState.runningTaskInfo val tooltipGlobalCoordinates = Point( if (isRtl()) { @@ -287,16 +315,27 @@ class AppHandleEducationController( arrowDirection = DesktopWindowingEducationTooltipController.TooltipArrowDirection.HORIZONTAL, onDismissAction = { - // TODO: b/341320146 - Log previous tooltip was dismissed + desktopModeUiEventLogger.log( + taskInfo, + DesktopUiEventEnum.EXIT_DESKTOP_MODE_EDUCATION_TOOLTIP_DISMISSED, + ) }, onEducationClickAction = { - openHandleMenuCallback(captionState.runningTaskInfo.taskId) + openHandleMenuCallback(taskInfo.taskId) + desktopModeUiEventLogger.log( + taskInfo, + DesktopUiEventEnum.EXIT_DESKTOP_MODE_EDUCATION_TOOLTIP_CLICKED, + ) }, ) windowingEducationViewController.showEducationTooltip( - taskId = captionState.runningTaskInfo.taskId, + taskId = taskInfo.taskId, tooltipViewConfig = exitWindowingTooltipConfig, ) + desktopModeUiEventLogger.log( + taskInfo, + DesktopUiEventEnum.EXIT_DESKTOP_MODE_EDUCATION_TOOLTIP_SHOWN, + ) } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java index 31715f0444a9..b60fb5e7bfdd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java @@ -93,7 +93,8 @@ public class FreeformTaskTransitionHandler } @Override - public IBinder startMinimizedModeTransition(WindowContainerTransaction wct) { + public IBinder startMinimizedModeTransition( + WindowContainerTransaction wct, int taskId, boolean isLastTask) { final int type = Transitions.TRANSIT_MINIMIZE; final IBinder token = mTransitions.startTransition(type, wct, this); mPendingTransitionTokens.add(token); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java index a874a5be426d..822934c1e646 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java @@ -38,10 +38,13 @@ public interface FreeformTaskTransitionStarter { * Starts window minimization transition * * @param wct the {@link WindowContainerTransaction} that changes the windowing mode + * @param taskId the task id of the task being minimized + * @param isLastTask true if the task being minimized is the last visible task * * @return the started transition */ - IBinder startMinimizedModeTransition(WindowContainerTransaction wct); + IBinder startMinimizedModeTransition( + WindowContainerTransaction wct, int taskId, boolean isLastTask); /** * Starts close window transition @@ -60,4 +63,4 @@ public interface FreeformTaskTransitionStarter { * @return the started transition */ IBinder startPipTransition(WindowContainerTransaction wct); -}
\ No newline at end of file +} 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 c0a0f469add4..d666126b91ba 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 @@ -22,7 +22,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.service.dreams.Flags.dismissDreamOnKeyguardDismiss; import static android.view.WindowManager.KEYGUARD_VISIBILITY_TRANSIT_FLAGS; -import static android.view.WindowManager.TRANSIT_FLAG_AOD_APPEARING; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED; @@ -201,8 +200,7 @@ public class KeyguardTransitionHandler transition, info, startTransaction, finishTransaction, finishCallback); } - if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_APPEARING) != 0 - || (info.getFlags() & TRANSIT_FLAG_AOD_APPEARING) != 0) { + if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_APPEARING) != 0) { return startAnimation(mAppearTransition, "appearing", transition, info, startTransaction, finishTransaction, finishCallback); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipAppIconOverlay.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipAppIconOverlay.java index b4cf8905d02e..88ac865c24b9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipAppIconOverlay.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipAppIconOverlay.java @@ -26,6 +26,7 @@ import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.hardware.HardwareBuffer; import android.util.TypedValue; import android.view.SurfaceControl; @@ -39,7 +40,6 @@ public final class PipAppIconOverlay extends PipContentOverlay { private final Context mContext; private final int mAppIconSizePx; - private final Rect mAppBounds; private final int mOverlayHalfSize; private final Matrix mTmpTransform = new Matrix(); private final float[] mTmpFloat9 = new float[9]; @@ -56,10 +56,6 @@ public final class PipAppIconOverlay extends PipContentOverlay { final int overlaySize = getOverlaySize(appBounds, destinationBounds); mOverlayHalfSize = overlaySize >> 1; - // When the activity is in the secondary split, make sure the scaling center is not - // offset. - mAppBounds = new Rect(0, 0, appBounds.width(), appBounds.height()); - mBitmap = Bitmap.createBitmap(overlaySize, overlaySize, Bitmap.Config.ARGB_8888); prepareAppIconOverlay(appIcon); mLeash = new SurfaceControl.Builder() @@ -85,12 +81,17 @@ public final class PipAppIconOverlay extends PipContentOverlay { @Override public void attach(SurfaceControl.Transaction tx, SurfaceControl parentLeash) { + final HardwareBuffer buffer = mBitmap.getHardwareBuffer(); tx.show(mLeash); tx.setLayer(mLeash, Integer.MAX_VALUE); - tx.setBuffer(mLeash, mBitmap.getHardwareBuffer()); + tx.setBuffer(mLeash, buffer); tx.setAlpha(mLeash, 0f); tx.reparent(mLeash, parentLeash); tx.apply(); + // Cleanup the bitmap and buffer after setting up the leash + mBitmap.recycle(); + mBitmap = null; + buffer.close(); } @Override @@ -108,16 +109,6 @@ public final class PipAppIconOverlay extends PipContentOverlay { .setAlpha(mLeash, fraction < 0.5f ? 0 : (fraction - 0.5f) * 2); } - - - @Override - public void detach(SurfaceControl.Transaction tx) { - super.detach(tx); - if (mBitmap != null && !mBitmap.isRecycled()) { - mBitmap.recycle(); - } - } - private void prepareAppIconOverlay(Drawable appIcon) { final Canvas canvas = new Canvas(); canvas.setBitmap(mBitmap); @@ -139,6 +130,8 @@ public final class PipAppIconOverlay extends PipContentOverlay { mOverlayHalfSize + mAppIconSizePx / 2); appIcon.setBounds(appIconBounds); appIcon.draw(canvas); + Bitmap oldBitmap = mBitmap; mBitmap = mBitmap.copy(Bitmap.Config.HARDWARE, false /* mutable */); + oldBitmap.recycle(); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDragToResizeHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDragToResizeHandler.java new file mode 100644 index 000000000000..bd0b810b2a44 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDragToResizeHandler.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2025 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.pip2.phone; + +import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_BOTTOM; +import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_LEFT; +import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_RIGHT; +import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_TOP; +import static com.android.wm.shell.pip2.phone.PipMenuView.ANIM_TYPE_NONE; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Point; +import android.graphics.PointF; +import android.graphics.Rect; +import android.graphics.Region; +import android.view.MotionEvent; + +import com.android.internal.policy.TaskResizingAlgorithm; +import com.android.wm.shell.R; +import com.android.wm.shell.common.pip.PipBoundsAlgorithm; +import com.android.wm.shell.common.pip.PipBoundsState; + +import java.util.function.Function; + +/** Helper for handling drag-corner-to-resize gestures. */ +public class PipDragToResizeHandler { + private final Context mContext; + private final PipResizeGestureHandler mPipResizeGestureHandler; + private final PipBoundsState mPipBoundsState; + private final PhonePipMenuController mPhonePipMenuController; + private final PipBoundsAlgorithm mPipBoundsAlgorithm; + private final PipScheduler mPipScheduler; + + private final Region mTmpRegion = new Region(); + private final Rect mDragCornerSize = new Rect(); + private final Rect mTmpTopLeftCorner = new Rect(); + private final Rect mTmpTopRightCorner = new Rect(); + private final Rect mTmpBottomLeftCorner = new Rect(); + private final Rect mTmpBottomRightCorner = new Rect(); + private final Rect mDisplayBounds = new Rect(); + private final Function<Rect, Rect> mMovementBoundsSupplier; + private int mDelta; + + public PipDragToResizeHandler(Context context, PipResizeGestureHandler pipResizeGestureHandler, + PipBoundsState pipBoundsState, + PhonePipMenuController phonePipMenuController, PipBoundsAlgorithm pipBoundsAlgorithm, + PipScheduler pipScheduler, Function<Rect, Rect> movementBoundsSupplier) { + mContext = context; + mPipResizeGestureHandler = pipResizeGestureHandler; + mPipBoundsState = pipBoundsState; + mPhonePipMenuController = phonePipMenuController; + mPipBoundsAlgorithm = pipBoundsAlgorithm; + mPipScheduler = pipScheduler; + mMovementBoundsSupplier = movementBoundsSupplier; + } + + /** Invoked by {@link PipResizeGestureHandler#reloadResources}. */ + void reloadResources() { + final Resources res = mContext.getResources(); + mDelta = res.getDimensionPixelSize(R.dimen.pip_resize_edge_size); + } + + /** Invoked by {@link PipResizeGestureHandler#onInputEvent} if drag-corner-to-resize is + * enabled. */ + void onDragCornerResize(MotionEvent ev, Rect lastResizeBounds, PointF downPoint, + Rect downBounds, Point minSize, Point maxSize, float touchSlop) { + int action = ev.getActionMasked(); + float x = ev.getX(); + float y = ev.getY(); + if (action == MotionEvent.ACTION_DOWN) { + lastResizeBounds.setEmpty(); + final boolean allowGesture = isWithinDragResizeRegion((int) x, (int) y); + mPipResizeGestureHandler.setAllowGesture(allowGesture); + if (allowGesture) { + setCtrlType((int) x, (int) y); + downPoint.set(x, y); + downBounds.set(mPipBoundsState.getBounds()); + } + } else if (mPipResizeGestureHandler.getAllowGesture()) { + switch (action) { + case MotionEvent.ACTION_POINTER_DOWN: + // We do not support multi touch for resizing via drag + mPipResizeGestureHandler.setAllowGesture(false); + break; + case MotionEvent.ACTION_MOVE: + final boolean thresholdCrossed = mPipResizeGestureHandler.getThresholdCrossed(); + // Capture inputs + if (!mPipResizeGestureHandler.getThresholdCrossed() + && Math.hypot(x - downPoint.x, y - downPoint.y) > touchSlop) { + mPipResizeGestureHandler.setThresholdCrossed(true); + // Reset the down to begin resizing from this point + downPoint.set(x, y); + mPipResizeGestureHandler.pilferPointers(); + } + if (mPipResizeGestureHandler.getThresholdCrossed()) { + if (mPhonePipMenuController.isMenuVisible()) { + mPhonePipMenuController.hideMenu(ANIM_TYPE_NONE, + false /* resize */); + } + final Rect currentPipBounds = mPipBoundsState.getBounds(); + lastResizeBounds.set(TaskResizingAlgorithm.resizeDrag(x, y, + downPoint.x, downPoint.y, currentPipBounds, + mPipResizeGestureHandler.getCtrlType(), minSize.x, + minSize.y, maxSize, true, + downBounds.width() > downBounds.height())); + mPipBoundsAlgorithm.transformBoundsToAspectRatio(lastResizeBounds, + mPipBoundsState.getAspectRatio(), false /* useCurrentMinEdgeSize */, + true /* useCurrentSize */); + mPipScheduler.scheduleUserResizePip(lastResizeBounds); + mPipBoundsState.setHasUserResizedPip(true); + } + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + mPipResizeGestureHandler.finishResize(); + break; + } + } + } + + /** + * Check whether the current x,y coordinate is within the region in which drag-resize should + * start. + * This consists of 4 small squares on the 4 corners of the PIP window, a quarter of which + * overlaps with the PIP window while the rest goes outside of the PIP window. + * _ _ _ _ + * |_|_|_________|_|_| + * |_|_| |_|_| + * | PIP | + * | WINDOW | + * _|_ _|_ + * |_|_|_________|_|_| + * |_|_| |_|_| + */ + boolean isWithinDragResizeRegion(int x, int y) { + final Rect currentPipBounds = mPipBoundsState.getBounds(); + if (currentPipBounds == null) { + return false; + } + resetDragCorners(); + mTmpTopLeftCorner.offset(currentPipBounds.left - mDelta / 2, + currentPipBounds.top - mDelta / 2); + mTmpTopRightCorner.offset(currentPipBounds.right - mDelta / 2, + currentPipBounds.top - mDelta / 2); + mTmpBottomLeftCorner.offset(currentPipBounds.left - mDelta / 2, + currentPipBounds.bottom - mDelta / 2); + mTmpBottomRightCorner.offset(currentPipBounds.right - mDelta / 2, + currentPipBounds.bottom - mDelta / 2); + + mTmpRegion.setEmpty(); + mTmpRegion.op(mTmpTopLeftCorner, Region.Op.UNION); + mTmpRegion.op(mTmpTopRightCorner, Region.Op.UNION); + mTmpRegion.op(mTmpBottomLeftCorner, Region.Op.UNION); + mTmpRegion.op(mTmpBottomRightCorner, Region.Op.UNION); + + return mTmpRegion.contains(x, y); + } + + private void resetDragCorners() { + mDragCornerSize.set(0, 0, mDelta, mDelta); + mTmpTopLeftCorner.set(mDragCornerSize); + mTmpTopRightCorner.set(mDragCornerSize); + mTmpBottomLeftCorner.set(mDragCornerSize); + mTmpBottomRightCorner.set(mDragCornerSize); + } + + private void setCtrlType(int x, int y) { + final Rect currentPipBounds = mPipBoundsState.getBounds(); + int ctrlType = mPipResizeGestureHandler.getCtrlType(); + + Rect movementBounds = mMovementBoundsSupplier.apply(currentPipBounds); + + mDisplayBounds.set(movementBounds.left, + movementBounds.top, + movementBounds.right + currentPipBounds.width(), + movementBounds.bottom + currentPipBounds.height()); + + if (mTmpTopLeftCorner.contains(x, y) && currentPipBounds.top != mDisplayBounds.top + && currentPipBounds.left != mDisplayBounds.left) { + ctrlType |= CTRL_LEFT; + ctrlType |= CTRL_TOP; + } + if (mTmpTopRightCorner.contains(x, y) && currentPipBounds.top != mDisplayBounds.top + && currentPipBounds.right != mDisplayBounds.right) { + ctrlType |= CTRL_RIGHT; + ctrlType |= CTRL_TOP; + } + if (mTmpBottomRightCorner.contains(x, y) + && currentPipBounds.bottom != mDisplayBounds.bottom + && currentPipBounds.right != mDisplayBounds.right) { + ctrlType |= CTRL_RIGHT; + ctrlType |= CTRL_BOTTOM; + } + if (mTmpBottomLeftCorner.contains(x, y) + && currentPipBounds.bottom != mDisplayBounds.bottom + && currentPipBounds.left != mDisplayBounds.left) { + ctrlType |= CTRL_LEFT; + ctrlType |= CTRL_BOTTOM; + } + + mPipResizeGestureHandler.setCtrlType(ctrlType); + } + +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipPinchToResizeHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipPinchToResizeHandler.java new file mode 100644 index 000000000000..1e41af379864 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipPinchToResizeHandler.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2025 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.pip2.phone; + +import android.graphics.Point; +import android.graphics.PointF; +import android.graphics.Rect; +import android.view.MotionEvent; + +import com.android.wm.shell.common.pip.PipBoundsState; +import com.android.wm.shell.common.pip.PipPinchResizingAlgorithm; + +/** Helper for handling pinch-to-resize gestures. */ +public class PipPinchToResizeHandler { + private final PipResizeGestureHandler mPipResizeGestureHandler; + private final PipBoundsState mPipBoundsState; + private final PhonePipMenuController mPhonePipMenuController; + private final PipScheduler mPipScheduler; + private final PipPinchResizingAlgorithm mPinchResizingAlgorithm; + + private int mFirstIndex = -1; + private int mSecondIndex = -1; + + public PipPinchToResizeHandler(PipResizeGestureHandler pipResizeGestureHandler, + PipBoundsState pipBoundsState, PhonePipMenuController phonePipMenuController, + PipScheduler pipScheduler) { + mPipResizeGestureHandler = pipResizeGestureHandler; + mPipBoundsState = pipBoundsState; + mPhonePipMenuController = phonePipMenuController; + mPipScheduler = pipScheduler; + + mPinchResizingAlgorithm = new PipPinchResizingAlgorithm(); + } + + /** Invoked by {@link PipResizeGestureHandler#onInputEvent} if pinch-to-resize is enabled. */ + void onPinchResize(MotionEvent ev, PointF downPoint, PointF downSecondPoint, Rect downBounds, + PointF lastPoint, PointF lastSecondPoint, Rect lastResizeBounds, float touchSlop, + Point minSize, Point maxSize) { + int action = ev.getActionMasked(); + + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + mFirstIndex = -1; + mSecondIndex = -1; + mPipResizeGestureHandler.setAllowGesture(false); + mPipResizeGestureHandler.finishResize(); + } + + if (ev.getPointerCount() != 2) { + return; + } + + final Rect pipBounds = mPipBoundsState.getBounds(); + if (action == MotionEvent.ACTION_POINTER_DOWN) { + if (mFirstIndex == -1 && mSecondIndex == -1 + && pipBounds.contains((int) ev.getRawX(0), (int) ev.getRawY(0)) + && pipBounds.contains((int) ev.getRawX(1), (int) ev.getRawY(1))) { + mPipResizeGestureHandler.setAllowGesture(true); + mFirstIndex = 0; + mSecondIndex = 1; + downPoint.set(ev.getRawX(mFirstIndex), ev.getRawY(mFirstIndex)); + downSecondPoint.set(ev.getRawX(mSecondIndex), ev.getRawY(mSecondIndex)); + downBounds.set(pipBounds); + + lastPoint.set(downPoint); + lastSecondPoint.set(lastSecondPoint); + lastResizeBounds.set(downBounds); + + // start the high perf session as the second pointer gets detected + mPipResizeGestureHandler.startHighPerfSession(); + } + } + + if (action == MotionEvent.ACTION_MOVE) { + if (mFirstIndex == -1 || mSecondIndex == -1) { + return; + } + + float x0 = ev.getRawX(mFirstIndex); + float y0 = ev.getRawY(mFirstIndex); + float x1 = ev.getRawX(mSecondIndex); + float y1 = ev.getRawY(mSecondIndex); + lastPoint.set(x0, y0); + lastSecondPoint.set(x1, y1); + + // Capture inputs + if (!mPipResizeGestureHandler.getThresholdCrossed() + && (distanceBetween(downSecondPoint, lastSecondPoint) > touchSlop + || distanceBetween(downPoint, lastPoint) > touchSlop)) { + mPipResizeGestureHandler.pilferPointers(); + mPipResizeGestureHandler.setThresholdCrossed(true); + // Reset the down to begin resizing from this point + downPoint.set(lastPoint); + downSecondPoint.set(lastSecondPoint); + + if (mPhonePipMenuController.isMenuVisible()) { + mPhonePipMenuController.hideMenu(); + } + } + + if (mPipResizeGestureHandler.getThresholdCrossed()) { + final float angle = mPinchResizingAlgorithm.calculateBoundsAndAngle(downPoint, + downSecondPoint, lastPoint, lastSecondPoint, minSize, maxSize, + downBounds, lastResizeBounds); + + mPipResizeGestureHandler.setAngle(angle); + mPipScheduler.scheduleUserResizePip(lastResizeBounds, angle); + mPipBoundsState.setHasUserResizedPip(true); + } + } + } + + private float distanceBetween(PointF p1, PointF p2) { + return (float) Math.hypot(p2.x - p1.x, p2.y - p1.y); + } + +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java index e4be3f60f86e..b869bf153c34 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java @@ -44,13 +44,14 @@ import com.android.wm.shell.R; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.pip.PipBoundsAlgorithm; import com.android.wm.shell.common.pip.PipBoundsState; +import com.android.wm.shell.common.pip.PipDesktopState; import com.android.wm.shell.common.pip.PipDisplayLayoutState; import com.android.wm.shell.common.pip.PipPerfHintController; -import com.android.wm.shell.common.pip.PipPinchResizingAlgorithm; import com.android.wm.shell.common.pip.PipUiEventLogger; import com.android.wm.shell.pip2.animation.PipResizeAnimator; import java.io.PrintWriter; +import java.util.function.Function; /** * Helper on top of PipTouchHandler that handles inputs OUTSIDE of the PIP window, which is used to @@ -72,8 +73,8 @@ public class PipResizeGestureHandler implements private final PipTransitionState mPipTransitionState; private final PhonePipMenuController mPhonePipMenuController; private final PipDisplayLayoutState mPipDisplayLayoutState; + private final PipDesktopState mPipDesktopState; private final PipUiEventLogger mPipUiEventLogger; - private final PipPinchResizingAlgorithm mPinchResizingAlgorithm; private final ShellExecutor mMainExecutor; private final PointF mDownPoint = new PointF(); @@ -93,16 +94,18 @@ public class PipResizeGestureHandler implements private boolean mIsAttached; private boolean mIsEnabled; private boolean mEnablePinchResize; + private boolean mEnableDragCornerResize; private boolean mIsSysUiStateValid; private boolean mThresholdCrossed; private boolean mOngoingPinchToResize = false; private boolean mWaitingForBoundsChangeTransition = false; private float mAngle = 0; - int mFirstIndex = -1; - int mSecondIndex = -1; + private InputMonitor mInputMonitor; private InputEventReceiver mInputEventReceiver; + private PipDragToResizeHandler mPipDragToResizeHandler; + private PipPinchToResizeHandler mPipPinchToResizeHandler; @Nullable private final PipPerfHintController mPipPerfHintController; @@ -121,7 +124,9 @@ public class PipResizeGestureHandler implements PipTransitionState pipTransitionState, PipUiEventLogger pipUiEventLogger, PhonePipMenuController menuActivityController, + Function<Rect, Rect> movementBoundsSupplier, PipDisplayLayoutState pipDisplayLayoutState, + PipDesktopState pipDesktopState, ShellExecutor mainExecutor, @Nullable PipPerfHintController pipPerfHintController) { mContext = context; @@ -137,8 +142,13 @@ public class PipResizeGestureHandler implements mPhonePipMenuController = menuActivityController; mPipDisplayLayoutState = pipDisplayLayoutState; + mPipDesktopState = pipDesktopState; mPipUiEventLogger = pipUiEventLogger; - mPinchResizingAlgorithm = new PipPinchResizingAlgorithm(); + + mPipDragToResizeHandler = new PipDragToResizeHandler(context, this, pipBoundsState, + menuActivityController, pipBoundsAlgorithm, pipScheduler, movementBoundsSupplier); + mPipPinchToResizeHandler = new PipPinchToResizeHandler(this, pipBoundsState, + menuActivityController, pipScheduler); } void init() { @@ -163,6 +173,7 @@ public class PipResizeGestureHandler implements } private void reloadResources() { + mPipDragToResizeHandler.reloadResources(); mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop(); } @@ -180,6 +191,8 @@ public class PipResizeGestureHandler implements void onActivityPinned() { mIsAttached = true; updateIsEnabled(); + // Only enable drag-corner-to-resize if PiP was entered when Desktop Mode session is active. + mEnableDragCornerResize = mPipDesktopState.isPipInDesktopMode(); } void onActivityUnpinned() { @@ -211,9 +224,44 @@ public class PipResizeGestureHandler implements } } + boolean getAllowGesture() { + return mAllowGesture; + } + + void setAllowGesture(boolean allowGesture) { + mAllowGesture = allowGesture; + } + + boolean getThresholdCrossed() { + return mThresholdCrossed; + } + + void setThresholdCrossed(boolean thresholdCrossed) { + mThresholdCrossed = thresholdCrossed; + } + + int getCtrlType() { + return mCtrlType; + } + + void setCtrlType(int ctrlType) { + mCtrlType = ctrlType; + } + + void setAngle(float angle) { + mAngle = angle; + } + + void startHighPerfSession() { + if (mPipPerfHintController != null) { + mPipHighPerfSession = mPipPerfHintController.startSession( + this::onHighPerfSessionTimeout, "onPinchResize"); + } + } + @VisibleForTesting void onInputEvent(InputEvent ev) { - if (!mEnablePinchResize) { + if (!mEnableDragCornerResize && !mEnablePinchResize) { // No need to handle anything if resizing isn't enabled. return; } @@ -240,7 +288,12 @@ public class PipResizeGestureHandler implements } if (mOngoingPinchToResize) { - onPinchResize(mv); + mPipPinchToResizeHandler.onPinchResize(mv, mDownPoint, mDownSecondPoint, + mDownBounds, mLastPoint, mLastSecondPoint, mLastResizeBounds, mTouchSlop, + mMinSize, mMaxSize); + } else if (mEnableDragCornerResize) { + mPipDragToResizeHandler.onDragCornerResize(mv, mLastResizeBounds, mDownPoint, + mDownBounds, mMinSize, mMaxSize, mTouchSlop); } } } @@ -261,20 +314,31 @@ public class PipResizeGestureHandler implements } boolean willStartResizeGesture(MotionEvent ev) { - if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) { - if (mEnablePinchResize && ev.getPointerCount() == 2) { - onPinchResize(ev); - mOngoingPinchToResize = mAllowGesture; - return mAllowGesture; - } + switch (ev.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + if (mEnableDragCornerResize && mPipDragToResizeHandler.isWithinDragResizeRegion( + (int) ev.getRawX(), + (int) ev.getRawY())) { + return true; + } + break; + + case MotionEvent.ACTION_POINTER_DOWN: + if (mEnablePinchResize && ev.getPointerCount() == 2) { + mPipPinchToResizeHandler.onPinchResize(ev, mDownPoint, mDownSecondPoint, + mDownBounds, mLastPoint, mLastSecondPoint, mLastResizeBounds, + mTouchSlop, mMinSize, mMaxSize); + mOngoingPinchToResize = mAllowGesture; + return mAllowGesture; + } + break; + + default: + break; } return false; } - private boolean isInValidSysUiState() { - return mIsSysUiStateValid; - } - private void onHighPerfSessionTimeout(PipPerfHintController.PipHighPerfSession session) {} private void cleanUpHighPerfSessionMaybe() { @@ -285,83 +349,6 @@ public class PipResizeGestureHandler implements } } - @VisibleForTesting - void onPinchResize(MotionEvent ev) { - int action = ev.getActionMasked(); - - if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { - mFirstIndex = -1; - mSecondIndex = -1; - mAllowGesture = false; - finishResize(); - } - - if (ev.getPointerCount() != 2) { - return; - } - - final Rect pipBounds = mPipBoundsState.getBounds(); - if (action == MotionEvent.ACTION_POINTER_DOWN) { - if (mFirstIndex == -1 && mSecondIndex == -1 - && pipBounds.contains((int) ev.getRawX(0), (int) ev.getRawY(0)) - && pipBounds.contains((int) ev.getRawX(1), (int) ev.getRawY(1))) { - mAllowGesture = true; - mFirstIndex = 0; - mSecondIndex = 1; - mDownPoint.set(ev.getRawX(mFirstIndex), ev.getRawY(mFirstIndex)); - mDownSecondPoint.set(ev.getRawX(mSecondIndex), ev.getRawY(mSecondIndex)); - mDownBounds.set(pipBounds); - - mLastPoint.set(mDownPoint); - mLastSecondPoint.set(mLastSecondPoint); - mLastResizeBounds.set(mDownBounds); - - // start the high perf session as the second pointer gets detected - if (mPipPerfHintController != null) { - mPipHighPerfSession = mPipPerfHintController.startSession( - this::onHighPerfSessionTimeout, "onPinchResize"); - } - } - } - - if (action == MotionEvent.ACTION_MOVE) { - if (mFirstIndex == -1 || mSecondIndex == -1) { - return; - } - - float x0 = ev.getRawX(mFirstIndex); - float y0 = ev.getRawY(mFirstIndex); - float x1 = ev.getRawX(mSecondIndex); - float y1 = ev.getRawY(mSecondIndex); - mLastPoint.set(x0, y0); - mLastSecondPoint.set(x1, y1); - - // Capture inputs - if (!mThresholdCrossed - && (distanceBetween(mDownSecondPoint, mLastSecondPoint) > mTouchSlop - || distanceBetween(mDownPoint, mLastPoint) > mTouchSlop)) { - pilferPointers(); - mThresholdCrossed = true; - // Reset the down to begin resizing from this point - mDownPoint.set(mLastPoint); - mDownSecondPoint.set(mLastSecondPoint); - - if (mPhonePipMenuController.isMenuVisible()) { - mPhonePipMenuController.hideMenu(); - } - } - - if (mThresholdCrossed) { - mAngle = mPinchResizingAlgorithm.calculateBoundsAndAngle(mDownPoint, - mDownSecondPoint, mLastPoint, mLastSecondPoint, mMinSize, mMaxSize, - mDownBounds, mLastResizeBounds); - - mPipScheduler.scheduleUserResizePip(mLastResizeBounds, mAngle); - mPipBoundsState.setHasUserResizedPip(true); - } - } - } - private void snapToMovementBoundsEdge(Rect bounds, Rect movementBounds) { final int leftEdge = bounds.left; @@ -404,17 +391,21 @@ public class PipResizeGestureHandler implements // mPipTaskOrganizer.scheduleFinishResizePip(finalBounds, mUpdateResizeBoundsCallback); } - private void finishResize() { + /** Handles additional resizing and state changes after gesture resizing is done. */ + void finishResize() { if (mLastResizeBounds.isEmpty()) { resetState(); } - if (!mOngoingPinchToResize) { - return; - } // Cache initial bounds after release for animation before mLastResizeBounds are modified. mStartBoundsAfterRelease.set(mLastResizeBounds); + // Drag-corner-to-resize - we don't need to adjust the bounds at this point + if (!mOngoingPinchToResize) { + scheduleBoundsChange(); + return; + } + // If user resize is pretty close to max size, just auto resize to max. if (mLastResizeBounds.width() >= PINCH_RESIZE_AUTO_MAX_RATIO * mMaxSize.x || mLastResizeBounds.height() >= PINCH_RESIZE_AUTO_MAX_RATIO * mMaxSize.y) { @@ -438,6 +429,10 @@ public class PipResizeGestureHandler implements mLastResizeBounds, movementBounds); mPipBoundsAlgorithm.applySnapFraction(mLastResizeBounds, snapFraction); + scheduleBoundsChange(); + } + + private void scheduleBoundsChange() { // Update the transition state to schedule a resize transition. Bundle extra = new Bundle(); extra.putBoolean(RESIZE_BOUNDS_CHANGE, true); @@ -489,10 +484,6 @@ public class PipResizeGestureHandler implements mOhmOffset = offset; } - private float distanceBetween(PointF p1, PointF p2) { - return (float) Math.hypot(p2.x - p1.x, p2.y - p1.y); - } - private void resizeRectAboutCenter(Rect rect, int w, int h) { int cx = rect.centerX(); int cy = rect.centerY(); @@ -573,6 +564,7 @@ public class PipResizeGestureHandler implements pw.println(innerPrefix + "mIsAttached=" + mIsAttached); pw.println(innerPrefix + "mIsEnabled=" + mIsEnabled); pw.println(innerPrefix + "mEnablePinchResize=" + mEnablePinchResize); + pw.println(innerPrefix + "mEnableDragCornerResize=" + mEnableDragCornerResize); pw.println(innerPrefix + "mThresholdCrossed=" + mThresholdCrossed); pw.println(innerPrefix + "mOhmOffset=" + mOhmOffset); pw.println(innerPrefix + "mMinSize=" + mMinSize); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java index e405f3339054..72346b335a8e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java @@ -59,6 +59,7 @@ import com.android.wm.shell.common.FloatingContentCoordinator; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.pip.PipBoundsAlgorithm; import com.android.wm.shell.common.pip.PipBoundsState; +import com.android.wm.shell.common.pip.PipDesktopState; import com.android.wm.shell.common.pip.PipDisplayLayoutState; import com.android.wm.shell.common.pip.PipDoubleTapHelper; import com.android.wm.shell.common.pip.PipPerfHintController; @@ -187,6 +188,7 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha @NonNull PipScheduler pipScheduler, @NonNull SizeSpecSource sizeSpecSource, @NonNull PipDisplayLayoutState pipDisplayLayoutState, + PipDesktopState pipDesktopState, DisplayController displayController, PipMotionHelper pipMotionHelper, FloatingContentCoordinator floatingContentCoordinator, @@ -226,7 +228,8 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha mainExecutor); mPipResizeGestureHandler = new PipResizeGestureHandler(context, pipBoundsAlgorithm, pipBoundsState, mTouchState, mPipScheduler, mPipTransitionState, pipUiEventLogger, - menuController, mPipDisplayLayoutState, mainExecutor, mPipPerfHintController); + menuController, this::getMovementBounds, mPipDisplayLayoutState, pipDesktopState, + mainExecutor, mPipPerfHintController); mPipBoundsState.addOnAspectRatioChangedCallback(aspectRatio -> { updateMinMaxSize(aspectRatio); onAspectRatioChanged(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java index bb9b479524e5..9adaa3614a0f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java @@ -72,7 +72,6 @@ import com.android.wm.shell.pip2.animation.PipAlphaAnimator; import com.android.wm.shell.pip2.animation.PipEnterAnimator; import com.android.wm.shell.pip2.animation.PipExpandAnimator; import com.android.wm.shell.shared.TransitionUtil; -import com.android.wm.shell.shared.pip.PipContentOverlay; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; @@ -301,6 +300,9 @@ public class PipTransition extends PipTransitionController implements mPipTransitionState.setState(PipTransitionState.EXITING_PIP); return startRemoveAnimation(info, startTransaction, finishTransaction, finishCallback); } + // For any unhandled transition, make sure the PiP surface is properly updated, + // i.e. corner and shadow radius. + syncPipSurfaceState(info, startTransaction, finishTransaction); return false; } @@ -422,7 +424,7 @@ public class PipTransition extends PipTransitionController implements final Rect destinationBounds = pipChange.getEndAbsBounds(); final SurfaceControl swipePipToHomeOverlay = mPipTransitionState.getSwipePipToHomeOverlay(); if (swipePipToHomeOverlay != null) { - final int overlaySize = PipContentOverlay.PipAppIconOverlay.getOverlaySize( + final int overlaySize = PipAppIconOverlay.getOverlaySize( mPipTransitionState.getSwipePipToHomeAppBounds(), destinationBounds); // It is possible we reparent the PIP activity to a new PIP task (in multi-activity // apps), so we should also reparent the overlay to the final PIP task. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentsAnimationRunner.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentsAnimationRunner.aidl index 8cdb8c4512a9..f8d84e4f3c21 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentsAnimationRunner.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentsAnimationRunner.aidl @@ -59,11 +59,12 @@ oneway interface IRecentsAnimationRunner { void onAnimationStart(in IRecentsAnimationController controller, in RemoteAnimationTarget[] apps, in RemoteAnimationTarget[] wallpapers, in Rect homeContentInsets, in Rect minimizedHomeBounds, in Bundle extras, - in TransitionInfo info) = 2; + in @nullable TransitionInfo info) = 2; /** * Called when the task of an activity that has been started while the recents animation * was running becomes ready for control. */ - void onTasksAppeared(in RemoteAnimationTarget[] app) = 3; + void onTasksAppeared(in RemoteAnimationTarget[] app, + in @nullable TransitionInfo transitionInfo) = 3; } 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 7751741ae082..a969845fb8e8 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 @@ -1214,13 +1214,16 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, // Since we're accepting the merge, update the finish transaction so that changes via // that transaction will be applied on top of those of the merged transitions mFinishTransaction = finishT; - // not using the incoming anim-only surfaces - info.releaseAnimSurfaces(); + boolean passTransitionInfo = ENABLE_DESKTOP_RECENTS_TRANSITIONS_CORNERS_BUGFIX.isTrue(); + if (!passTransitionInfo) { + // not using the incoming anim-only surfaces + info.releaseAnimSurfaces(); + } if (appearedTargets != null) { try { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "[%d] RecentsController.merge: calling onTasksAppeared", mInstanceId); - mListener.onTasksAppeared(appearedTargets); + mListener.onTasksAppeared(appearedTargets, passTransitionInfo ? info : null); } catch (RemoteException e) { Slog.e(TAG, "Error sending appeared tasks to recents animation", e); } 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 e9f8a4a86d27..ba30d924e0b1 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 @@ -638,6 +638,14 @@ public class SplitScreenController implements SplitDragPolicy.Starter, } /** + * Starts an existing task via StageCoordinator. + */ + public void startTask(int taskId, @SplitPosition int position, @Nullable Bundle options, + @Nullable WindowContainerToken hideTaskToken, @SplitIndex int index) { + mStageCoordinator.startTask(taskId, position, options, hideTaskToken, index); + } + + /** * See {@link #startShortcut(String, String, int, Bundle, UserHandle)} * @param instanceId to be used by {@link SplitscreenEventLogger} */ 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 15ac03ccaf30..a799b7f2580e 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 @@ -2859,14 +2859,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, prepareExitSplitScreen(dismissTop, out, EXIT_REASON_APP_FINISHED); mSplitTransitions.setDismissTransition(transition, dismissTop, EXIT_REASON_APP_FINISHED); - } else if (isOpening && !mPausingTasks.isEmpty()) { - // One of the splitting task is opening while animating the split pair in - // recents, which means to dismiss the split pair to this task. - int dismissTop = getStageType(stage) == STAGE_TYPE_MAIN - ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE; - prepareExitSplitScreen(dismissTop, out, EXIT_REASON_APP_FINISHED); - mSplitTransitions.setDismissTransition(transition, dismissTop, - EXIT_REASON_APP_FINISHED); } else if (!isSplitScreenVisible() && isOpening) { // If split is running in the background and the trigger task is appearing into // split, prepare to enter split screen. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java index a5a5fd73d5c0..01428e60582e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java @@ -149,8 +149,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { private Drawable mEnterpriseThumbnailDrawable; - static final InteractionJankMonitor sInteractionJankMonitor = - InteractionJankMonitor.getInstance(); + final InteractionJankMonitor mInteractionJankMonitor; private BroadcastReceiver mEnterpriseResourceUpdatedReceiver = new BroadcastReceiver() { @Override @@ -169,7 +168,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { @NonNull TransactionPool transactionPool, @NonNull ShellExecutor mainExecutor, @NonNull Handler mainHandler, @NonNull ShellExecutor animExecutor, - @NonNull RootTaskDisplayAreaOrganizer rootTDAOrganizer) { + @NonNull RootTaskDisplayAreaOrganizer rootTDAOrganizer, + @NonNull InteractionJankMonitor interactionJankMonitor) { mDisplayController = displayController; mTransactionPool = transactionPool; mContext = context; @@ -181,6 +181,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class); shellInit.addInitCallback(this::onInit, this); mRootTDAOrganizer = rootTDAOrganizer; + mInteractionJankMonitor = interactionJankMonitor; } private void onInit() { @@ -331,14 +332,14 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { final boolean isTaskTransition = isTaskTransition(info); if (isTaskTransition) { - sInteractionJankMonitor.begin(info.getRoot(0).getLeash(), mContext, + mInteractionJankMonitor.begin(info.getRoot(0).getLeash(), mContext, mMainHandler, CUJ_DEFAULT_TASK_TO_TASK_ANIMATION); } final Runnable onAnimFinish = () -> { if (!animations.isEmpty()) return; if (isTaskTransition) { - sInteractionJankMonitor.end(CUJ_DEFAULT_TASK_TO_TASK_ANIMATION); + mInteractionJankMonitor.end(CUJ_DEFAULT_TASK_TO_TASK_ANIMATION); } mAnimations.remove(transition); finishCallback.onTransitionFinished(null /* wct */); @@ -1031,6 +1032,6 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { @Override public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted, @Nullable SurfaceControl.Transaction finishTransaction) { - sInteractionJankMonitor.cancel(CUJ_DEFAULT_TASK_TO_TASK_ANIMATION); + mInteractionJankMonitor.cancel(CUJ_DEFAULT_TASK_TO_TASK_ANIMATION); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index c90f6cf62b7e..e28a7fa159c5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -77,6 +77,7 @@ import androidx.annotation.BinderThread; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.protolog.ProtoLog; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; @@ -196,6 +197,9 @@ public class Transitions implements RemoteCallable<Transitions>, /** Transition type for app compat reachability. */ public static final int TRANSIT_MOVE_LETTERBOX_REACHABILITY = TRANSIT_FIRST_CUSTOM + 23; + /** Transition type for converting a task to a bubble. */ + public static final int TRANSIT_CONVERT_TO_BUBBLE = TRANSIT_FIRST_CUSTOM + 24; + /** Transition type for desktop mode transitions. */ public static final int TRANSIT_DESKTOP_MODE_TYPES = WindowManager.TRANSIT_FIRST_CUSTOM + 100; @@ -335,7 +339,8 @@ public class Transitions implements RemoteCallable<Transitions>, mDisplayController = displayController; mPlayerImpl = new TransitionPlayerImpl(); mDefaultTransitionHandler = new DefaultTransitionHandler(context, shellInit, - displayController, pool, mainExecutor, mainHandler, animExecutor, rootTDAOrganizer); + displayController, pool, mainExecutor, mainHandler, animExecutor, rootTDAOrganizer, + InteractionJankMonitor.getInstance()); mRemoteTransitionHandler = new RemoteTransitionHandler(mMainExecutor); mShellCommandHandler = shellCommandHandler; mShellController = shellController; @@ -1867,6 +1872,7 @@ public class Transitions implements RemoteCallable<Transitions>, case TRANSIT_MINIMIZE -> "MINIMIZE"; case TRANSIT_START_RECENTS_TRANSITION -> "START_RECENTS_TRANSITION"; case TRANSIT_END_RECENTS_TRANSITION -> "END_RECENTS_TRANSITION"; + case TRANSIT_CONVERT_TO_BUBBLE -> "CONVERT_TO_BUBBLE"; default -> ""; }; if (typeStr.isEmpty()) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java index 7aa00370ff58..dd5439a8aa10 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java @@ -389,7 +389,9 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel, FocusT } else if (id == R.id.back_button) { mTaskOperations.injectBackKey(mDisplayId); } else if (id == R.id.minimize_window) { - mTaskOperations.minimizeTask(mTaskToken); + // This minimize button uses the same effect for any minimization. The last argument + // doesn't matter. + mTaskOperations.minimizeTask(mTaskToken, mTaskId, /* isLastTask= */ false); } else if (id == R.id.maximize_window) { RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId); final DisplayAreaInfo rootDisplayAreaInfo = diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleImageButton.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleImageButton.kt index b21c3f522eab..458815d19658 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleImageButton.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleImageButton.kt @@ -17,9 +17,12 @@ package com.android.wm.shell.windowdecor import android.animation.ValueAnimator +import android.annotation.DimenRes +import android.content.res.Resources; import android.content.Context import android.util.AttributeSet import android.widget.ImageButton +import com.android.wm.shell.R /** * [ImageButton] for the handle at the top of fullscreen apps. Has custom hover @@ -30,13 +33,23 @@ class HandleImageButton (context: Context?, attrs: AttributeSet?) : ImageButton(context, attrs) { private val handleAnimator = ValueAnimator() + /** Final horizontal padding for hover enter. **/ + private val HANDLE_HOVER_ENTER_PADDING = loadDimensionPixelSize( + R.dimen.desktop_mode_fullscreen_decor_caption_horizontal_padding_hovered) + /** Final horizontal padding for press down. **/ + private val HANDLE_PRESS_DOWN_PADDING = loadDimensionPixelSize( + R.dimen.desktop_mode_fullscreen_decor_caption_horizontal_padding_touched) + /** Default horizontal padding. **/ + private val HANDLE_DEFAULT_PADDING = loadDimensionPixelSize( + R.dimen.desktop_mode_fullscreen_decor_caption_horizontal_padding_default) + override fun onHoverChanged(hovered: Boolean) { super.onHoverChanged(hovered) if (hovered) { - animateHandle(HANDLE_HOVER_ANIM_DURATION, HANDLE_HOVER_ENTER_SCALE) + animateHandle(HANDLE_HOVER_ANIM_DURATION, HANDLE_HOVER_ENTER_PADDING) } else { if (!isPressed) { - animateHandle(HANDLE_HOVER_ANIM_DURATION, HANDLE_DEFAULT_SCALE) + animateHandle(HANDLE_HOVER_ANIM_DURATION, HANDLE_DEFAULT_PADDING) } } } @@ -45,35 +58,37 @@ class HandleImageButton (context: Context?, attrs: AttributeSet?) : if (isPressed != pressed) { super.setPressed(pressed) if (pressed) { - animateHandle(HANDLE_PRESS_ANIM_DURATION, HANDLE_PRESS_DOWN_SCALE) + animateHandle(HANDLE_PRESS_ANIM_DURATION, HANDLE_PRESS_DOWN_PADDING) } else { - animateHandle(HANDLE_PRESS_ANIM_DURATION, HANDLE_DEFAULT_SCALE) + animateHandle(HANDLE_PRESS_ANIM_DURATION, HANDLE_DEFAULT_PADDING) } } } - private fun animateHandle(duration: Long, endScale: Float) { + private fun animateHandle(duration: Long, endPadding: Int) { if (handleAnimator.isRunning) { handleAnimator.cancel() } handleAnimator.duration = duration - handleAnimator.setFloatValues(scaleX, endScale) + handleAnimator.setIntValues(paddingLeft, endPadding) handleAnimator.addUpdateListener { animator -> - scaleX = animator.animatedValue as Float + val padding = animator.animatedValue as Int + setPadding(padding, paddingTop, padding, paddingBottom) } handleAnimator.start() } + private fun loadDimensionPixelSize(@DimenRes resourceId: Int): Int { + if (resourceId == Resources.ID_NULL) { + return 0 + } + return context.resources.getDimensionPixelSize(resourceId) + } + companion object { /** The duration of animations related to hover state. **/ private const val HANDLE_HOVER_ANIM_DURATION = 300L /** The duration of animations related to pressed state. **/ private const val HANDLE_PRESS_ANIM_DURATION = 200L - /** Ending scale for hover enter. **/ - private const val HANDLE_HOVER_ENTER_SCALE = 1.2f - /** Ending scale for press down. **/ - private const val HANDLE_PRESS_DOWN_SCALE = 0.85f - /** Default scale for handle. **/ - private const val HANDLE_DEFAULT_SCALE = 1f } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt index a17bcb39f1a0..ff50672953c9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt @@ -37,6 +37,9 @@ import android.view.WindowInsets.Type.systemBars import android.view.WindowManager import android.widget.ImageButton import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.Space +import android.widget.TextView import android.window.DesktopModeFlags import android.window.SurfaceSyncGroup import androidx.annotation.StringRes @@ -480,16 +483,23 @@ class HandleMenu( private val splitscreenBtn = windowingPill.requireViewById<ImageButton>( R.id.split_screen_button) private val floatingBtn = windowingPill.requireViewById<ImageButton>(R.id.floating_button) + private val floatingBtnSpace = windowingPill.requireViewById<Space>( + R.id.floating_button_space) + private val desktopBtn = windowingPill.requireViewById<ImageButton>(R.id.desktop_button) + private val desktopBtnSpace = windowingPill.requireViewById<Space>( + R.id.desktop_button_space) // More Actions Pill. private val moreActionsPill = rootView.requireViewById<View>(R.id.more_actions_pill) - private val screenshotBtn = moreActionsPill.requireViewById<View>(R.id.screenshot_button) - private val newWindowBtn = moreActionsPill.requireViewById<View>(R.id.new_window_button) + private val screenshotBtn = moreActionsPill.requireViewById<HandleMenuActionButton>( + R.id.screenshot_button) + private val newWindowBtn = moreActionsPill.requireViewById<HandleMenuActionButton>( + R.id.new_window_button) private val manageWindowBtn = moreActionsPill - .requireViewById<View>(R.id.manage_windows_button) + .requireViewById<HandleMenuActionButton>(R.id.manage_windows_button) private val changeAspectRatioBtn = moreActionsPill - .requireViewById<View>(R.id.change_aspect_ratio_button) + .requireViewById<HandleMenuActionButton>(R.id.change_aspect_ratio_button) // Open in Browser/App Pill. private val openInAppOrBrowserPill = rootView.requireViewById<View>( @@ -682,6 +692,7 @@ class HandleMenu( if (!BubbleAnythingFlagHelper.enableBubbleToFullscreen()) { floatingBtn.visibility = View.GONE + floatingBtnSpace.visibility = View.GONE } fullscreenBtn.isSelected = taskInfo.isFullscreen @@ -710,8 +721,10 @@ class HandleMenu( ).forEach { val button = it.first val shouldShow = it.second - val label = button.requireViewById<MarqueedTextView>(R.id.label) - val image = button.requireViewById<ImageView>(R.id.image) + + val buttonRoot = button.requireViewById<LinearLayout>(R.id.action_button) + val label = buttonRoot.requireViewById<MarqueedTextView>(R.id.label) + val image = buttonRoot.requireViewById<ImageView>(R.id.image) button.isGone = !shouldShow label.apply { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuActionButton.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuActionButton.kt new file mode 100644 index 000000000000..4b2e473d6ec2 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuActionButton.kt @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2025 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.windowdecor + +import android.annotation.ColorInt +import android.annotation.IdRes +import android.content.Context +import android.content.res.ColorStateList +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.core.content.withStyledAttributes +import androidx.core.view.isGone +import com.android.wm.shell.R + +/** + * Button-like component used to display the "Additional options" elements of the Handle menu window + * decoration. + * + * The possible options for which this button is used for are "Screenshot", "New Window", "Manage + * Windows" and "Change Aspect Ratio". + */ +class HandleMenuActionButton @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr) { + + private val rootElement: LinearLayout + private val iconView: ImageView + private val textView: MarqueedTextView + + init { + val view = LayoutInflater.from(context).inflate( + R.layout.desktop_mode_window_decor_handle_menu_action_button, this, true) + rootElement = findViewById(R.id.action_button) + iconView = findViewById(R.id.image) + textView = findViewById(R.id.label) + + context.withStyledAttributes(attrs, R.styleable.HandleMenuActionButton) { + textView.text = getString(R.styleable.HandleMenuActionButton_android_text) + textView.setTextColor(getColor(R.styleable.HandleMenuActionButton_android_textColor, 0)) + iconView.setImageResource(getResourceId( + R.styleable.HandleMenuActionButton_android_src, 0)) + iconView.imageTintList = getColorStateList( + R.styleable.HandleMenuActionButton_android_drawableTint) + } + } + + /** + * Sets a listener to be invoked when this view is clicked. + * + * @param l the [OnClickListener] that receives click events. + */ + override fun setOnClickListener(l: OnClickListener?) { + rootElement.setOnClickListener(l) + } + + /** + * Sets the text color for the text inside the button. + * + * @param color the color to set for the text, as a color integer. + */ + fun setTextColor(@ColorInt color: Int) { + textView.setTextColor(color) + } + + /** + * Sets the icon for the button using a resource ID. + * + * @param resourceId the resource ID of the drawable to set as the icon. + */ + fun setIconResource(@IdRes resourceId: Int) { + iconView.setImageResource(resourceId) + } + + /** + * Sets the text to display inside the button. + * + * @param text the text to display. + */ + fun setText(text: CharSequence?) { + textView.text = text + } + + /** + * Sets the tint color for the icon. + * + * @param color the color to use for the tint, as a color integer. + */ + fun setDrawableTint(@ColorInt color: Int) { + iconView.imageTintList = ColorStateList.valueOf(color) + } + + /** + * Gets or sets the tint applied to the icon. + * + * @return The [ColorStateList] representing the tint, or null if no tint is applied. + */ + var compoundDrawableTintList: ColorStateList? + get() = iconView.imageTintList + set(value) { + iconView.imageTintList = value + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt index a9c2e68e62a6..bb20292a51d4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt @@ -237,8 +237,12 @@ class MultiDisplayVeiledResizeTaskPositioner( val startDisplayLayout = displayController.getDisplayLayout(startDisplayId) val currentDisplayLayout = displayController.getDisplayLayout(displayId) - if (startDisplayLayout == null || currentDisplayLayout == null) { - // Fall back to single-display drag behavior if any display layout is unavailable. + if (startDisplayId == displayId + || startDisplayLayout == null || currentDisplayLayout == null) { + // Fall back to single-display drag behavior if: + // 1. The drag destination display is the same as the start display. This prevents + // unnecessary animations caused by minor width/height changes due to DPI scaling. + // 2. Either the starting or current display layout is unavailable. DragPositioningCallbackUtility.updateTaskBounds( repositionTaskBounds, taskBoundsAtDragStart, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskOperations.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskOperations.java index bc85d2b40748..45ba4413814c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskOperations.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskOperations.java @@ -86,14 +86,18 @@ class TaskOperations { return null; } - IBinder minimizeTask(WindowContainerToken taskToken) { - return minimizeTask(taskToken, new WindowContainerTransaction()); + IBinder minimizeTask(WindowContainerToken taskToken, int taskId, boolean isLastTask) { + return minimizeTask(taskToken, taskId, isLastTask, new WindowContainerTransaction()); } - IBinder minimizeTask(WindowContainerToken taskToken, WindowContainerTransaction wct) { + IBinder minimizeTask( + WindowContainerToken taskToken, + int taskId, + boolean isLastTask, + WindowContainerTransaction wct) { wct.reorder(taskToken, false); if (Transitions.ENABLE_SHELL_TRANSITIONS) { - return mTransitionStarter.startMinimizedModeTransition(wct); + return mTransitionStarter.startMinimizedModeTransition(wct, taskId, isLastTask); } else { mSyncQueue.queue(wct); return null; 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 76005c22972a..25dadfde274d 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 @@ -911,7 +911,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> } } - @VisibleForTesting public interface SurfaceControlViewHostFactory { default SurfaceControlViewHost create(Context c, Display d, WindowlessWindowManager wmm) { return new SurfaceControlViewHost(c, d, wmm, "WindowDecoration"); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java index 4198f5904566..42310caba1c6 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java @@ -17,6 +17,10 @@ package com.android.wm.shell.bubbles; import static android.view.WindowManager.TRANSIT_CHANGE; +import static com.android.wm.shell.transition.Transitions.TRANSIT_CONVERT_TO_BUBBLE; + +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -31,12 +35,14 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; +import android.graphics.Rect; import android.os.IBinder; import android.view.SurfaceControl; import android.view.ViewRootImpl; import android.window.IWindowContainerToken; import android.window.TransitionInfo; import android.window.WindowContainerToken; +import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; @@ -65,6 +71,10 @@ import org.mockito.MockitoAnnotations; */ @SmallTest public class BubbleTransitionsTest extends ShellTestCase { + + private static final int FULLSCREEN_TASK_WIDTH = 200; + private static final int FULLSCREEN_TASK_HEIGHT = 100; + @Mock private BubbleData mBubbleData; @Mock @@ -117,10 +127,7 @@ public class BubbleTransitionsTest extends ShellTestCase { private ActivityManager.RunningTaskInfo setupBubble() { ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo(); - final IWindowContainerToken itoken = mock(IWindowContainerToken.class); - final IBinder asBinder = mock(IBinder.class); - when(itoken.asBinder()).thenReturn(asBinder); - WindowContainerToken token = new WindowContainerToken(itoken); + WindowContainerToken token = createMockToken(); taskInfo.token = token; final TaskView tv = mock(TaskView.class); final TaskViewTaskController tvtc = mock(TaskViewTaskController.class); @@ -131,13 +138,32 @@ public class BubbleTransitionsTest extends ShellTestCase { return taskInfo; } + private TransitionInfo setupFullscreenTaskTransition(ActivityManager.RunningTaskInfo taskInfo) { + final TransitionInfo info = new TransitionInfo(TRANSIT_CONVERT_TO_BUBBLE, 0); + final TransitionInfo.Change chg = new TransitionInfo.Change(taskInfo.token, + mock(SurfaceControl.class)); + chg.setTaskInfo(taskInfo); + chg.setMode(TRANSIT_CHANGE); + chg.setStartAbsBounds(new Rect(0, 0, FULLSCREEN_TASK_WIDTH, FULLSCREEN_TASK_HEIGHT)); + info.addChange(chg); + info.addRoot(new TransitionInfo.Root(0, mock(SurfaceControl.class), 0, 0)); + return info; + } + + private WindowContainerToken createMockToken() { + final IWindowContainerToken itoken = mock(IWindowContainerToken.class); + final IBinder asBinder = mock(IBinder.class); + when(itoken.asBinder()).thenReturn(asBinder); + return new WindowContainerToken(itoken); + } + @Test public void testConvertToBubble() { // Basic walk-through of convert-to-bubble transition stages ActivityManager.RunningTaskInfo taskInfo = setupBubble(); final BubbleTransitions.BubbleTransition bt = mBubbleTransitions.startConvertToBubble( mBubble, taskInfo, mExpandedViewManager, mTaskViewFactory, mBubblePositioner, - mStackView, mLayerView, mIconFactory, false); + mStackView, mLayerView, mIconFactory, null, false); final BubbleTransitions.ConvertToBubble ctb = (BubbleTransitions.ConvertToBubble) bt; ctb.onInflated(mBubble); when(mLayerView.canExpandView(any())).thenReturn(true); @@ -146,13 +172,7 @@ public class BubbleTransitionsTest extends ShellTestCase { // Ensure we are communicating with the taskviewtransitions queue assertTrue(mTaskViewTransitions.hasPending()); - final TransitionInfo info = new TransitionInfo(TRANSIT_CHANGE, 0); - final TransitionInfo.Change chg = new TransitionInfo.Change(taskInfo.token, - mock(SurfaceControl.class)); - chg.setTaskInfo(taskInfo); - chg.setMode(TRANSIT_CHANGE); - info.addChange(chg); - info.addRoot(new TransitionInfo.Root(0, mock(SurfaceControl.class), 0, 0)); + final TransitionInfo info = setupFullscreenTaskTransition(taskInfo); SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class); final boolean[] finishCalled = new boolean[]{false}; @@ -163,22 +183,69 @@ public class BubbleTransitionsTest extends ShellTestCase { ctb.startAnimation(ctb.mTransition, info, startT, finishT, finishCb); assertFalse(mTaskViewTransitions.hasPending()); + verify(startT).setPosition(any(), eq(0f), eq(0f)); + verify(mBubbleData).notificationEntryUpdated(eq(mBubble), anyBoolean(), anyBoolean()); - ctb.continueExpand(); clearInvocations(mBubble); verify(mBubble, never()).setPreparingTransition(any()); ctb.surfaceCreated(); - verify(mBubble).setPreparingTransition(isNull()); + // Check that preparing transition is not reset before continueExpand is called + verify(mBubble, never()).setPreparingTransition(any()); ArgumentCaptor<Runnable> animCb = ArgumentCaptor.forClass(Runnable.class); verify(mLayerView).animateConvert(any(), any(), any(), any(), animCb.capture()); + + // continueExpand is now called, check that preparing transition is cleared + ctb.continueExpand(); + verify(mBubble).setPreparingTransition(isNull()); + assertFalse(finishCalled[0]); animCb.getValue().run(); assertTrue(finishCalled[0]); } @Test + public void testConvertToBubble_drag() { + ActivityManager.RunningTaskInfo taskInfo = setupBubble(); + + Rect draggedTaskBounds = new Rect(10, 20, 30, 40); + WindowContainerTransaction pendingWct = new WindowContainerTransaction(); + WindowContainerToken pendingDragOpToken = createMockToken(); + pendingWct.reorder(pendingDragOpToken, /* onTop= */ false); + + BubbleTransitions.DragData dragData = new BubbleTransitions.DragData( + draggedTaskBounds, pendingWct, /* releasedOnLeft= */ false + ); + + final BubbleTransitions.BubbleTransition bt = mBubbleTransitions.startConvertToBubble( + mBubble, taskInfo, mExpandedViewManager, mTaskViewFactory, mBubblePositioner, + mStackView, mLayerView, mIconFactory, dragData, false); + final BubbleTransitions.ConvertToBubble ctb = (BubbleTransitions.ConvertToBubble) bt; + + ArgumentCaptor<WindowContainerTransaction> wctCaptor = ArgumentCaptor.forClass( + WindowContainerTransaction.class); + ctb.onInflated(mBubble); + verify(mTransitions).startTransition(anyInt(), wctCaptor.capture(), eq(ctb)); + + // Verify that the WCT has the pending operation from drag data + WindowContainerTransaction transitionWct = wctCaptor.getValue(); + assertThat(transitionWct.getHierarchyOps().stream().anyMatch(op -> op.getType() + == WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER + && op.getContainer() == pendingDragOpToken.asBinder())).isTrue(); + + final TransitionInfo info = setupFullscreenTaskTransition(taskInfo); + SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); + SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class); + Transitions.TransitionFinishCallback finishCb = wct -> {}; + ctb.startAnimation(ctb.mTransition, info, startT, finishT, finishCb); + + // Verify that dragged task bounds are used for the position + verify(startT).setPosition(any(), eq((float) draggedTaskBounds.left), + eq((float) draggedTaskBounds.top)); + } + + @Test public void testConvertFromBubble() { ActivityManager.RunningTaskInfo taskInfo = setupBubble(); final BubbleTransitions.BubbleTransition bt = mBubbleTransitions.startConvertFromBubble( diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt index 0b41952a89d7..77cd1e56853d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt @@ -58,6 +58,7 @@ import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock import org.mockito.Mockito @@ -128,12 +129,21 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() { @Test fun startMinimizedModeTransition_callsFreeformTaskTransitionHandler() { val wct = WindowContainerTransaction() - whenever(freeformTaskTransitionHandler.startMinimizedModeTransition(any())) + val taskId = 1 + val isLastTask = false + whenever( + freeformTaskTransitionHandler.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(mock()) - mixedHandler.startMinimizedModeTransition(wct) + mixedHandler.startMinimizedModeTransition(wct, taskId, isLastTask) - verify(freeformTaskTransitionHandler).startMinimizedModeTransition(wct) + verify(freeformTaskTransitionHandler) + .startMinimizedModeTransition(eq(wct), eq(taskId), eq(isLastTask)) } @Test @@ -531,6 +541,131 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() { } @Test + @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_BY_MINIMIZE_TRANSITION_BUGFIX) + fun startMinimizedModeTransition_exitByMinimizeTransitionFlagsDisabled_doesNotUseMixedHandler() { + val wct = WindowContainerTransaction() + val task = createTask(WINDOWING_MODE_FREEFORM) + whenever( + freeformTaskTransitionHandler.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) + .thenReturn(mock()) + + mixedHandler.startMinimizedModeTransition( + wct = wct, + taskId = task.taskId, + isLastTask = true, + ) + + verify(freeformTaskTransitionHandler) + .startMinimizedModeTransition(eq(wct), eq(task.taskId), eq(true)) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_BY_MINIMIZE_TRANSITION_BUGFIX) + fun startMinimizedModeTransition_exitByMinimizeTransitionFlagsEnabled_notLastTask_callsMinimizationHandler() { + val wct = WindowContainerTransaction() + val minimizingTask = createTask(WINDOWING_MODE_FREEFORM) + val minimizingTaskChange = createChange(minimizingTask) + val transition = Binder() + whenever( + transitions.startTransition(eq(Transitions.TRANSIT_MINIMIZE), eq(wct), anyOrNull()) + ) + .thenReturn(transition) + whenever( + desktopMinimizationTransitionHandler.startAnimation( + any(), + any(), + any(), + any(), + any(), + ) + ) + .thenReturn(true) + + mixedHandler.startMinimizedModeTransition( + wct = wct, + taskId = minimizingTask.taskId, + isLastTask = false, + ) + val started = + mixedHandler.startAnimation( + transition = transition, + info = + createCloseTransitionInfo( + Transitions.TRANSIT_MINIMIZE, + listOf(minimizingTaskChange), + ), + startTransaction = mock(), + finishTransaction = mock(), + finishCallback = {}, + ) + + assertTrue("Should delegate animation to minimization transition handler", started) + verify(desktopMinimizationTransitionHandler) + .startAnimation( + eq(transition), + argThat { info -> info.changes.contains(minimizingTaskChange) }, + any(), + any(), + any(), + ) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_BY_MINIMIZE_TRANSITION_BUGFIX) + fun startMinimizedModeTransition_exitByMinimizeTransitionFlagsEnabled_withMinimizingLastTask_dispatchesTransition() { + val wct = WindowContainerTransaction() + val minimizingTask = createTask(WINDOWING_MODE_FREEFORM) + val minimizingTaskChange = createChange(minimizingTask) + val transition = Binder() + whenever( + transitions.startTransition(eq(Transitions.TRANSIT_MINIMIZE), eq(wct), anyOrNull()) + ) + .thenReturn(transition) + whenever( + desktopMinimizationTransitionHandler.startAnimation( + any(), + any(), + any(), + any(), + any(), + ) + ) + .thenReturn(true) + + mixedHandler.startMinimizedModeTransition( + wct = wct, + taskId = minimizingTask.taskId, + isLastTask = true, + ) + mixedHandler.startAnimation( + transition = transition, + info = + createCloseTransitionInfo( + Transitions.TRANSIT_MINIMIZE, + listOf(minimizingTaskChange), + ), + startTransaction = mock(), + finishTransaction = mock(), + finishCallback = {}, + ) + + verify(transitions) + .dispatchTransition( + eq(transition), + argThat { info -> info.changes.contains(minimizingTaskChange) }, + any(), + any(), + any(), + eq(mixedHandler), + ) + } + + @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX) fun addPendingAndAnimateLaunchTransition_noMinimizeChange_doesNotReparentMinimizeChange() { val wct = WindowContainerTransaction() diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt index 8f45cf4d08fc..20d50aa32f7f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt @@ -23,6 +23,7 @@ import android.graphics.Rect import android.platform.test.annotations.EnableFlags import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper +import android.view.Display import android.view.SurfaceControl import androidx.test.filters.SmallTest import com.android.internal.policy.SystemBarUtils @@ -30,6 +31,7 @@ import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE import com.android.wm.shell.R import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.TestShellExecutor import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayLayout import com.android.wm.shell.common.SyncTransactionQueue @@ -60,18 +62,22 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() { private lateinit var taskInfo: RunningTaskInfo @Mock private lateinit var syncQueue: SyncTransactionQueue @Mock private lateinit var displayController: DisplayController + @Mock private lateinit var display: Display @Mock private lateinit var taskSurface: SurfaceControl @Mock private lateinit var taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer @Mock private lateinit var displayLayout: DisplayLayout @Mock private lateinit var bubbleBoundsProvider: BubbleDropTargetBoundsProvider private lateinit var visualIndicator: DesktopModeVisualIndicator + private val desktopExecutor = TestShellExecutor() + private val mainExecutor = TestShellExecutor() @Before fun setUp() { whenever(displayLayout.width()).thenReturn(DISPLAY_BOUNDS.width()) whenever(displayLayout.height()).thenReturn(DISPLAY_BOUNDS.height()) whenever(displayLayout.stableInsets()).thenReturn(STABLE_INSETS) + whenever(displayController.getDisplay(anyInt())).thenReturn(display) whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout) whenever(displayController.getDisplay(anyInt())).thenReturn(mContext.display) whenever(bubbleBoundsProvider.getBubbleBarExpandedViewDropTargetBounds(any())) @@ -305,7 +311,11 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() { whenever(bubbleBoundsProvider.getBubbleBarExpandedViewDropTargetBounds(/* onLeft= */ true)) .thenReturn(dropTargetBounds) createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FULLSCREEN) + desktopExecutor.flushAll() + mainExecutor.flushAll() visualIndicator.updateIndicatorType(PointF(100f, 1500f)) + desktopExecutor.flushAll() + mainExecutor.flushAll() animatorTestRule.advanceTimeBy(200) @@ -322,7 +332,11 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() { whenever(bubbleBoundsProvider.getBubbleBarExpandedViewDropTargetBounds(/* onLeft= */ false)) .thenReturn(dropTargetBounds) createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FULLSCREEN) + desktopExecutor.flushAll() + mainExecutor.flushAll() visualIndicator.updateIndicatorType(PointF(2300f, 1500f)) + desktopExecutor.flushAll() + mainExecutor.flushAll() animatorTestRule.advanceTimeBy(200) @@ -332,6 +346,8 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() { private fun createVisualIndicator(dragStartState: DesktopModeVisualIndicator.DragStartState) { visualIndicator = DesktopModeVisualIndicator( + desktopExecutor, + mainExecutor, syncQueue, taskInfo, displayController, 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 718bf322f6a9..eb4ec1189b0b 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 @@ -29,6 +29,7 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.content.ComponentName +import android.content.Context import android.content.Intent import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo.CONFIG_DENSITY @@ -51,6 +52,8 @@ import android.os.UserManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization +import android.testing.TestableContext +import android.view.Display import android.view.Display.DEFAULT_DISPLAY import android.view.DragEvent import android.view.Gravity @@ -147,6 +150,7 @@ import com.android.wm.shell.transition.TestRemoteTransition import com.android.wm.shell.transition.Transitions import com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS import com.android.wm.shell.transition.Transitions.TransitionHandler +import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModelTestsBase.Companion.HOME_LAUNCHER_PACKAGE_NAME import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration import com.android.wm.shell.windowdecor.tiling.DesktopTilingDecorViewModel import com.google.common.truth.Truth.assertThat @@ -175,6 +179,7 @@ import org.mockito.ArgumentMatchers.isA import org.mockito.ArgumentMatchers.isNull import org.mockito.Mock import org.mockito.Mockito +import org.mockito.Mockito.anyBoolean import org.mockito.Mockito.anyInt import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.mock @@ -186,7 +191,6 @@ import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.argThat import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.atLeastOnce -import org.mockito.kotlin.capture import org.mockito.kotlin.eq import org.mockito.kotlin.whenever import org.mockito.quality.Strictness @@ -209,6 +213,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Mock lateinit var shellController: ShellController @Mock lateinit var displayController: DisplayController @Mock lateinit var displayLayout: DisplayLayout + @Mock lateinit var display: Display @Mock lateinit var shellTaskOrganizer: ShellTaskOrganizer @Mock lateinit var syncQueue: SyncTransactionQueue @Mock lateinit var rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer @@ -256,6 +261,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Mock private lateinit var desksOrganizer: DesksOrganizer @Mock private lateinit var userProfileContexts: UserProfileContexts @Mock private lateinit var desksTransitionsObserver: DesksTransitionObserver + @Mock private lateinit var packageManager: PackageManager + @Mock private lateinit var mockDisplayContext: Context private lateinit var controller: DesktopTasksController private lateinit var shellInit: ShellInit @@ -265,8 +272,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() private lateinit var recentsTransitionStateListener: RecentsTransitionStateListener private lateinit var testScope: CoroutineScope private lateinit var desktopModeCompatPolicy: DesktopModeCompatPolicy + private lateinit var spyContext: TestableContext private val shellExecutor = TestShellExecutor() + private val bgExecutor = TestShellExecutor() // Mock running tasks are registered here so we can get the list from mock shell task organizer private val runningTasks = mutableListOf<RunningTaskInfo>() @@ -281,6 +290,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() private val UNRESIZABLE_LANDSCAPE_BOUNDS = Rect(25, 449, 1575, 1611) private val UNRESIZABLE_PORTRAIT_BOUNDS = Rect(830, 75, 1730, 1275) private val wallpaperToken = MockToken().token() + private val homeComponentName = ComponentName(HOME_LAUNCHER_PACKAGE_NAME, /* class */ "") @Before fun setUp() { @@ -294,6 +304,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() doReturn(true).`when` { DesktopModeStatus.canEnterDesktopMode(any()) } testScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) + spyContext = spy(mContext) shellInit = spy(ShellInit(testExecutor)) userRepositories = DesktopUserRepositories( @@ -315,12 +326,14 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() mContext, mockHandler, ) - desktopModeCompatPolicy = spy(DesktopModeCompatPolicy(context)) + desktopModeCompatPolicy = spy(DesktopModeCompatPolicy(spyContext)) whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenAnswer { runningTasks } whenever(transitions.startTransition(anyInt(), any(), isNull())).thenAnswer { Binder() } whenever(enterDesktopTransitionHandler.moveToDesktop(any(), any())).thenAnswer { Binder() } whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout) + whenever(displayController.getDisplayContext(anyInt())).thenReturn(mockDisplayContext) + whenever(displayController.getDisplay(anyInt())).thenReturn(display) whenever(displayLayout.getStableBounds(any())).thenAnswer { i -> (i.arguments.first() as Rect).set(STABLE_BOUNDS) } @@ -373,6 +386,9 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() taskRepository = userRepositories.current taskRepository.addDesk(displayId = DEFAULT_DISPLAY, deskId = DEFAULT_DISPLAY) taskRepository.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = DEFAULT_DISPLAY) + + spyContext.setMockPackageManager(packageManager) + whenever(packageManager.getHomeActivities(ArrayList())).thenReturn(homeComponentName) } private fun createController() = @@ -400,6 +416,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() recentsTransitionHandler, multiInstanceHelper, shellExecutor, + bgExecutor, Optional.of(desktopTasksLimiter), recentTasksController, mockInteractionJankMonitor, @@ -2747,13 +2764,20 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() fun onDesktopWindowMinimize_noActiveTask_doesntRemoveWallpaper() { val task = setUpFreeformTask(active = false) val transition = Binder() - whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) + whenever( + freeformTaskTransitionStarter.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(transition) controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON) val captor = argumentCaptor<WindowContainerTransaction>() - verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture()) + verify(freeformTaskTransitionStarter) + .startMinimizedModeTransition(captor.capture(), eq(task.taskId), eq(false)) captor.firstValue.hierarchyOps.none { hop -> hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK && hop.container == wallpaperToken.asBinder() } @@ -2769,18 +2793,26 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON) verify(freeformTaskTransitionStarter).startPipTransition(any()) - verify(freeformTaskTransitionStarter, never()).startMinimizedModeTransition(any()) + verify(freeformTaskTransitionStarter, never()) + .startMinimizedModeTransition(any(), anyInt(), anyBoolean()) } @Test fun onPipTaskMinimize_autoEnterDisabled_startMinimizeTransition() { val task = setUpPipTask(autoEnterEnabled = false) - whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) + whenever( + freeformTaskTransitionStarter.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(Binder()) controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON) - verify(freeformTaskTransitionStarter).startMinimizedModeTransition(any()) + verify(freeformTaskTransitionStarter) + .startMinimizedModeTransition(any(), eq(task.taskId), anyBoolean()) verify(freeformTaskTransitionStarter, never()).startPipTransition(any()) } @@ -2804,13 +2836,20 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() fun onDesktopWindowMinimize_singleActiveTask_noWallpaperActivityToken_doesntRemoveWallpaper() { val task = setUpFreeformTask(active = true) val transition = Binder() - whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) + whenever( + freeformTaskTransitionStarter.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(transition) controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON) val captor = argumentCaptor<WindowContainerTransaction>() - verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture()) + verify(freeformTaskTransitionStarter) + .startMinimizedModeTransition(captor.capture(), eq(task.taskId), eq(true)) captor.firstValue.hierarchyOps.none { hop -> hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK } } @@ -2819,14 +2858,21 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() fun onTaskMinimize_singleActiveTask_hasWallpaperActivityToken_removesWallpaper() { val task = setUpFreeformTask() val transition = Binder() - whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) + whenever( + freeformTaskTransitionStarter.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(transition) // The only active task is being minimized. controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON) val captor = argumentCaptor<WindowContainerTransaction>() - verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture()) + verify(freeformTaskTransitionStarter) + .startMinimizedModeTransition(captor.capture(), eq(task.taskId), eq(true)) // Adds remove wallpaper operation captor.firstValue.assertReorderAt(index = 0, wallpaperToken, toTop = false) } @@ -2835,7 +2881,13 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() fun onDesktopWindowMinimize_singleActiveTask_alreadyMinimized_doesntRemoveWallpaper() { val task = setUpFreeformTask() val transition = Binder() - whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) + whenever( + freeformTaskTransitionStarter.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(transition) taskRepository.minimizeTask(DEFAULT_DISPLAY, task.taskId) @@ -2843,7 +2895,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON) val captor = argumentCaptor<WindowContainerTransaction>() - verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture()) + verify(freeformTaskTransitionStarter) + .startMinimizedModeTransition(captor.capture(), eq(task.taskId), eq(false)) captor.firstValue.hierarchyOps.none { hop -> hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK && hop.container == wallpaperToken.asBinder() } @@ -2854,13 +2907,20 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val task1 = setUpFreeformTask(active = true) setUpFreeformTask(active = true) val transition = Binder() - whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) + whenever( + freeformTaskTransitionStarter.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(transition) controller.minimizeTask(task1, MinimizeReason.MINIMIZE_BUTTON) val captor = argumentCaptor<WindowContainerTransaction>() - verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture()) + verify(freeformTaskTransitionStarter) + .startMinimizedModeTransition(captor.capture(), eq(task1.taskId), eq(false)) captor.firstValue.hierarchyOps.none { hop -> hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK && hop.container == wallpaperToken.asBinder() } @@ -2872,7 +2932,13 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val task1 = setUpFreeformTask(active = true) val task2 = setUpFreeformTask(active = true) val transition = Binder() - whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) + whenever( + freeformTaskTransitionStarter.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(transition) taskRepository.minimizeTask(DEFAULT_DISPLAY, task2.taskId) @@ -2880,7 +2946,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.minimizeTask(task1, MinimizeReason.MINIMIZE_BUTTON) // Adds remove wallpaper operation val captor = argumentCaptor<WindowContainerTransaction>() - verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture()) + verify(freeformTaskTransitionStarter) + .startMinimizedModeTransition(captor.capture(), eq(task1.taskId), eq(true)) // Adds remove wallpaper operation captor.firstValue.assertReorderAt(index = 0, wallpaperToken, toTop = false) } @@ -2889,7 +2956,13 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() fun onDesktopWindowMinimize_triesToExitImmersive() { val task = setUpFreeformTask() val transition = Binder() - whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) + whenever( + freeformTaskTransitionStarter.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(transition) controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON) @@ -2902,7 +2975,13 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val task = setUpFreeformTask() val transition = Binder() val runOnTransit = RunOnStartTransitionCallback() - whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) + whenever( + freeformTaskTransitionStarter.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(transition) whenever(mMockDesktopImmersiveController.exitImmersiveIfApplicable(any(), eq(task), any())) .thenReturn( @@ -4849,7 +4928,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val optionsCaptor = argumentCaptor<Bundle>() runOpenInstance(task, taskToRequest.taskId) verify(splitScreenController) - .startTask(anyInt(), anyInt(), optionsCaptor.capture(), anyOrNull()) + .startTask(anyInt(), anyInt(), optionsCaptor.capture(), anyOrNull(), any()) assertThat(ActivityOptions.fromBundle(optionsCaptor.firstValue).launchWindowingMode) .isEqualTo(WINDOWING_MODE_MULTI_WINDOW) } @@ -4863,7 +4942,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val optionsCaptor = argumentCaptor<Bundle>() runOpenInstance(task, taskToRequest.taskId) verify(splitScreenController) - .startTask(anyInt(), anyInt(), optionsCaptor.capture(), anyOrNull()) + .startTask(anyInt(), anyInt(), optionsCaptor.capture(), anyOrNull(), any()) assertThat(ActivityOptions.fromBundle(optionsCaptor.firstValue).launchWindowingMode) .isEqualTo(WINDOWING_MODE_MULTI_WINDOW) } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt index 1732875f1d57..85f6cd36992d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt @@ -25,6 +25,8 @@ import com.android.internal.jank.InteractionJankMonitor import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.ShellTestCase import com.android.wm.shell.TestRunningTaskInfoBuilder +import com.android.wm.shell.bubbles.BubbleController +import com.android.wm.shell.bubbles.BubbleTransitions import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP @@ -34,6 +36,7 @@ import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP import com.android.wm.shell.splitscreen.SplitScreenController import com.android.wm.shell.transition.Transitions import com.android.wm.shell.windowdecor.MoveToDesktopAnimator +import java.util.Optional import java.util.function.Supplier import junit.framework.Assert.assertEquals import junit.framework.Assert.assertFalse @@ -48,6 +51,7 @@ import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.eq import org.mockito.Mock import org.mockito.MockitoSession +import org.mockito.kotlin.argThat import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.times @@ -71,6 +75,7 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { @Mock private lateinit var draggedTaskLeash: SurfaceControl @Mock private lateinit var homeTaskLeash: SurfaceControl @Mock private lateinit var desktopUserRepositories: DesktopUserRepositories + @Mock private lateinit var bubbleController: BubbleController private val transactionSupplier = Supplier { mock<SurfaceControl.Transaction>() } @@ -87,6 +92,7 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { taskDisplayAreaOrganizer, desktopUserRepositories, mockInteractionJankMonitor, + Optional.of(bubbleController), transactionSupplier, ) .apply { setSplitScreenController(splitScreenController) } @@ -97,6 +103,7 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { taskDisplayAreaOrganizer, desktopUserRepositories, mockInteractionJankMonitor, + Optional.of(bubbleController), transactionSupplier, ) .apply { setSplitScreenController(splitScreenController) } @@ -169,6 +176,32 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { } @Test + fun startDragToDesktop_cancelledBeforeReady_verifyBubbleLeftCancel() { + performEarlyCancel( + defaultHandler, + DragToDesktopTransitionHandler.CancelState.CANCEL_BUBBLE_LEFT, + ) + verify(bubbleController) + .expandStackAndSelectBubble( + any<RunningTaskInfo>(), + argThat<BubbleTransitions.DragData> { isReleasedOnLeft }, + ) + } + + @Test + fun startDragToDesktop_cancelledBeforeReady_verifyBubbleRightCancel() { + performEarlyCancel( + defaultHandler, + DragToDesktopTransitionHandler.CancelState.CANCEL_BUBBLE_RIGHT, + ) + verify(bubbleController) + .expandStackAndSelectBubble( + any<RunningTaskInfo>(), + argThat<BubbleTransitions.DragData> { !isReleasedOnLeft }, + ) + } + + @Test fun startDragToDesktop_aborted_finishDropped() { val task = createTask() // Simulate transition is started. @@ -343,6 +376,40 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { } @Test + fun cancelDragToDesktop_bubbleLeftCancelType_bubbleRequested() { + startDrag(defaultHandler) + + // Then user cancelled it, requesting bubble. + defaultHandler.cancelDragToDesktopTransition( + DragToDesktopTransitionHandler.CancelState.CANCEL_BUBBLE_LEFT + ) + + // Verify the request went through bubble controller. + verify(bubbleController) + .expandStackAndSelectBubble( + any<RunningTaskInfo>(), + argThat<BubbleTransitions.DragData> { isReleasedOnLeft }, + ) + } + + @Test + fun cancelDragToDesktop_bubbleRightCancelType_bubbleRequested() { + startDrag(defaultHandler) + + // Then user cancelled it, requesting bubble. + defaultHandler.cancelDragToDesktopTransition( + DragToDesktopTransitionHandler.CancelState.CANCEL_BUBBLE_RIGHT + ) + + // Verify the request went through bubble controller. + verify(bubbleController) + .expandStackAndSelectBubble( + any<RunningTaskInfo>(), + argThat<BubbleTransitions.DragData> { !isReleasedOnLeft }, + ) + } + + @Test fun cancelDragToDesktop_startWasNotReady_animateCancel() { val task = createTask() // Simulate transition is started and is ready to animate. diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainerTest.kt new file mode 100644 index 000000000000..79b0f1c7eadd --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainerTest.kt @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2025 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.desktopmode + +import android.app.ActivityManager +import android.app.ActivityManager.RunningTaskInfo +import android.graphics.Rect +import android.graphics.drawable.Drawable +import android.graphics.drawable.LayerDrawable +import android.platform.test.annotations.EnableFlags +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper +import android.view.Display +import android.view.SurfaceControl +import android.view.SurfaceControlViewHost +import android.view.View +import androidx.test.filters.SmallTest +import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE +import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.TestRunningTaskInfoBuilder +import com.android.wm.shell.TestShellExecutor +import com.android.wm.shell.common.DisplayController +import com.android.wm.shell.common.DisplayLayout +import com.android.wm.shell.common.SyncTransactionQueue +import com.android.wm.shell.shared.bubbles.BubbleDropTargetBoundsProvider +import com.android.wm.shell.windowdecor.WindowDecoration.SurfaceControlViewHostFactory +import com.google.common.truth.Truth.assertThat +import kotlin.test.Test +import org.junit.Before +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.Mock +import org.mockito.Mockito.mock +import org.mockito.kotlin.any +import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.eq +import org.mockito.kotlin.spy +import org.mockito.kotlin.verify +import org.mockito.kotlin.verifyZeroInteractions +import org.mockito.kotlin.whenever + +/** + * Test class for [VisualIndicatorViewContainer] and [VisualIndicatorAnimator] + * + * Usage: atest WMShellUnitTests:VisualIndicatorViewContainerTest + */ +@SmallTest +@RunWithLooper +@RunWith(AndroidTestingRunner::class) +@EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) +class VisualIndicatorViewContainerTest : ShellTestCase() { + @Mock private lateinit var view: View + @Mock private lateinit var displayLayout: DisplayLayout + @Mock private lateinit var displayController: DisplayController + @Mock private lateinit var taskSurface: SurfaceControl + @Mock private lateinit var syncQueue: SyncTransactionQueue + @Mock private lateinit var mockSurfaceControlViewHostFactory: SurfaceControlViewHostFactory + @Mock private lateinit var mockBackground: LayerDrawable + @Mock private lateinit var bubbleDropTargetBoundsProvider: BubbleDropTargetBoundsProvider + private val taskInfo: RunningTaskInfo = createTaskInfo() + private val mainExecutor = TestShellExecutor() + private val desktopExecutor = TestShellExecutor() + + @Before + fun setUp() { + whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout) + whenever(displayLayout.getStableBounds(any())).thenAnswer { i -> + (i.arguments.first() as Rect).set(DISPLAY_BOUNDS) + } + whenever(mockSurfaceControlViewHostFactory.create(any(), any(), any())) + .thenReturn(mock(SurfaceControlViewHost::class.java)) + } + + @Test + fun testTransitionIndicator_sameTypeReturnsEarly() { + val spyViewContainer = setupSpyViewContainer() + // Test early return on startType == endType. + spyViewContainer.transitionIndicator( + taskInfo, + displayController, + DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR, + DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR, + ) + desktopExecutor.flushAll() + verify(spyViewContainer) + .transitionIndicator( + eq(taskInfo), + eq(displayController), + eq(DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR), + eq(DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR), + ) + // Assert fadeIn, fadeOut, and animateIndicatorType were not called. + verifyZeroInteractions(spyViewContainer) + } + + @Test + fun testTransitionIndicator_firstTypeNoIndicator_callsFadeIn() { + val spyViewContainer = setupSpyViewContainer() + spyViewContainer.transitionIndicator( + taskInfo, + displayController, + DesktopModeVisualIndicator.IndicatorType.NO_INDICATOR, + DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR, + ) + desktopExecutor.flushAll() + verify(spyViewContainer).fadeInIndicator(any(), any()) + } + + @Test + fun testTransitionIndicator_secondTypeNoIndicator_callsFadeOut() { + val spyViewContainer = setupSpyViewContainer() + spyViewContainer.transitionIndicator( + taskInfo, + displayController, + DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR, + DesktopModeVisualIndicator.IndicatorType.NO_INDICATOR, + ) + desktopExecutor.flushAll() + verify(spyViewContainer) + .fadeOutIndicator( + any(), + eq(DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR), + anyOrNull(), + ) + } + + @Test + fun testTransitionIndicator_differentTypes_callsTransitionIndicator() { + val spyViewContainer = setupSpyViewContainer() + spyViewContainer.transitionIndicator( + taskInfo, + displayController, + DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR, + DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR, + ) + desktopExecutor.flushAll() + verify(spyViewContainer) + .transitionIndicator( + any(), + any(), + eq(DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR), + eq(DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR), + ) + } + + @Test + fun testFadeInBoundsCalculation() { + val spyIndicator = setupSpyViewContainer() + val animator = + spyIndicator.indicatorView?.let { + VisualIndicatorViewContainer.VisualIndicatorAnimator.fadeBoundsIn( + it, + DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR, + displayLayout, + bubbleDropTargetBoundsProvider, + ) + } + assertThat(animator?.indicatorStartBounds).isEqualTo(Rect(15, 15, 985, 985)) + assertThat(animator?.indicatorEndBounds).isEqualTo(Rect(0, 0, 1000, 1000)) + } + + @Test + fun testFadeOutBoundsCalculation() { + val spyIndicator = setupSpyViewContainer() + val animator = + spyIndicator.indicatorView?.let { + VisualIndicatorViewContainer.VisualIndicatorAnimator.fadeBoundsOut( + it, + DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR, + displayLayout, + bubbleDropTargetBoundsProvider, + ) + } + assertThat(animator?.indicatorStartBounds).isEqualTo(Rect(0, 0, 1000, 1000)) + assertThat(animator?.indicatorEndBounds).isEqualTo(Rect(15, 15, 985, 985)) + } + + @Test + fun testChangeIndicatorTypeBoundsCalculation() { + // Test fullscreen to split-left bounds. + var animator = + VisualIndicatorViewContainer.VisualIndicatorAnimator.animateIndicatorType( + view, + displayLayout, + DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR, + DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR, + bubbleDropTargetBoundsProvider, + ) + // Test desktop to split-right bounds. + animator = + VisualIndicatorViewContainer.VisualIndicatorAnimator.animateIndicatorType( + view, + displayLayout, + DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR, + DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR, + bubbleDropTargetBoundsProvider, + ) + } + + private fun setupSpyViewContainer(): VisualIndicatorViewContainer { + val viewContainer = + VisualIndicatorViewContainer( + desktopExecutor, + mainExecutor, + SurfaceControl.Builder(), + syncQueue, + mockSurfaceControlViewHostFactory, + bubbleDropTargetBoundsProvider, + ) + viewContainer.createView( + context, + mock(Display::class.java), + displayLayout, + taskInfo, + taskSurface, + ) + desktopExecutor.flushAll() + viewContainer.indicatorView?.background = mockBackground + whenever(mockBackground.findDrawableByLayerId(anyInt())) + .thenReturn(mock(Drawable::class.java)) + return spy(viewContainer) + } + + private fun createTaskInfo(): RunningTaskInfo { + val taskDescriptionBuilder = ActivityManager.TaskDescription.Builder() + return TestRunningTaskInfoBuilder() + .setDisplayId(Display.DEFAULT_DISPLAY) + .setTaskDescriptionBuilder(taskDescriptionBuilder) + .setVisible(true) + .build() + } + + companion object { + private val DISPLAY_BOUNDS = Rect(0, 0, 1000, 1000) + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt index dfb1b0c8c642..9cb2a055e45d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt @@ -16,9 +16,12 @@ package com.android.wm.shell.desktopmode.compatui +import android.content.ComponentName import android.content.Intent +import android.content.pm.PackageManager import android.os.Binder import android.testing.AndroidTestingRunner +import android.testing.TestableContext import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CHANGE import android.view.WindowManager.TRANSIT_CLOSE @@ -37,6 +40,7 @@ import com.android.wm.shell.shared.desktopmode.DesktopModeCompatPolicy import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.TransitionInfoBuilder import com.android.wm.shell.transition.Transitions +import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModelTestsBase.Companion.HOME_LAUNCHER_PACKAGE_NAME import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test @@ -44,6 +48,7 @@ import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyInt import org.mockito.kotlin.any import org.mockito.kotlin.mock +import org.mockito.kotlin.spy import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @@ -62,16 +67,23 @@ class SystemModalsTransitionHandlerTest : ShellTestCase() { private val desktopRepository = mock<DesktopRepository>() private val startT = mock<SurfaceControl.Transaction>() private val finishT = mock<SurfaceControl.Transaction>() + private val packageManager = mock<PackageManager>() + private val componentName = mock<ComponentName>() + private lateinit var spyContext: TestableContext private lateinit var transitionHandler: SystemModalsTransitionHandler private lateinit var desktopModeCompatPolicy: DesktopModeCompatPolicy @Before fun setUp() { + spyContext = spy(mContext) // Simulate having one Desktop task so that we see Desktop Mode as active whenever(desktopUserRepositories.current).thenReturn(desktopRepository) whenever(desktopRepository.getVisibleTaskCount(anyInt())).thenReturn(1) - desktopModeCompatPolicy = DesktopModeCompatPolicy(context) + whenever(spyContext.packageManager).thenReturn(packageManager) + whenever(componentName.packageName).thenReturn(HOME_LAUNCHER_PACKAGE_NAME) + whenever(packageManager.getHomeActivities(ArrayList())).thenReturn(componentName) + desktopModeCompatPolicy = DesktopModeCompatPolicy(spyContext) transitionHandler = createTransitionHandler() } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt index 86e8142b1aaa..08b9e0413e9d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt @@ -26,6 +26,8 @@ import com.android.modules.utils.testing.ExtendedMockitoRule import com.android.window.flags.Flags import com.android.wm.shell.ShellTestCase import com.android.wm.shell.desktopmode.CaptionState +import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger +import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.DesktopUiEventEnum import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository import com.android.wm.shell.desktopmode.education.AppHandleEducationController.Companion.APP_HANDLE_EDUCATION_DELAY_MILLIS import com.android.wm.shell.desktopmode.education.AppHandleEducationController.Companion.TOOLTIP_VISIBLE_DURATION_MILLIS @@ -86,6 +88,7 @@ class AppHandleEducationControllerTest : ShellTestCase() { @Mock private lateinit var mockDataStoreRepository: AppHandleEducationDatastoreRepository @Mock private lateinit var mockCaptionHandleRepository: WindowDecorCaptionHandleRepository @Mock private lateinit var mockTooltipController: DesktopWindowingEducationTooltipController + @Mock private lateinit var mockDesktopModeUiEventLogger: DesktopModeUiEventLogger @Before fun setUp() { @@ -105,6 +108,7 @@ class AppHandleEducationControllerTest : ShellTestCase() { mockTooltipController, testScope.backgroundScope, Dispatchers.Main, + mockDesktopModeUiEventLogger, ) } @@ -123,6 +127,8 @@ class AppHandleEducationControllerTest : ShellTestCase() { verify(mockTooltipController, times(1)).showEducationTooltip(any(), any()) verify(mockDataStoreRepository, times(1)) .updateAppHandleHintViewedTimestampMillis(eq(true)) + verify(mockDesktopModeUiEventLogger, times(1)) + .log(any(), eq(DesktopUiEventEnum.APP_HANDLE_EDUCATION_TOOLTIP_SHOWN)) } @Test @@ -155,6 +161,8 @@ class AppHandleEducationControllerTest : ShellTestCase() { verify(mockTooltipController, times(1)).showEducationTooltip(any(), any()) verify(mockDataStoreRepository, times(1)) .updateEnterDesktopModeHintViewedTimestampMillis(eq(true)) + verify(mockDesktopModeUiEventLogger, times(1)) + .log(any(), eq(DesktopUiEventEnum.ENTER_DESKTOP_MODE_EDUCATION_TOOLTIP_SHOWN)) } @Test @@ -170,6 +178,8 @@ class AppHandleEducationControllerTest : ShellTestCase() { verify(mockTooltipController, times(1)).showEducationTooltip(any(), any()) verify(mockDataStoreRepository, times(1)) .updateExitDesktopModeHintViewedTimestampMillis(eq(true)) + verify(mockDesktopModeUiEventLogger, times(1)) + .log(any(), eq(DesktopUiEventEnum.EXIT_DESKTOP_MODE_EDUCATION_TOOLTIP_SHOWN)) } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java index 439be9155b26..fd5e567f69ed 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java @@ -34,6 +34,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -293,6 +294,31 @@ public class RecentsTransitionHandlerTest extends ShellTestCase { @Test @EnableFlags(FLAG_ENABLE_DESKTOP_RECENTS_TRANSITIONS_CORNERS_BUGFIX) + public void testMerge_openingTasks_callsOnTasksAppeared() throws Exception { + final IRecentsAnimationRunner animationRunner = mock(IRecentsAnimationRunner.class); + TransitionInfo mergeTransitionInfo = new TransitionInfoBuilder(TRANSIT_OPEN) + .addChange(TRANSIT_OPEN, new TestRunningTaskInfoBuilder().build()) + .build(); + final IBinder transition = startRecentsTransition(/* synthetic= */ false, animationRunner); + SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class); + mRecentsTransitionHandler.startAnimation( + transition, createTransitionInfo(), new StubTransaction(), new StubTransaction(), + mock(Transitions.TransitionFinishCallback.class)); + + mRecentsTransitionHandler.findController(transition).merge( + mergeTransitionInfo, + new StubTransaction(), + finishT, + transition, + mock(Transitions.TransitionFinishCallback.class)); + mMainExecutor.flushAll(); + + verify(animationRunner).onTasksAppeared( + /* appearedTargets= */ any(), eq(mergeTransitionInfo)); + } + + @Test + @EnableFlags(FLAG_ENABLE_DESKTOP_RECENTS_TRANSITIONS_CORNERS_BUGFIX) public void testMergeAndFinish_openingFreeformTasks_setsCornerRadius() { ActivityManager.RunningTaskInfo freeformTask = new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicyTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicyTest.kt index ae1e4e0fbbc1..f69bf34ea3f7 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicyTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicyTest.kt @@ -30,6 +30,7 @@ import com.android.internal.R import com.android.window.flags.Flags import com.android.wm.shell.ShellTestCase import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask +import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModelTestsBase.Companion.HOME_LAUNCHER_PACKAGE_NAME import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges import org.junit.Assert.assertFalse @@ -52,10 +53,14 @@ import org.mockito.kotlin.whenever class DesktopModeCompatPolicyTest : ShellTestCase() { @get:Rule val compatRule = PlatformCompatChangeRule() private lateinit var desktopModeCompatPolicy: DesktopModeCompatPolicy + private val packageManager: PackageManager = mock() + private val homeActivities = ComponentName(HOME_LAUNCHER_PACKAGE_NAME, /* class */ "") @Before fun setUp() { desktopModeCompatPolicy = DesktopModeCompatPolicy(mContext) + whenever(packageManager.getHomeActivities(any())).thenReturn(homeActivities) + mContext.setMockPackageManager(packageManager) } @Test @@ -128,10 +133,6 @@ class DesktopModeCompatPolicyTest : ShellTestCase() { @Test fun testIsTopActivityExemptFromDesktopWindowing_defaultHomePackage() { - val packageManager: PackageManager = mock() - val homeActivities = ComponentName("defaultHomePackage", /* class */ "") - whenever(packageManager.getHomeActivities(any())).thenReturn(homeActivities) - mContext.setMockPackageManager(packageManager) assertTrue(desktopModeCompatPolicy.isTopActivityExemptFromDesktopWindowing( createFreeformTask(/* displayId */ 0) .apply { @@ -142,10 +143,6 @@ class DesktopModeCompatPolicyTest : ShellTestCase() { @Test fun testIsTopActivityExemptFromDesktopWindowing_defaultHomePackage_notDisplayed() { - val packageManager: PackageManager = mock() - val homeActivities = ComponentName("defaultHomePackage", /* class */ "") - whenever(packageManager.getHomeActivities(any())).thenReturn(homeActivities) - mContext.setMockPackageManager(packageManager) assertFalse(desktopModeCompatPolicy.isTopActivityExemptFromDesktopWindowing( createFreeformTask(/* displayId */ 0) .apply { @@ -155,6 +152,21 @@ class DesktopModeCompatPolicyTest : ShellTestCase() { } @Test + fun testIsTopActivityExemptFromDesktopWindowing_defaultHomePackage_notYetAvailable() { + val emptyHomeActivities: ComponentName = mock() + mContext.setMockPackageManager(packageManager) + + whenever(emptyHomeActivities.packageName).thenReturn(null) + whenever(packageManager.getHomeActivities(any())).thenReturn(emptyHomeActivities) + + assertTrue(desktopModeCompatPolicy.isTopActivityExemptFromDesktopWindowing( + createFreeformTask(/* displayId */ 0) + .apply { + isTopActivityNoDisplay = false + })) + } + + @Test @EnableFlags(Flags.FLAG_EXCLUDE_CAPTION_FROM_APP_BOUNDS) @DisableCompatChanges(ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED) fun testShouldExcludeCaptionFromAppBounds_resizeable_false() { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt index 391d46287498..741a0fdcf63c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt @@ -157,23 +157,40 @@ class DesktopModeStatusTest : ShellTestCase() { } @Test - fun isInternalDisplayEligibleToHostDesktops_configDEModeOn_returnsTrue() { + fun isDeviceEligibleForDesktopMode_configDEModeOnAndIntDispHostsDesktop_returnsTrue() { + doReturn(true).whenever(mockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported)) doReturn(true).whenever(mockResources).getBoolean(eq(R.bool.config_canInternalDisplayHostDesktops)) - assertThat(DesktopModeStatus.isInternalDisplayEligibleToHostDesktops(mockContext)).isTrue() + assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isTrue() + } + + @Test + fun isDeviceEligibleForDesktopMode_configDEModeOffAndIntDispHostsDesktop_returnsFalse() { + doReturn(false).whenever(mockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported)) + doReturn(true).whenever(mockResources).getBoolean(eq(R.bool.config_canInternalDisplayHostDesktops)) + + assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isFalse() + } + + @Test + fun isDeviceEligibleForDesktopMode_configDEModeOnAndIntDispHostsDesktopOff_returnsFalse() { + doReturn(true).whenever(mockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported)) + doReturn(false).whenever(mockResources).getBoolean(eq(R.bool.config_canInternalDisplayHostDesktops)) + + assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isFalse() } @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) @Test fun isInternalDisplayEligibleToHostDesktops_supportFlagOff_returnsFalse() { - assertThat(DesktopModeStatus.isInternalDisplayEligibleToHostDesktops(mockContext)).isFalse() + assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isFalse() } @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) @Test fun isInternalDisplayEligibleToHostDesktops_supportFlagOn_returnsFalse() { - assertThat(DesktopModeStatus.isInternalDisplayEligibleToHostDesktops(mockContext)).isFalse() + assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isFalse() } @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) @@ -183,7 +200,7 @@ class DesktopModeStatusTest : ShellTestCase() { eq(R.bool.config_isDesktopModeDevOptionSupported) ) - assertThat(DesktopModeStatus.isInternalDisplayEligibleToHostDesktops(mockContext)).isTrue() + assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isTrue() } @DisableFlags(Flags.FLAG_SHOW_DESKTOP_EXPERIENCE_DEV_OPTION) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java index 82392e0e3bc0..18fdbeff40f4 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/DefaultTransitionHandlerTest.java @@ -48,6 +48,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.internal.jank.InteractionJankMonitor; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.TestShellExecutor; @@ -96,7 +97,7 @@ public class DefaultTransitionHandlerTest extends ShellTestCase { mTransitionHandler = new DefaultTransitionHandler( mContext, mShellInit, mDisplayController, mTransactionPool, mMainExecutor, mMainHandler, mAnimExecutor, - mRootTaskDisplayAreaOrganizer); + mRootTaskDisplayAreaOrganizer, mock(InteractionJankMonitor.class)); mShellInit.init(); } 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 49812d381178..da41a23f066c 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 @@ -28,7 +28,6 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.Intent.ACTION_MAIN -import android.content.pm.PackageManager import android.graphics.Rect import android.graphics.Region import android.hardware.display.DisplayManager @@ -310,14 +309,10 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) fun testDecorationIsNotCreatedForDefaultHomePackage() { - val packageManager: PackageManager = org.mockito.kotlin.mock() - val homeActivities = ComponentName("defaultHomePackage", /* class */ "") val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN).apply { - baseActivity = homeActivities + baseActivity = homeComponentName isTopActivityNoDisplay = false } - mContext.setMockPackageManager(packageManager) - whenever(packageManager.getHomeActivities(any())).thenReturn(homeActivities) onTaskOpening(task) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt index 9f106da9f4b9..e40034b09f39 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt @@ -20,7 +20,9 @@ import android.app.ActivityManager.RunningTaskInfo import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW import android.app.WindowConfiguration.WindowingMode +import android.content.ComponentName import android.content.pm.ActivityInfo +import android.content.pm.PackageManager import android.graphics.Rect import android.hardware.input.InputManager import android.os.Handler @@ -146,8 +148,10 @@ open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() { protected val mockDesktopRepository: DesktopRepository = mock<DesktopRepository>() protected val mockRecentsTransitionHandler = mock<RecentsTransitionHandler>() protected val motionEvent = mock<MotionEvent>() - val displayLayout = mock<DisplayLayout>() - val display = mock<Display>() + private val displayLayout = mock<DisplayLayout>() + private val display = mock<Display>() + private val packageManager = mock<PackageManager>() + protected val homeComponentName = ComponentName(HOME_LAUNCHER_PACKAGE_NAME, /* class */ "") protected lateinit var spyContext: TestableContext private lateinit var desktopModeEventLogger: DesktopModeEventLogger @@ -178,7 +182,7 @@ open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() { whenever(mockDisplayController.getDisplay(any())).thenReturn(display) whenever(mockDesktopUserRepositories.getProfile(anyInt())) .thenReturn(mockDesktopRepository) - desktopModeCompatPolicy = DesktopModeCompatPolicy(context) + desktopModeCompatPolicy = DesktopModeCompatPolicy(spyContext) desktopModeWindowDecorViewModel = DesktopModeWindowDecorViewModel( spyContext, testShellExecutor, @@ -273,6 +277,8 @@ open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() { whenever(displayLayout.getStableBounds(any())).thenAnswer { i -> (i.arguments.first() as Rect).set(STABLE_BOUNDS) } + spyContext.setMockPackageManager(packageManager) + whenever(packageManager.getHomeActivities(ArrayList())).thenReturn(homeComponentName) } @After @@ -354,5 +360,6 @@ open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() { val STABLE_INSETS = Rect(0, 100, 0, 0) val INITIAL_BOUNDS = Rect(0, 0, 100, 100) val STABLE_BOUNDS = Rect(0, 0, 1000, 1000) + val HOME_LAUNCHER_PACKAGE_NAME = "com.android.launcher" } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt index 63babc5e1c3c..937938df82c8 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt @@ -249,6 +249,25 @@ class MultiDisplayVeiledResizeTaskPositionerTest : ShellTestCase() { } @Test + fun testDragResize_movesTaskOnSameDisplay_noPxDpConversion() = runOnUiThread { + taskPositioner.onDragPositioningStart( + CTRL_TYPE_UNDEFINED, + DISPLAY_ID_0, + STARTING_BOUNDS.left.toFloat(), + STARTING_BOUNDS.top.toFloat(), + ) + + taskPositioner.onDragPositioningEnd( + DISPLAY_ID_0, + STARTING_BOUNDS.left.toFloat() + 70, + STARTING_BOUNDS.top.toFloat() + 20, + ) + + verify(spyDisplayLayout0, never()).localPxToGlobalDp(any(), any()) + verify(spyDisplayLayout0, never()).globalDpToLocalPx(any(), any()) + } + + @Test fun testDragResize_movesTaskToNewDisplay() = runOnUiThread { taskPositioner.onDragPositioningStart( CTRL_TYPE_UNDEFINED, diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp index dbb891455ddd..e693fcfd3918 100644 --- a/libs/androidfw/ApkAssets.cpp +++ b/libs/androidfw/ApkAssets.cpp @@ -162,10 +162,13 @@ const std::string& ApkAssets::GetDebugName() const { return assets_provider_->GetDebugName(); } -bool ApkAssets::IsUpToDate() const { +UpToDate ApkAssets::IsUpToDate() const { // Loaders are invalidated by the app, not the system, so assume they are up to date. - return IsLoader() || ((!loaded_idmap_ || loaded_idmap_->IsUpToDate()) - && assets_provider_->IsUpToDate()); + if (IsLoader()) { + return UpToDate::Always; + } + const auto idmap_res = loaded_idmap_ ? loaded_idmap_->IsUpToDate() : UpToDate::Always; + return combine(idmap_res, [this] { return assets_provider_->IsUpToDate(); }); } } // namespace android diff --git a/libs/androidfw/AssetsProvider.cpp b/libs/androidfw/AssetsProvider.cpp index 2d3c06506a1f..808509120462 100644 --- a/libs/androidfw/AssetsProvider.cpp +++ b/libs/androidfw/AssetsProvider.cpp @@ -24,9 +24,27 @@ #include <ziparchive/zip_archive.h> namespace android { -namespace { -constexpr const char* kEmptyDebugString = "<empty>"; -} // namespace + +static constexpr std::string_view kEmptyDebugString = "<empty>"; + +std::unique_ptr<AssetsProvider> AssetsProvider::CreateWithOverride( + std::unique_ptr<AssetsProvider> provider, std::unique_ptr<AssetsProvider> override) { + if (provider == nullptr) { + return {}; + } + if (override == nullptr) { + return provider; + } + return MultiAssetsProvider::Create(std::move(override), std::move(provider)); +} + +std::unique_ptr<AssetsProvider> AssetsProvider::CreateFromNullable( + std::unique_ptr<AssetsProvider> nullable) { + if (nullable) { + return nullable; + } + return EmptyAssetsProvider::Create(); +} std::unique_ptr<Asset> AssetsProvider::Open(const std::string& path, Asset::AccessMode mode, bool* file_exists) const { @@ -86,11 +104,9 @@ void ZipAssetsProvider::ZipCloser::operator()(ZipArchive* a) const { } ZipAssetsProvider::ZipAssetsProvider(ZipArchiveHandle handle, PathOrDebugName&& path, - package_property_t flags, time_t last_mod_time) - : zip_handle_(handle), - name_(std::move(path)), - flags_(flags), - last_mod_time_(last_mod_time) {} + package_property_t flags, ModDate last_mod_time) + : zip_handle_(handle), name_(std::move(path)), flags_(flags), last_mod_time_(last_mod_time) { +} std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path, package_property_t flags, @@ -104,10 +120,10 @@ std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path, return {}; } - struct stat sb{.st_mtime = -1}; + ModDate mod_date = kInvalidModDate; // Skip all up-to-date checks if the file won't ever change. - if (!isReadonlyFilesystem(path.c_str())) { - if ((released_fd < 0 ? stat(path.c_str(), &sb) : fstat(released_fd, &sb)) < 0) { + if (isKnownWritablePath(path.c_str()) || !isReadonlyFilesystem(GetFileDescriptor(handle))) { + if (mod_date = getFileModDate(GetFileDescriptor(handle)); mod_date == kInvalidModDate) { // Stat requires execute permissions on all directories path to the file. If the process does // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will // always have to return true. @@ -116,7 +132,7 @@ std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path, } return std::unique_ptr<ZipAssetsProvider>( - new ZipAssetsProvider(handle, PathOrDebugName::Path(std::move(path)), flags, sb.st_mtime)); + new ZipAssetsProvider(handle, PathOrDebugName::Path(std::move(path)), flags, mod_date)); } std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(base::unique_fd fd, @@ -137,10 +153,10 @@ std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(base::unique_fd fd, return {}; } - struct stat sb{.st_mtime = -1}; + ModDate mod_date = kInvalidModDate; // Skip all up-to-date checks if the file won't ever change. if (!isReadonlyFilesystem(released_fd)) { - if (fstat(released_fd, &sb) < 0) { + if (mod_date = getFileModDate(released_fd); mod_date == kInvalidModDate) { // Stat requires execute permissions on all directories path to the file. If the process does // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will // always have to return true. @@ -150,7 +166,7 @@ std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(base::unique_fd fd, } return std::unique_ptr<ZipAssetsProvider>(new ZipAssetsProvider( - handle, PathOrDebugName::DebugName(std::move(friendly_name)), flags, sb.st_mtime)); + handle, PathOrDebugName::DebugName(std::move(friendly_name)), flags, mod_date)); } std::unique_ptr<Asset> ZipAssetsProvider::OpenInternal(const std::string& path, @@ -282,21 +298,16 @@ const std::string& ZipAssetsProvider::GetDebugName() const { return name_.GetDebugName(); } -bool ZipAssetsProvider::IsUpToDate() const { - if (last_mod_time_ == -1) { - return true; +UpToDate ZipAssetsProvider::IsUpToDate() const { + if (last_mod_time_ == kInvalidModDate) { + return UpToDate::Always; } - struct stat sb{}; - if (fstat(GetFileDescriptor(zip_handle_.get()), &sb) < 0) { - // If fstat fails on the zip archive, return true so the zip archive the resource system does - // attempt to refresh the ApkAsset. - return true; - } - return last_mod_time_ == sb.st_mtime; + return fromBool(last_mod_time_ == getFileModDate(GetFileDescriptor(zip_handle_.get()))); } -DirectoryAssetsProvider::DirectoryAssetsProvider(std::string&& path, time_t last_mod_time) - : dir_(std::move(path)), last_mod_time_(last_mod_time) {} +DirectoryAssetsProvider::DirectoryAssetsProvider(std::string&& path, ModDate last_mod_time) + : dir_(std::move(path)), last_mod_time_(last_mod_time) { +} std::unique_ptr<DirectoryAssetsProvider> DirectoryAssetsProvider::Create(std::string path) { struct stat sb; @@ -317,7 +328,7 @@ std::unique_ptr<DirectoryAssetsProvider> DirectoryAssetsProvider::Create(std::st const bool isReadonly = isReadonlyFilesystem(path.c_str()); return std::unique_ptr<DirectoryAssetsProvider>( - new DirectoryAssetsProvider(std::move(path), isReadonly ? -1 : sb.st_mtime)); + new DirectoryAssetsProvider(std::move(path), isReadonly ? kInvalidModDate : getModDate(sb))); } std::unique_ptr<Asset> DirectoryAssetsProvider::OpenInternal(const std::string& path, @@ -346,17 +357,11 @@ const std::string& DirectoryAssetsProvider::GetDebugName() const { return dir_; } -bool DirectoryAssetsProvider::IsUpToDate() const { - if (last_mod_time_ == -1) { - return true; +UpToDate DirectoryAssetsProvider::IsUpToDate() const { + if (last_mod_time_ == kInvalidModDate) { + return UpToDate::Always; } - struct stat sb; - if (stat(dir_.c_str(), &sb) < 0) { - // If stat fails on the zip archive, return true so the zip archive the resource system does - // attempt to refresh the ApkAsset. - return true; - } - return last_mod_time_ == sb.st_mtime; + return fromBool(last_mod_time_ == getFileModDate(dir_.c_str())); } MultiAssetsProvider::MultiAssetsProvider(std::unique_ptr<AssetsProvider>&& primary, @@ -397,8 +402,8 @@ const std::string& MultiAssetsProvider::GetDebugName() const { return debug_name_; } -bool MultiAssetsProvider::IsUpToDate() const { - return primary_->IsUpToDate() && secondary_->IsUpToDate(); +UpToDate MultiAssetsProvider::IsUpToDate() const { + return combine(primary_->IsUpToDate(), [this] { return secondary_->IsUpToDate(); }); } EmptyAssetsProvider::EmptyAssetsProvider(std::optional<std::string>&& path) : @@ -438,12 +443,12 @@ const std::string& EmptyAssetsProvider::GetDebugName() const { if (path_.has_value()) { return *path_; } - const static std::string kEmpty = kEmptyDebugString; + constexpr static std::string kEmpty{kEmptyDebugString}; return kEmpty; } -bool EmptyAssetsProvider::IsUpToDate() const { - return true; +UpToDate EmptyAssetsProvider::IsUpToDate() const { + return UpToDate::Always; } } // namespace android diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp index 095be57a5dc8..f0ef97e5bdcc 100644 --- a/libs/androidfw/Idmap.cpp +++ b/libs/androidfw/Idmap.cpp @@ -22,9 +22,10 @@ #include "android-base/logging.h" #include "android-base/stringprintf.h" #include "android-base/utf8.h" -#include "androidfw/misc.h" +#include "androidfw/AssetManager.h" #include "androidfw/ResourceTypes.h" #include "androidfw/Util.h" +#include "androidfw/misc.h" #include "utils/ByteOrder.h" #include "utils/Trace.h" @@ -280,11 +281,16 @@ LoadedIdmap::LoadedIdmap(const std::string& idmap_path, const Idmap_header* head configurations_(configs), overlay_entries_(overlay_entries), string_pool_(std::move(string_pool)), - idmap_fd_( - android::base::utf8::open(idmap_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY | O_PATH)), overlay_apk_path_(overlay_apk_path), target_apk_path_(target_apk_path), - idmap_last_mod_time_(getFileModDate(idmap_fd_.get())) { + idmap_last_mod_time_(kInvalidModDate) { + if (!isReadonlyFilesystem(std::string(overlay_apk_path_).c_str()) || + !(target_apk_path_ == AssetManager::TARGET_APK_PATH || + isReadonlyFilesystem(std::string(target_apk_path_).c_str()))) { + idmap_fd_.reset( + android::base::utf8::open(idmap_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY | O_PATH)); + idmap_last_mod_time_ = getFileModDate(idmap_fd_); + } } std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPiece idmap_data) { @@ -405,8 +411,11 @@ std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPie std::move(idmap_string_pool),*overlay_path, *target_path)); } -bool LoadedIdmap::IsUpToDate() const { - return idmap_last_mod_time_ == getFileModDate(idmap_fd_.get()); +UpToDate LoadedIdmap::IsUpToDate() const { + if (idmap_last_mod_time_ == kInvalidModDate) { + return UpToDate::Always; + } + return fromBool(idmap_last_mod_time_ == getFileModDate(idmap_fd_.get())); } } // namespace android diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 978bc768cd3d..a18c5f5f92f6 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -152,12 +152,11 @@ static void fill9patchOffsets(Res_png_9patch* patch) { patch->colorsOffset = patch->yDivsOffset + (patch->numYDivs * sizeof(int32_t)); } -void Res_value::copyFrom_dtoh(const Res_value& src) -{ - size = dtohs(src.size); - res0 = src.res0; - dataType = src.dataType; - data = dtohl(src.data); +void Res_value::copyFrom_dtoh_slow(const Res_value& src) { + size = dtohs(src.size); + res0 = src.res0; + dataType = src.dataType; + data = dtohl(src.data); } void Res_png_9patch::deviceToFile() @@ -2035,16 +2034,6 @@ status_t ResXMLTree::validateNode(const ResXMLTree_node* node) const // -------------------------------------------------------------------- // -------------------------------------------------------------------- -void ResTable_config::copyFromDeviceNoSwap(const ResTable_config& o) { - const size_t size = dtohl(o.size); - if (size >= sizeof(ResTable_config)) { - *this = o; - } else { - memcpy(this, &o, size); - memset(((uint8_t*)this)+size, 0, sizeof(ResTable_config)-size); - } -} - /* static */ size_t unpackLanguageOrRegion(const char in[2], const char base, char out[4]) { if (in[0] & 0x80) { @@ -2109,34 +2098,33 @@ size_t ResTable_config::unpackRegion(char region[4]) const { return unpackLanguageOrRegion(this->country, '0', region); } - -void ResTable_config::copyFromDtoH(const ResTable_config& o) { - copyFromDeviceNoSwap(o); - size = sizeof(ResTable_config); - mcc = dtohs(mcc); - mnc = dtohs(mnc); - density = dtohs(density); - screenWidth = dtohs(screenWidth); - screenHeight = dtohs(screenHeight); - sdkVersion = dtohs(sdkVersion); - minorVersion = dtohs(minorVersion); - smallestScreenWidthDp = dtohs(smallestScreenWidthDp); - screenWidthDp = dtohs(screenWidthDp); - screenHeightDp = dtohs(screenHeightDp); -} - -void ResTable_config::swapHtoD() { - size = htodl(size); - mcc = htods(mcc); - mnc = htods(mnc); - density = htods(density); - screenWidth = htods(screenWidth); - screenHeight = htods(screenHeight); - sdkVersion = htods(sdkVersion); - minorVersion = htods(minorVersion); - smallestScreenWidthDp = htods(smallestScreenWidthDp); - screenWidthDp = htods(screenWidthDp); - screenHeightDp = htods(screenHeightDp); +void ResTable_config::copyFromDtoH_slow(const ResTable_config& o) { + copyFromDeviceNoSwap(o); + size = sizeof(ResTable_config); + mcc = dtohs(mcc); + mnc = dtohs(mnc); + density = dtohs(density); + screenWidth = dtohs(screenWidth); + screenHeight = dtohs(screenHeight); + sdkVersion = dtohs(sdkVersion); + minorVersion = dtohs(minorVersion); + smallestScreenWidthDp = dtohs(smallestScreenWidthDp); + screenWidthDp = dtohs(screenWidthDp); + screenHeightDp = dtohs(screenHeightDp); +} + +void ResTable_config::swapHtoD_slow() { + size = htodl(size); + mcc = htods(mcc); + mnc = htods(mnc); + density = htods(density); + screenWidth = htods(screenWidth); + screenHeight = htods(screenHeight); + sdkVersion = htods(sdkVersion); + minorVersion = htods(minorVersion); + smallestScreenWidthDp = htods(smallestScreenWidthDp); + screenWidthDp = htods(screenWidthDp); + screenHeightDp = htods(screenHeightDp); } /* static */ inline int compareLocales(const ResTable_config &l, const ResTable_config &r) { @@ -2149,7 +2137,7 @@ void ResTable_config::swapHtoD() { // systems should happen very infrequently (if at all.) // The comparison code relies on memcmp low-level optimizations that make it // more efficient than strncmp. - const char emptyScript[sizeof(l.localeScript)] = {'\0', '\0', '\0', '\0'}; + static constexpr char emptyScript[sizeof(l.localeScript)] = {'\0', '\0', '\0', '\0'}; const char *lScript = l.localeScriptWasComputed ? emptyScript : l.localeScript; const char *rScript = r.localeScriptWasComputed ? emptyScript : r.localeScript; diff --git a/libs/androidfw/Util.cpp b/libs/androidfw/Util.cpp index be55fe8b4bb6..86c459fb4647 100644 --- a/libs/androidfw/Util.cpp +++ b/libs/androidfw/Util.cpp @@ -32,13 +32,18 @@ namespace android { namespace util { void ReadUtf16StringFromDevice(const uint16_t* src, size_t len, std::string* out) { - char buf[5]; - while (*src && len != 0) { - char16_t c = static_cast<char16_t>(dtohs(*src)); - utf16_to_utf8(&c, 1, buf, sizeof(buf)); - out->append(buf, strlen(buf)); - ++src; - --len; + static constexpr bool kDeviceEndiannessSame = dtohs(0x1001) == 0x1001; + if constexpr (kDeviceEndiannessSame) { + *out = Utf16ToUtf8({(const char16_t*)src, strnlen16((const char16_t*)src, len)}); + } else { + char buf[5]; + while (*src && len != 0) { + char16_t c = static_cast<char16_t>(dtohs(*src)); + utf16_to_utf8(&c, 1, buf, sizeof(buf)); + out->append(buf, strlen(buf)); + ++src; + --len; + } } } @@ -63,8 +68,10 @@ std::string Utf16ToUtf8(StringPiece16 utf16) { } std::string utf8; - utf8.resize(utf8_length); - utf16_to_utf8(utf16.data(), utf16.length(), &*utf8.begin(), utf8_length + 1); + utf8.resize_and_overwrite(utf8_length, [&utf16](char* data, size_t size) { + utf16_to_utf8(utf16.data(), utf16.length(), data, size + 1); + return size; + }); return utf8; } diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h index 231808beb718..3f6f4661f2f7 100644 --- a/libs/androidfw/include/androidfw/ApkAssets.h +++ b/libs/androidfw/include/androidfw/ApkAssets.h @@ -116,7 +116,7 @@ class ApkAssets : public RefBase { return resources_asset_ != nullptr && resources_asset_->isAllocated(); } - bool IsUpToDate() const; + UpToDate IsUpToDate() const; // DANGER! // This is a destructive method that rips the assets provider out of ApkAssets object. diff --git a/libs/androidfw/include/androidfw/AssetsProvider.h b/libs/androidfw/include/androidfw/AssetsProvider.h index d33c325ff369..037f684f5b78 100644 --- a/libs/androidfw/include/androidfw/AssetsProvider.h +++ b/libs/androidfw/include/androidfw/AssetsProvider.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROIDFW_ASSETSPROVIDER_H -#define ANDROIDFW_ASSETSPROVIDER_H +#pragma once #include <memory> #include <string> @@ -37,6 +36,12 @@ namespace android { struct AssetsProvider { static constexpr off64_t kUnknownLength = -1; + static std::unique_ptr<AssetsProvider> CreateWithOverride( + std::unique_ptr<AssetsProvider> provider, std::unique_ptr<AssetsProvider> override); + + static std::unique_ptr<AssetsProvider> CreateFromNullable( + std::unique_ptr<AssetsProvider> nullable); + // Opens a file for reading. If `file_exists` is not null, it will be set to `true` if the file // exists. This is useful for determining if the file exists but was unable to be opened due to // an I/O error. @@ -58,7 +63,7 @@ struct AssetsProvider { WARN_UNUSED virtual const std::string& GetDebugName() const = 0; // Returns whether the interface provides the most recent version of its files. - WARN_UNUSED virtual bool IsUpToDate() const = 0; + WARN_UNUSED virtual UpToDate IsUpToDate() const = 0; // Creates an Asset from a file on disk. static std::unique_ptr<Asset> CreateAssetFromFile(const std::string& path); @@ -95,7 +100,7 @@ struct ZipAssetsProvider : public AssetsProvider { WARN_UNUSED std::optional<std::string_view> GetPath() const override; WARN_UNUSED const std::string& GetDebugName() const override; - WARN_UNUSED bool IsUpToDate() const override; + WARN_UNUSED UpToDate IsUpToDate() const override; WARN_UNUSED std::optional<uint32_t> GetCrc(std::string_view path) const; ~ZipAssetsProvider() override = default; @@ -106,7 +111,7 @@ struct ZipAssetsProvider : public AssetsProvider { private: struct PathOrDebugName; ZipAssetsProvider(ZipArchive* handle, PathOrDebugName&& path, package_property_t flags, - time_t last_mod_time); + ModDate last_mod_time); struct PathOrDebugName { static PathOrDebugName Path(std::string value) { @@ -135,7 +140,7 @@ struct ZipAssetsProvider : public AssetsProvider { std::unique_ptr<ZipArchive, ZipCloser> zip_handle_; PathOrDebugName name_; package_property_t flags_; - time_t last_mod_time_; + ModDate last_mod_time_; }; // Supplies assets from a root directory. @@ -147,7 +152,7 @@ struct DirectoryAssetsProvider : public AssetsProvider { WARN_UNUSED std::optional<std::string_view> GetPath() const override; WARN_UNUSED const std::string& GetDebugName() const override; - WARN_UNUSED bool IsUpToDate() const override; + WARN_UNUSED UpToDate IsUpToDate() const override; ~DirectoryAssetsProvider() override = default; protected: @@ -156,9 +161,9 @@ struct DirectoryAssetsProvider : public AssetsProvider { bool* file_exists) const override; private: - explicit DirectoryAssetsProvider(std::string&& path, time_t last_mod_time); + explicit DirectoryAssetsProvider(std::string&& path, ModDate last_mod_time); std::string dir_; - time_t last_mod_time_; + ModDate last_mod_time_; }; // Supplies assets from a `primary` asset provider and falls back to supplying assets from the @@ -172,7 +177,7 @@ struct MultiAssetsProvider : public AssetsProvider { WARN_UNUSED std::optional<std::string_view> GetPath() const override; WARN_UNUSED const std::string& GetDebugName() const override; - WARN_UNUSED bool IsUpToDate() const override; + WARN_UNUSED UpToDate IsUpToDate() const override; ~MultiAssetsProvider() override = default; protected: @@ -199,7 +204,7 @@ struct EmptyAssetsProvider : public AssetsProvider { WARN_UNUSED std::optional<std::string_view> GetPath() const override; WARN_UNUSED const std::string& GetDebugName() const override; - WARN_UNUSED bool IsUpToDate() const override; + WARN_UNUSED UpToDate IsUpToDate() const override; ~EmptyAssetsProvider() override = default; protected: @@ -212,5 +217,3 @@ struct EmptyAssetsProvider : public AssetsProvider { }; } // namespace android - -#endif /* ANDROIDFW_ASSETSPROVIDER_H */ diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h index d1db13f53069..0c0856315d8f 100644 --- a/libs/androidfw/include/androidfw/Idmap.h +++ b/libs/androidfw/include/androidfw/Idmap.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef IDMAP_H_ -#define IDMAP_H_ +#pragma once #include <memory> #include <string> @@ -32,6 +31,31 @@ namespace android { +// An enum that tracks more states than just 'up to date' or 'not' for a resources container: +// there are several cases where we know for sure that the object can't change and won't get +// out of date. Reporting those states to the managed layer allows it to stop checking here +// completely, speeding up the cache lookups by dozens of milliseconds. +enum class UpToDate : int { False, True, Always }; + +// Combines two UpToDate values, and only accesses the second one if it matters to the result. +template <class Getter> +UpToDate combine(UpToDate first, Getter secondGetter) { + switch (first) { + case UpToDate::False: + return UpToDate::False; + case UpToDate::True: { + const auto second = secondGetter(); + return second == UpToDate::False ? UpToDate::False : UpToDate::True; + } + case UpToDate::Always: + return secondGetter(); + } +} + +inline UpToDate fromBool(bool value) { + return value ? UpToDate::True : UpToDate::False; +} + class LoadedIdmap; class IdmapResMap; struct Idmap_header; @@ -197,7 +221,7 @@ class LoadedIdmap { // Returns whether the idmap file on disk has not been modified since the construction of this // LoadedIdmap. - bool IsUpToDate() const; + UpToDate IsUpToDate() const; protected: // Exposed as protected so that tests can subclass and mock this class out. @@ -237,5 +261,3 @@ class LoadedIdmap { }; } // namespace android - -#endif // IDMAP_H_ diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index 8b2871c21a1e..30594dcfa939 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -47,6 +47,8 @@ namespace android { +constexpr const bool kDeviceEndiannessSame = dtohs(0x1001) == 0x1001; + constexpr const uint32_t kIdmapMagic = 0x504D4449u; constexpr const uint32_t kIdmapCurrentVersion = 0x0000000Bu; @@ -408,7 +410,16 @@ struct Res_value typedef uint32_t data_type; data_type data; - void copyFrom_dtoh(const Res_value& src); + void copyFrom_dtoh(const Res_value& src) { + if constexpr (kDeviceEndiannessSame) { + *this = src; + } else { + copyFrom_dtoh_slow(src); + } + } + + private: + void copyFrom_dtoh_slow(const Res_value& src); }; /** @@ -1254,11 +1265,32 @@ struct ResTable_config // Varies in length from 3 to 8 chars. Zero-filled value. char localeNumberingSystem[8]; - void copyFromDeviceNoSwap(const ResTable_config& o); - - void copyFromDtoH(const ResTable_config& o); - - void swapHtoD(); + void copyFromDeviceNoSwap(const ResTable_config& o) { + const auto o_size = dtohl(o.size); + if (o_size >= sizeof(ResTable_config)) [[likely]] { + *this = o; + } else { + memcpy(this, &o, o_size); + memset(((uint8_t*)this) + o_size, 0, sizeof(ResTable_config) - o_size); + } + this->size = sizeof(*this); + } + + void copyFromDtoH(const ResTable_config& o) { + if constexpr (kDeviceEndiannessSame) { + copyFromDeviceNoSwap(o); + } else { + copyFromDtoH_slow(o); + } + } + + void swapHtoD() { + if constexpr (kDeviceEndiannessSame) { + ; // noop + } else { + swapHtoD_slow(); + } + } int compare(const ResTable_config& o) const; int compareLogical(const ResTable_config& o) const; @@ -1384,6 +1416,10 @@ struct ResTable_config bool isBetterThanBeforeLocale(const ResTable_config& o, const ResTable_config* requested) const; String8 toString() const; + + private: + void copyFromDtoH_slow(const ResTable_config& o); + void swapHtoD_slow(); }; /** diff --git a/libs/androidfw/include/androidfw/misc.h b/libs/androidfw/include/androidfw/misc.h index c9ba8a01a5e9..d8ca64a174a2 100644 --- a/libs/androidfw/include/androidfw/misc.h +++ b/libs/androidfw/include/androidfw/misc.h @@ -15,6 +15,7 @@ */ #pragma once +#include <sys/stat.h> #include <time.h> // @@ -64,10 +65,15 @@ ModDate getFileModDate(const char* fileName); /* same, but also returns -1 if the file has already been deleted */ ModDate getFileModDate(int fd); +// Extract the modification date from the stat structure. +ModDate getModDate(const struct ::stat& st); + // Check if |path| or |fd| resides on a readonly filesystem. bool isReadonlyFilesystem(const char* path); bool isReadonlyFilesystem(int fd); +bool isKnownWritablePath(const char* path); + } // namespace android // Whoever uses getFileModDate() will need this as well diff --git a/libs/androidfw/misc.cpp b/libs/androidfw/misc.cpp index 32f3624a3aee..26eb320805c9 100644 --- a/libs/androidfw/misc.cpp +++ b/libs/androidfw/misc.cpp @@ -16,10 +16,10 @@ #define LOG_TAG "misc" -// -// Miscellaneous utility functions. -// -#include <androidfw/misc.h> +#include "androidfw/misc.h" + +#include <errno.h> +#include <sys/stat.h> #include "android-base/logging.h" @@ -28,9 +28,7 @@ #include <sys/vfs.h> #endif // __linux__ -#include <errno.h> -#include <sys/stat.h> - +#include <array> #include <cstdio> #include <cstring> #include <tuple> @@ -40,28 +38,26 @@ namespace android { /* * Get a file's type. */ -FileType getFileType(const char* fileName) -{ - struct stat sb; - - if (stat(fileName, &sb) < 0) { - if (errno == ENOENT || errno == ENOTDIR) - return kFileTypeNonexistent; - else { - PLOG(ERROR) << "getFileType(): stat(" << fileName << ") failed"; - return kFileTypeUnknown; - } - } else { - if (S_ISREG(sb.st_mode)) - return kFileTypeRegular; - else if (S_ISDIR(sb.st_mode)) - return kFileTypeDirectory; - else if (S_ISCHR(sb.st_mode)) - return kFileTypeCharDev; - else if (S_ISBLK(sb.st_mode)) - return kFileTypeBlockDev; - else if (S_ISFIFO(sb.st_mode)) - return kFileTypeFifo; +FileType getFileType(const char* fileName) { + struct stat sb; + if (stat(fileName, &sb) < 0) { + if (errno == ENOENT || errno == ENOTDIR) + return kFileTypeNonexistent; + else { + PLOG(ERROR) << "getFileType(): stat(" << fileName << ") failed"; + return kFileTypeUnknown; + } + } else { + if (S_ISREG(sb.st_mode)) + return kFileTypeRegular; + else if (S_ISDIR(sb.st_mode)) + return kFileTypeDirectory; + else if (S_ISCHR(sb.st_mode)) + return kFileTypeCharDev; + else if (S_ISBLK(sb.st_mode)) + return kFileTypeBlockDev; + else if (S_ISFIFO(sb.st_mode)) + return kFileTypeFifo; #if defined(S_ISLNK) else if (S_ISLNK(sb.st_mode)) return kFileTypeSymlink; @@ -75,7 +71,7 @@ FileType getFileType(const char* fileName) } } -static ModDate getModDate(const struct stat& st) { +ModDate getModDate(const struct stat& st) { #ifdef _WIN32 return st.st_mtime; #elif defined(__APPLE__) @@ -113,8 +109,14 @@ bool isReadonlyFilesystem(const char*) { bool isReadonlyFilesystem(int) { return false; } +bool isKnownWritablePath(const char*) { + return false; +} #else // __linux__ bool isReadonlyFilesystem(const char* path) { + if (isKnownWritablePath(path)) { + return false; + } struct statfs sfs; if (::statfs(path, &sfs)) { PLOG(ERROR) << "isReadonlyFilesystem(): statfs(" << path << ") failed"; @@ -131,6 +133,13 @@ bool isReadonlyFilesystem(int fd) { } return (sfs.f_flags & ST_RDONLY) != 0; } + +bool isKnownWritablePath(const char* path) { + // We know that all paths in /data/ are writable. + static constexpr char kRwPrefix[] = "/data/"; + return strncmp(kRwPrefix, path, std::size(kRwPrefix) - 1) == 0; +} + #endif // __linux__ } // namespace android diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp index cb2e56f5f5e4..22b9e69500d9 100644 --- a/libs/androidfw/tests/Idmap_test.cpp +++ b/libs/androidfw/tests/Idmap_test.cpp @@ -218,10 +218,11 @@ TEST_F(IdmapTest, OverlayAssetsIsUpToDate) { auto apk_assets = ApkAssets::LoadOverlay(temp_file.path); ASSERT_NE(nullptr, apk_assets); - ASSERT_TRUE(apk_assets->IsUpToDate()); + ASSERT_TRUE(apk_assets->IsOverlay()); + ASSERT_EQ(UpToDate::True, apk_assets->IsUpToDate()); unlink(temp_file.path); - ASSERT_FALSE(apk_assets->IsUpToDate()); + ASSERT_EQ(UpToDate::False, apk_assets->IsUpToDate()); const auto sleep_duration = std::chrono::nanoseconds(std::max(kModDateResolutionNs, 1'000'000ull)); @@ -230,7 +231,27 @@ TEST_F(IdmapTest, OverlayAssetsIsUpToDate) { base::WriteStringToFile("hello", temp_file.path); std::this_thread::sleep_for(sleep_duration); - ASSERT_FALSE(apk_assets->IsUpToDate()); + ASSERT_EQ(UpToDate::False, apk_assets->IsUpToDate()); +} + +TEST(IdmapTestUpToDate, Combine) { + ASSERT_EQ(UpToDate::False, combine(UpToDate::False, [] { + ADD_FAILURE(); // Shouldn't get called at all. + return UpToDate::False; + })); + + ASSERT_EQ(UpToDate::False, combine(UpToDate::True, [] { return UpToDate::False; })); + + ASSERT_EQ(UpToDate::True, combine(UpToDate::True, [] { return UpToDate::True; })); + ASSERT_EQ(UpToDate::True, combine(UpToDate::True, [] { return UpToDate::Always; })); + ASSERT_EQ(UpToDate::True, combine(UpToDate::Always, [] { return UpToDate::True; })); + + ASSERT_EQ(UpToDate::Always, combine(UpToDate::Always, [] { return UpToDate::Always; })); +} + +TEST(IdmapTestUpToDate, FromBool) { + ASSERT_EQ(UpToDate::False, fromBool(false)); + ASSERT_EQ(UpToDate::True, fromBool(true)); } } // namespace diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp index a958a091a830..36feabde07eb 100644 --- a/libs/hwui/FrameInfo.cpp +++ b/libs/hwui/FrameInfo.cpp @@ -32,8 +32,9 @@ const std::array FrameInfoNames{"Flags", "PerformTraversalsStart", "DrawStart", "FrameDeadline", - "FrameInterval", "FrameStartTime", + "FrameInterval", + "WorkloadTarget", "SyncQueued", "SyncStart", "IssueDrawCommandsStart", @@ -48,7 +49,7 @@ const std::array FrameInfoNames{"Flags", }; -static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 23, +static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 24, "Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)"); void FrameInfo::importUiThreadInfo(int64_t* info) { diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h index f7ad13978a30..61c30b803b00 100644 --- a/libs/hwui/FrameInfo.h +++ b/libs/hwui/FrameInfo.h @@ -30,7 +30,8 @@ namespace android { namespace uirenderer { -static constexpr size_t UI_THREAD_FRAME_INFO_SIZE = 12; +// This value must be in sync with `FRAME_INFO_SIZE` in FrameInfo.Java +static constexpr size_t UI_THREAD_FRAME_INFO_SIZE = 13; enum class FrameInfoIndex { Flags = 0, @@ -47,6 +48,11 @@ enum class FrameInfoIndex { FrameInterval, // End of UI frame info + // The target workload duration based on the original frame deadline and + // and intended vsync. Counted in UI_THREAD_FRAME_INFO_SIZE so its value + // can be set in setVsync(). + WorkloadTarget, + SyncQueued, SyncStart, @@ -109,6 +115,7 @@ public: set(FrameInfoIndex::FrameStartTime) = vsyncTime; set(FrameInfoIndex::FrameDeadline) = frameDeadline; set(FrameInfoIndex::FrameInterval) = frameInterval; + set(FrameInfoIndex::WorkloadTarget) = frameDeadline - intendedVsync; return *this; } diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp index 638a060bdb1c..80eb6bc986d6 100644 --- a/libs/hwui/JankTracker.cpp +++ b/libs/hwui/JankTracker.cpp @@ -201,7 +201,7 @@ void JankTracker::finishFrame(FrameInfo& frame, std::unique_ptr<FrameMetricsRepo // If we are in triple buffering, we have enough buffers in queue to sustain a single frame // drop without jank, so adjust the frame interval to the deadline. if (isTripleBuffered) { - int64_t originalDeadlineDuration = deadline - frame[FrameInfoIndex::IntendedVsync]; + int64_t originalDeadlineDuration = frame[FrameInfoIndex::WorkloadTarget]; deadline = mNextFrameStartUnstuffed + originalDeadlineDuration; frame.set(FrameInfoIndex::FrameDeadline) = deadline; } diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index 7d01dfbb446f..21430f7e6777 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -57,6 +57,9 @@ constexpr bool query_global_priority() { constexpr bool early_preload_gl_context() { return false; } +constexpr bool calc_workload_orig_deadline() { + return false; +} } // namespace hwui_flags #endif @@ -299,5 +302,10 @@ bool Properties::earlyPreloadGlContext() { hwui_flags::early_preload_gl_context()); } +bool Properties::calcWorkloadOrigDeadline() { + static bool sCalcWorkloadOrigDeadline = base::GetBoolProperty( + "debug.hwui.calc_workload_orig_deadline", hwui_flags::calc_workload_orig_deadline()); + return sCalcWorkloadOrigDeadline; +} } // namespace uirenderer } // namespace android diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 280a75a28e65..a7a564428636 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -384,6 +384,7 @@ public: static bool initializeGlAlways(); static bool resampleGainmapRegions(); static bool earlyPreloadGlContext(); + static bool calcWorkloadOrigDeadline(); private: static StretchEffectBehavior stretchEffectBehavior; diff --git a/libs/hwui/aconfig/hwui_flags.aconfig b/libs/hwui/aconfig/hwui_flags.aconfig index 2851dd8b1003..62fd7d358123 100644 --- a/libs/hwui/aconfig/hwui_flags.aconfig +++ b/libs/hwui/aconfig/hwui_flags.aconfig @@ -176,4 +176,15 @@ flag { namespace: "core_graphics" description: "Initialize GL context and GraphicBufferAllocater init on renderThread preload. This improves app startup time for apps using GL." bug: "383612849" +} + +flag { + name: "calc_workload_orig_deadline" + namespace: "window_surfaces" + description: "Use original frame deadline to calculate the workload target deadline for jank tracking" + bug: "389939827" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } }
\ No newline at end of file diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index b36b8be10779..e3e393c4fdfb 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -789,7 +789,13 @@ void CanvasContext::draw(bool solelyTextureViewUpdates) { int64_t frameDeadline = mCurrentFrameInfo->get(FrameInfoIndex::FrameDeadline); int64_t dequeueBufferDuration = mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration); - mHintSessionWrapper->updateTargetWorkDuration(frameDeadline - intendedVsync); + if (Properties::calcWorkloadOrigDeadline()) { + // Uses the unmodified frame deadline in calculating workload target duration + mHintSessionWrapper->updateTargetWorkDuration( + mCurrentFrameInfo->get(FrameInfoIndex::WorkloadTarget)); + } else { + mHintSessionWrapper->updateTargetWorkDuration(frameDeadline - intendedVsync); + } if (didDraw) { int64_t frameStartTime = mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime); diff --git a/libs/hwui/tests/unit/JankTrackerTests.cpp b/libs/hwui/tests/unit/JankTrackerTests.cpp index b67e419e7d4a..c289d67fbef6 100644 --- a/libs/hwui/tests/unit/JankTrackerTests.cpp +++ b/libs/hwui/tests/unit/JankTrackerTests.cpp @@ -45,6 +45,7 @@ TEST(JankTracker, noJank) { info->set(FrameInfoIndex::FrameCompleted) = 115_ms; info->set(FrameInfoIndex::FrameInterval) = 16_ms; info->set(FrameInfoIndex::FrameDeadline) = 120_ms; + info->set(FrameInfoIndex::WorkloadTarget) = 20_ms; jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId); info = jankTracker.startFrame(); @@ -55,6 +56,7 @@ TEST(JankTracker, noJank) { info->set(FrameInfoIndex::FrameCompleted) = 131_ms; info->set(FrameInfoIndex::FrameInterval) = 16_ms; info->set(FrameInfoIndex::FrameDeadline) = 136_ms; + info->set(FrameInfoIndex::WorkloadTarget) = 20_ms; jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId); ASSERT_EQ(2, container.get()->totalFrameCount()); @@ -79,6 +81,7 @@ TEST(JankTracker, jank) { info->set(FrameInfoIndex::FrameCompleted) = 121_ms; info->set(FrameInfoIndex::FrameInterval) = 16_ms; info->set(FrameInfoIndex::FrameDeadline) = 120_ms; + info->set(FrameInfoIndex::WorkloadTarget) = 20_ms; jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId); ASSERT_EQ(1, container.get()->totalFrameCount()); @@ -102,6 +105,7 @@ TEST(JankTracker, legacyJankButNoRealJank) { info->set(FrameInfoIndex::FrameCompleted) = 118_ms; info->set(FrameInfoIndex::FrameInterval) = 16_ms; info->set(FrameInfoIndex::FrameDeadline) = 120_ms; + info->set(FrameInfoIndex::WorkloadTarget) = 20_ms; jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId); ASSERT_EQ(1, container.get()->totalFrameCount()); @@ -127,6 +131,7 @@ TEST(JankTracker, doubleStuffed) { info->set(FrameInfoIndex::FrameCompleted) = 121_ms; info->set(FrameInfoIndex::FrameInterval) = 16_ms; info->set(FrameInfoIndex::FrameDeadline) = 120_ms; + info->set(FrameInfoIndex::WorkloadTarget) = 20_ms; jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId); ASSERT_EQ(1, container.get()->jankFrameCount()); @@ -140,6 +145,7 @@ TEST(JankTracker, doubleStuffed) { info->set(FrameInfoIndex::FrameCompleted) = 137_ms; info->set(FrameInfoIndex::FrameInterval) = 16_ms; info->set(FrameInfoIndex::FrameDeadline) = 136_ms; + info->set(FrameInfoIndex::WorkloadTarget) = 20_ms; jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId); ASSERT_EQ(2, container.get()->totalFrameCount()); @@ -164,6 +170,7 @@ TEST(JankTracker, doubleStuffedThenPauseThenJank) { info->set(FrameInfoIndex::FrameCompleted) = 121_ms; info->set(FrameInfoIndex::FrameInterval) = 16_ms; info->set(FrameInfoIndex::FrameDeadline) = 120_ms; + info->set(FrameInfoIndex::WorkloadTarget) = 20_ms; jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId); ASSERT_EQ(1, container.get()->jankFrameCount()); @@ -177,6 +184,7 @@ TEST(JankTracker, doubleStuffedThenPauseThenJank) { info->set(FrameInfoIndex::FrameCompleted) = 137_ms; info->set(FrameInfoIndex::FrameInterval) = 16_ms; info->set(FrameInfoIndex::FrameDeadline) = 136_ms; + info->set(FrameInfoIndex::WorkloadTarget) = 20_ms; jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId); ASSERT_EQ(1, container.get()->jankFrameCount()); @@ -190,6 +198,7 @@ TEST(JankTracker, doubleStuffedThenPauseThenJank) { info->set(FrameInfoIndex::FrameCompleted) = 169_ms; info->set(FrameInfoIndex::FrameInterval) = 16_ms; info->set(FrameInfoIndex::FrameDeadline) = 168_ms; + info->set(FrameInfoIndex::WorkloadTarget) = 20_ms; jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId); ASSERT_EQ(3, container.get()->totalFrameCount()); @@ -214,6 +223,7 @@ TEST(JankTracker, doubleStuffedTwoIntervalBehind) { info->set(FrameInfoIndex::FrameCompleted) = 117_ms; info->set(FrameInfoIndex::FrameInterval) = 16_ms; info->set(FrameInfoIndex::FrameDeadline) = 116_ms; + info->set(FrameInfoIndex::WorkloadTarget) = 16_ms; jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId); ASSERT_EQ(1, container.get()->jankFrameCount()); @@ -228,6 +238,7 @@ TEST(JankTracker, doubleStuffedTwoIntervalBehind) { info->set(FrameInfoIndex::FrameCompleted) = 133_ms; info->set(FrameInfoIndex::FrameInterval) = 16_ms; info->set(FrameInfoIndex::FrameDeadline) = 132_ms; + info->set(FrameInfoIndex::WorkloadTarget) = 16_ms; jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId); ASSERT_EQ(1, container.get()->jankFrameCount()); @@ -242,6 +253,7 @@ TEST(JankTracker, doubleStuffedTwoIntervalBehind) { info->set(FrameInfoIndex::FrameCompleted) = 165_ms; info->set(FrameInfoIndex::FrameInterval) = 16_ms; info->set(FrameInfoIndex::FrameDeadline) = 148_ms; + info->set(FrameInfoIndex::WorkloadTarget) = 16_ms; jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId); ASSERT_EQ(2, container.get()->jankFrameCount()); @@ -256,6 +268,7 @@ TEST(JankTracker, doubleStuffedTwoIntervalBehind) { info->set(FrameInfoIndex::FrameCompleted) = 181_ms; info->set(FrameInfoIndex::FrameInterval) = 16_ms; info->set(FrameInfoIndex::FrameDeadline) = 164_ms; + info->set(FrameInfoIndex::WorkloadTarget) = 16_ms; jankTracker.finishFrame(*info, reporter, frameNumber, surfaceId); ASSERT_EQ(2, container.get()->jankFrameCount()); |