diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt index 4d68f5ac5d..a010057324 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt @@ -20,7 +20,6 @@ import android.animation.AnimatorListenerAdapter import android.content.Intent import android.graphics.PointF import android.os.SystemClock -import android.os.Trace import android.util.Log import android.view.Display.DEFAULT_DISPLAY import android.view.View @@ -30,7 +29,6 @@ import androidx.annotation.UiThread import androidx.annotation.VisibleForTesting import com.android.app.displaylib.DisplayRepository import com.android.app.displaylib.PerDisplayRepository -import com.android.app.tracing.traceSection import com.android.internal.jank.Cuj import com.android.launcher3.DeviceProfile import com.android.launcher3.PagedView @@ -200,7 +198,6 @@ constructor( ensureActive() onCommandFinished(command) } - } } } @@ -541,7 +538,6 @@ constructor( command.addListener(recentAnimListener) taskAnimationManager.notifyRecentsAnimationState(recentAnimListener) } else { - // Lawnchair-TODO: What name to put in intent here? val intent = Intent(interactionHandler.getLaunchIntent()) .putExtra(ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID, gestureState.gestureId) @@ -551,7 +547,6 @@ constructor( interactionHandler.onGestureStarted(false /*isLikelyToStartNewTask*/) command.addListener(recentAnimListener) } - //Trace.beginAsyncSection(TRANSITION_NAME, 0) OverviewCommandHelperProtoLogProxy.logSwitchingViaRecentsAnim(command) return false } @@ -569,7 +564,6 @@ constructor( ) { OverviewCommandHelperProtoLogProxy.logSwitchingViaRecentsAnimComplete(command) command.removeListener(handler) - Trace.endAsyncSection(TRANSITION_NAME, 0) onRecentsViewFocusUpdated(command) onCommandResult() } diff --git a/quickstep/src/com/android/quickstep/views/TaskContainer.kt b/quickstep/src/com/android/quickstep/views/TaskContainer.kt index 83458324f2..80f3913b91 100644 --- a/quickstep/src/com/android/quickstep/views/TaskContainer.kt +++ b/quickstep/src/com/android/quickstep/views/TaskContainer.kt @@ -20,7 +20,6 @@ import android.graphics.Bitmap import android.graphics.Matrix import android.view.View import android.view.View.OnClickListener -import com.android.app.tracing.traceSection import com.android.launcher3.Flags.enableRefactorTaskContentView import com.android.launcher3.Flags.enableRefactorTaskThumbnail import com.android.launcher3.model.data.TaskViewItemInfo diff --git a/wmshell/Android.bp b/wmshell/Android.bp index 25d3067a34..39e8e69df2 100644 --- a/wmshell/Android.bp +++ b/wmshell/Android.bp @@ -27,7 +27,9 @@ java_library { name: "wm_shell_protolog-groups", srcs: [ "src/com/android/wm/shell/protolog/ShellProtoLogGroup.java", - ":protolog-common-src", + ], + static_libs: [ + "protolog-common-lib", ], } @@ -39,28 +41,6 @@ filegroup { path: "src", } -// Sources that have no dependencies that can be used directly downstream of this library -// TODO(b/322791067): move these sources to WindowManager-Shell-shared -filegroup { - name: "wm_shell_util-sources", - srcs: [ - "src/com/android/wm/shell/animation/Interpolators.java", - "src/com/android/wm/shell/common/bubbles/*.kt", - "src/com/android/wm/shell/common/bubbles/*.java", - "src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt", - "src/com/android/wm/shell/common/split/SplitScreenConstants.java", - "src/com/android/wm/shell/common/TransactionPool.java", - "src/com/android/wm/shell/common/TriangleShape.java", - "src/com/android/wm/shell/common/desktopmode/*.kt", - "src/com/android/wm/shell/draganddrop/DragAndDropConstants.java", - "src/com/android/wm/shell/pip/PipContentOverlay.java", - "src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java", - "src/com/android/wm/shell/sysui/ShellSharedConstants.java", - "src/com/android/wm/shell/util/**/*.java", - ], - path: "src", -} - // Aidls which can be used directly downstream of this library filegroup { name: "wm_shell-aidls", @@ -79,74 +59,40 @@ filegroup { path: "src", } -genrule { +java_genrule { name: "wm_shell_protolog_src", srcs: [ ":protolog-impl", - ":wm_shell_protolog-groups", ":wm_shell-sources", + ":wm_shell_protolog-groups", ], tools: ["protologtool"], cmd: "$(location protologtool) transform-protolog-calls " + - "--protolog-class com.android.internal.protolog.common.ProtoLog " + + "--protolog-class com.android.internal.protolog.ProtoLog " + "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " + "--loggroups-jar $(location :wm_shell_protolog-groups) " + "--viewer-config-file-path /system_ext/etc/wmshell.protolog.pb " + - "--legacy-viewer-config-file-path /system_ext/etc/wmshell.protolog.json.gz " + - "--legacy-output-file-path /data/misc/wmtrace/shell_log.winscope " + "--output-srcjar $(out) " + "$(locations :wm_shell-sources)", out: ["wm_shell_protolog.srcjar"], } -genrule { - name: "generate-wm_shell_protolog.json", - srcs: [ - ":wm_shell_protolog-groups", - ":wm_shell-sources", - ], - tools: ["protologtool"], - cmd: "$(location protologtool) generate-viewer-config " + - "--protolog-class com.android.internal.protolog.common.ProtoLog " + - "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " + - "--loggroups-jar $(location :wm_shell_protolog-groups) " + - "--viewer-config-type json " + - "--viewer-config $(out) " + - "$(locations :wm_shell-sources)", - out: ["wm_shell_protolog.json"], -} - -genrule { +java_genrule { name: "gen-wmshell.protolog.pb", srcs: [ - ":wm_shell_protolog-groups", ":wm_shell-sources", + ":wm_shell_protolog-groups", ], tools: ["protologtool"], cmd: "$(location protologtool) generate-viewer-config " + - "--protolog-class com.android.internal.protolog.common.ProtoLog " + + "--protolog-class com.android.internal.protolog.ProtoLog " + "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " + "--loggroups-jar $(location :wm_shell_protolog-groups) " + - "--viewer-config-type proto " + "--viewer-config $(out) " + "$(locations :wm_shell-sources)", out: ["wmshell.protolog.pb"], } -genrule { - name: "protolog.json.gz", - srcs: [":generate-wm_shell_protolog.json"], - out: ["wmshell.protolog.json.gz"], - cmd: "gzip -c < $(in) > $(out)", -} - -prebuilt_etc { - name: "wmshell.protolog.json.gz", - system_ext_specific: true, - src: ":protolog.json.gz", - filename_from_src: true, -} - prebuilt_etc { name: "wmshell.protolog.pb", system_ext_specific: true, @@ -166,69 +112,76 @@ java_library { }, } -filegroup { - name: "wm_shell-shared-aidls", - - srcs: [ - "shared/**/*.aidl", - ], - - path: "shared/src", -} - java_library { - name: "WindowManager-Shell-shared", + name: "WindowManager-Shell-lite-proto", srcs: [ - "shared/**/*.java", - "shared/**/*.kt", - ":wm_shell-shared-aidls", - ], - static_libs: [ - "androidx.dynamicanimation_dynamicanimation", - "jsr330", + "src/com/android/wm/shell/desktopmode/education/data/proto/**/*.proto", + "src/com/android/wm/shell/desktopmode/persistence/*.proto", ], + proto: { + type: "lite", + }, } android_library { name: "WindowManager-Shell", srcs: [ - ":wm_shell_protolog_src", // TODO(b/168581922) protologtool do not support kotlin(*.kt) - ":wm_shell-sources-kt", ":wm_shell-aidls", + ":wm_shell-shared-aidls", + ":wm_shell-sources-kt", + ":wm_shell_protolog_src", + "src/com/android/wm/shell/EventLogTags.logtags", ], resource_dirs: [ "res", ], static_libs: [ - "androidx.appcompat_appcompat", - "androidx.core_core-animation", - "androidx.core_core-ktx", - "androidx.arch.core_core-runtime", - "androidx.compose.material3_material3", - "androidx-constraintlayout_constraintlayout", - "androidx.dynamicanimation_dynamicanimation", - "androidx.recyclerview_recyclerview", - "kotlinx-coroutines-android", - "kotlinx-coroutines-core", + "//frameworks/base/packages/SystemUI/aconfig:com_android_systemui_flags_lib", "//frameworks/libs/systemui:com_android_systemui_shared_flags_lib", "//frameworks/libs/systemui:iconloader_base", - "com_android_wm_shell_flags_lib", - "com.android.window.flags.window-aconfig-java", + "//frameworks/libs/systemui:msdl", + "//frameworks/libs/systemui:tracinglib-platform", + "//frameworks/libs/systemui:view_capture", + "PlatformAnimationLib", + "WindowManager-Shell-lite-proto", "WindowManager-Shell-proto", "WindowManager-Shell-shared", - "perfetto_trace_java_protos", + "androidx-constraintlayout_constraintlayout", + "androidx.appcompat_appcompat", + "androidx.arch.core_core-runtime", + "androidx.compose.material3_material3", + "androidx.core_core-ktx", + "androidx.datastore_datastore", + "androidx.dynamicanimation_dynamicanimation", + "androidx.recyclerview_recyclerview", + "com_android_launcher3_flags_lib", + "com_android_wm_shell_flags_lib", "dagger2", "jsr330", + "kotlinx-coroutines-android", + "kotlinx-coroutines-core", + "mechanics", + "perfetto_trace_java_protos", ], libs: [ // Soong fails to automatically add this dependency because all the // *.kt sources are inside a filegroup. "kotlin-annotations", ], + flags_packages: [ + "com_android_wm_shell_flags", + ], kotlincflags: ["-Xjvm-default=all"], manifest: "AndroidManifest.xml", plugins: ["dagger2-compiler"], use_resource_processor: true, } + +java_defaults { + name: "wmshell_defaults", + required: [ + "wmshell.protolog.pb", + ], +} diff --git a/wmshell/OWNERS b/wmshell/OWNERS index ebebd8a52c..68970e68de 100644 --- a/wmshell/OWNERS +++ b/wmshell/OWNERS @@ -1,5 +1,7 @@ -xutan@google.com +jorgegil@google.com +pbdr@google.com +pragyabajoria@google.com # Give submodule owners in shell resource approval -per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com, nmusgrave@google.com, pbdr@google.com, tkachenkoi@google.com, mpodolian@google.com, liranb@google.com +per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, lbill@google.com, madym@google.com, vaniadesmonda@google.com, pbdr@google.com, mpodolian@google.com, liranb@google.com, pragyabajoria@google.com, uysalorhan@google.com, gsennton@google.com, mattsziklay@google.com, mdehaini@google.com, peanutbutter@google.com, jeremysim@google.com per-file res*/*/tv_*.xml = bronger@google.com diff --git a/wmshell/aconfig/Android.bp b/wmshell/aconfig/Android.bp index 7f8f57b172..f8da7fa86c 100644 --- a/wmshell/aconfig/Android.bp +++ b/wmshell/aconfig/Android.bp @@ -4,6 +4,7 @@ aconfig_declarations { container: "system", srcs: [ "multitasking.aconfig", + "automotive.aconfig", ], } diff --git a/wmshell/aconfig/OWNERS b/wmshell/aconfig/OWNERS index 9eba0f2dea..eacadeacab 100644 --- a/wmshell/aconfig/OWNERS +++ b/wmshell/aconfig/OWNERS @@ -1,3 +1,4 @@ # Owners for flag changes madym@google.com -hwwang@google.com \ No newline at end of file +hwwang@google.com +sqsun@google.com \ No newline at end of file diff --git a/wmshell/aconfig/multitasking.aconfig b/wmshell/aconfig/multitasking.aconfig index 112eb617e7..69e2aca01a 100644 --- a/wmshell/aconfig/multitasking.aconfig +++ b/wmshell/aconfig/multitasking.aconfig @@ -1,21 +1,10 @@ # proto-file: build/make/tools/aconfig/aconfig_protos/protos/aconfig.proto +# proto-message: flag_declarations +# Project link: http://gantry/projects/android_platform_multitasking package: "com.android.wm.shell" container: "system" -flag { - name: "enable_app_pairs" - namespace: "multitasking" - description: "Enables the ability to create and save app pairs to the Home screen" - bug: "274835596" -} - -flag { - name: "enable_split_contextual" - namespace: "multitasking" - description: "Enables invoking split contextually" - bug: "276361926" -} flag { name: "enable_taskbar_navbar_unification" @@ -25,18 +14,10 @@ flag { } flag { - name: "enable_pip2_implementation" + name: "enable_pip2" namespace: "multitasking" description: "Enables the new implementation of PiP (PiP2)" - bug: "290220798" - is_fixed_read_only: true -} - -flag { - name: "enable_left_right_split_in_portrait" - namespace: "multitasking" - description: "Enables left/right split in portrait" - bug: "291018646" + bug: "311462191" } flag { @@ -102,6 +83,13 @@ flag { bug: "342245211" } +flag { + name: "enable_create_any_bubble" + namespace: "multitasking" + description: "Enable UI affordances to create bubbles via launcher app icons" + bug: "385220199" +} + flag { name: "only_reuse_bubbled_task_when_launched_from_bubble" namespace: "multitasking" @@ -113,10 +101,156 @@ flag { } flag { - name: "animate_bubble_size_change" + name: "enable_bubble_app_compat_fixes" namespace: "multitasking" - description: "Turns on the animation for bubble bar icons size change" - bug: "335575529" + description: "Enable fixes for app compat (e.g. insets and layout issues) for bubbles" + bug: "384610402" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "enable_taskbar_on_phones" + namespace: "multitasking" + description: "Enables taskbar on phones" + bug: "348007377" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "enable_shell_top_task_tracking" + namespace: "multitasking" + description: "Enables tracking top tasks from the shell" + bug: "346588978" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "enable_recents_bookend_transition" + namespace: "multitasking" + description: "Use a finish-transition to clean up recents instead of the finish-WCT" + bug: "346588978" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "enable_bubble_to_fullscreen" + namespace: "multitasking" + description: "Enable an option to move bubbles to fullscreen" + bug: "363326492" +} + +flag { + name: "enable_flexible_two_app_split" + namespace: "multitasking" + description: "Enables only 2 app 90:10 split" + bug: "349828130" +} + +flag { + name: "enable_flexible_split" + namespace: "multitasking" + description: "Enables flexibile split feature for split screen" + bug: "349828130" +} + +flag { + name: "task_view_repository" + namespace: "multitasking" + description: "Factor task-view state tracking out of taskviewtransitions" + bug: "384976265" +} + +flag { + name: "fix_missing_user_change_callbacks" + namespace: "multitasking" + description: "Fix a race condition that could make Shell miss a user change callback." + bug: "404251029" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "enable_bubble_bar_on_phones" + namespace: "multitasking" + description: "Try out bubble bar on phones" + bug: "394869612" +} + +flag { + name: "enable_bubble_task_view_listener" + namespace: "multitasking" + description: "Use the same taskview listener for bubble bar and floating" + bug: "272102927" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "enable_gsf" + namespace: "multitasking" + description: "Applies GSF font styles to multitasking." + bug: "400534660" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "enable_magnetic_split_divider" + namespace: "multitasking" + description: "Makes the split divider snap 'magnetically' to available snap points during drag" + bug: "383631946" +} + +flag { + name: "enable_dynamic_insets_for_app_launch" + namespace: "multitasking" + description: "Enables dynamic insets for app launch so the window is properly cropped" + bug: "336511494" +} + +flag { + name: "task_view_transitions_refactor" + namespace: "windowing_frontend" + description: "Refactor TaskViewTransitions.startAnimation" + bug: "402454136" +} + +flag { + name: "enable_pip_box_shadows" + namespace: "multitasking" + description: "Enables box shadows for PiP" + bug: "367464660" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "enable_bubble_swipe_up_cleanup" + namespace: "multitasking" + description: "Enable clean up of bubbles swipe gesture handling" + bug: "391909607" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "enable_enter_split_remove_bubble" + namespace: "multitasking" + description: "Enable removing a task from bubbles when it is entering split screen" + bug: "396315875" metadata { purpose: PURPOSE_BUGFIX } diff --git a/wmshell/multivalentTests/Android.bp b/wmshell/multivalentTests/Android.bp index 1ad19c9f30..5d14dc054b 100644 --- a/wmshell/multivalentTests/Android.bp +++ b/wmshell/multivalentTests/Android.bp @@ -35,7 +35,6 @@ android_app { android_robolectric_test { name: "WMShellRobolectricTests", instrumentation_for: "WindowManagerShellRobolectric", - upstream: true, java_resource_dirs: [ "robolectric/config", ], @@ -50,9 +49,14 @@ android_robolectric_test { "androidx.test.runner", "androidx.test.rules", "androidx.test.ext.junit", - "mockito-robolectric-prebuilt", + "mockito-robolectric-prebuilt", // mockito deps order matters! "mockito-kotlin2", + "WMShellTests-utils", // order matters because it depends on mockito-kotlin2 + "platform-parametric-runner-lib", "truth", + "flag-junit-base", + "flag-junit", + "testables", ], auto_gen_config: true, } @@ -63,22 +67,25 @@ android_test { "src/**/*.kt", ], static_libs: [ + "WMShellTests-utils", "WindowManager-Shell", - "junit", "androidx.core_core-animation-testing", - "androidx.test.runner", - "androidx.test.rules", "androidx.test.ext.junit", + "androidx.test.rules", + "androidx.test.runner", "frameworks-base-testutils", + "junit", "mockito-kotlin2", "mockito-target-extended-minus-junit4", - "truth", + "platform-parametric-runner-lib", "platform-test-annotations", "platform-test-rules", + "testables", + "truth", ], libs: [ - "android.test.base", - "android.test.runner", + "android.test.base.stubs.system", + "android.test.runner.stubs.system", ], jni_libs: [ "libdexmakerjvmtiagent", diff --git a/wmshell/multivalentTests/AndroidManifest.xml b/wmshell/multivalentTests/AndroidManifest.xml index f8f8338e5f..4341eaaf9f 100644 --- a/wmshell/multivalentTests/AndroidManifest.xml +++ b/wmshell/multivalentTests/AndroidManifest.xml @@ -1,8 +1,23 @@ + + + + + + + + + + + + + diff --git a/wmshell/multivalentTests/robolectric/config/robolectric.properties b/wmshell/multivalentTests/robolectric/config/robolectric.properties index 7a0527ccaa..d50d976c9e 100644 --- a/wmshell/multivalentTests/robolectric/config/robolectric.properties +++ b/wmshell/multivalentTests/robolectric/config/robolectric.properties @@ -1,2 +1,3 @@ sdk=NEWEST_SDK +graphicsMode=NATIVE diff --git a/wmshell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt b/wmshell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt index 9e1440d571..3b67d13106 100644 --- a/wmshell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt +++ b/wmshell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt @@ -27,10 +27,11 @@ import android.view.WindowManager import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import com.android.internal.protolog.common.ProtoLog +import com.android.internal.protolog.ProtoLog import com.android.wm.shell.R import com.android.wm.shell.bubbles.BubblePositioner.MAX_HEIGHT -import com.android.wm.shell.common.bubbles.BubbleBarLocation +import com.android.wm.shell.shared.bubbles.BubbleBarLocation +import com.android.wm.shell.shared.bubbles.DeviceConfig import com.google.common.truth.Truth.assertThat import com.google.common.util.concurrent.MoreExecutors.directExecutor import org.junit.Before @@ -154,19 +155,19 @@ class BubblePositionerTest { /** Test that the default resting position on tablet is middle right. */ @Test - fun testGetDefaultPosition_appBubble_onTablet() { + fun testGetDefaultPosition_noteBubble_onTablet() { positioner.update(defaultDeviceConfig.copy(isLargeScreen = true)) val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - val startPosition = positioner.getDefaultStartPosition(true /* isAppBubble */) + val startPosition = positioner.getDefaultStartPosition(true /* isNoteBubble */) assertThat(startPosition.x).isEqualTo(allowableStackRegion.right) assertThat(startPosition.y).isEqualTo(defaultYPosition) } @Test - fun testGetRestingPosition_appBubble_onTablet_RTL() { + fun testGetRestingPosition_noteBubble_onTablet_RTL() { positioner.update(defaultDeviceConfig.copy(isLargeScreen = true, isRtl = true)) val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - val startPosition = positioner.getDefaultStartPosition(true /* isAppBubble */) + val startPosition = positioner.getDefaultStartPosition(true /* isNoteBubble */) assertThat(startPosition.x).isEqualTo(allowableStackRegion.left) assertThat(startPosition.y).isEqualTo(defaultYPosition) } @@ -221,7 +222,7 @@ class BubblePositionerTest { positioner.setShowingInBubbleBar(true) positioner.update(deviceConfig) - positioner.bubbleBarTopOnScreen = 2500 + positioner.updateBubbleBarTopOnScreen(100) val spaceBetweenTopInsetAndBubbleBarInLandscape = 1680 val expandedViewVerticalSpacing = @@ -247,7 +248,7 @@ class BubblePositionerTest { ) positioner.setShowingInBubbleBar(true) positioner.update(deviceConfig) - positioner.bubbleBarTopOnScreen = 2500 + positioner.updateBubbleBarTopOnScreen(100) val spaceBetweenTopInsetAndBubbleBarInLandscape = 180 val expandedViewSpacing = @@ -268,7 +269,8 @@ class BubblePositionerTest { ) positioner.update(deviceConfig) val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) + val bubble = + Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor(), directExecutor()) assertThat(positioner.getExpandedViewHeight(bubble)).isEqualTo(MAX_HEIGHT) } @@ -294,6 +296,7 @@ class BubblePositionerTest { 0 /* taskId */, null /* locus */, true /* isDismissable */, + directExecutor(), directExecutor() ) {} @@ -322,6 +325,7 @@ class BubblePositionerTest { 0 /* taskId */, null /* locus */, true /* isDismissable */, + directExecutor(), directExecutor() ) {} @@ -416,7 +420,8 @@ class BubblePositionerTest { positioner.update(deviceConfig) val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) + val bubble = + Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor(), directExecutor()) // This bubble will have max height so it'll always be top aligned assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) @@ -433,7 +438,8 @@ class BubblePositionerTest { positioner.update(deviceConfig) val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) + val bubble = + Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor(), directExecutor()) // Always top aligned in phone portrait assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) @@ -452,7 +458,8 @@ class BubblePositionerTest { positioner.update(deviceConfig) val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) + val bubble = + Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor(), directExecutor()) // This bubble will have max height which is always top aligned on small tablets assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) @@ -470,7 +477,8 @@ class BubblePositionerTest { positioner.update(deviceConfig) val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) + val bubble = + Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor(), directExecutor()) // This bubble will have max height which is always top aligned on small tablets assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) @@ -489,7 +497,8 @@ class BubblePositionerTest { positioner.update(deviceConfig) val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) + val bubble = + Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor(), directExecutor()) // This bubble will have max height which is always top aligned on landscape, large tablet assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) @@ -507,7 +516,8 @@ class BubblePositionerTest { positioner.update(deviceConfig) val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) + val bubble = + Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor(), directExecutor()) val manageButtonHeight = context.resources.getDimensionPixelSize(R.dimen.bubble_manage_button_height) @@ -575,26 +585,115 @@ class BubblePositionerTest { @Test fun testGetBubbleBarExpandedViewBounds_onLeft() { - testGetBubbleBarExpandedViewBounds(onLeft = true, isOverflow = false) + verifyGetBubbleBarExpandedViewBounds(onLeft = true, isOverflow = false) } @Test fun testGetBubbleBarExpandedViewBounds_onRight() { - testGetBubbleBarExpandedViewBounds(onLeft = false, isOverflow = false) + verifyGetBubbleBarExpandedViewBounds(onLeft = false, isOverflow = false) } @Test fun testGetBubbleBarExpandedViewBounds_isOverflow_onLeft() { - testGetBubbleBarExpandedViewBounds(onLeft = true, isOverflow = true) + verifyGetBubbleBarExpandedViewBounds(onLeft = true, isOverflow = true) } @Test fun testGetBubbleBarExpandedViewBounds_isOverflow_onRight() { - testGetBubbleBarExpandedViewBounds(onLeft = false, isOverflow = true) + verifyGetBubbleBarExpandedViewBounds(onLeft = false, isOverflow = true) } - private fun testGetBubbleBarExpandedViewBounds(onLeft: Boolean, isOverflow: Boolean) { - positioner.setShowingInBubbleBar(true) + @Test + fun testGetTaskViewRestBounds_phone() { + val deviceConfig = + defaultDeviceConfig.copy( + insets = Insets.of(10, 20, 5, 15), + windowBounds = Rect(0, 0, 1800, 2600) + ) + positioner.update(deviceConfig) + + val padding = context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding) + val top = positioner.expandedViewYTopAligned + val left = positioner.insets.left + padding + val right = positioner.screenRect.right - positioner.insets.right - padding + val bottom = top + positioner.getMaxExpandedViewHeight(false) + + val rect = Rect() + positioner.getTaskViewRestBounds(rect) + assertThat(rect).isEqualTo(Rect(left, top, right, bottom)) + } + + @Test + fun getExpandedViewContainerPadding_largeScreen_fitsMaxViewWidth() { + val expandedViewWidth = context.resources.getDimensionPixelSize( + R.dimen.bubble_expanded_view_largescreen_width + ) + // set the screen size so that it is wide enough to fit the maximum width size + val screenWidth = expandedViewWidth * 2 + positioner.update( + defaultDeviceConfig.copy( + windowBounds = Rect(0, 0, screenWidth, 2000), + isLargeScreen = true, + isLandscape = false + ) + ) + val paddings = + positioner.getExpandedViewContainerPadding(/* onLeft= */ true, /* isOverflow= */ false) + + val padding = context.resources.getDimensionPixelSize( + R.dimen.bubble_expanded_view_largescreen_landscape_padding + ) + val right = screenWidth - expandedViewWidth - padding + assertThat(paddings).isEqualTo(intArrayOf(padding - positioner.pointerSize, 0, right, 0)) + } + + @Test + fun getExpandedViewContainerPadding_largeScreen_doesNotFitMaxViewWidth() { + positioner.update( + defaultDeviceConfig.copy( + windowBounds = Rect(0, 0, 600, 2000), + isLargeScreen = true, + isLandscape = false + ) + ) + val paddings = + positioner.getExpandedViewContainerPadding(/* onLeft= */ true, /* isOverflow= */ false) + + val padding = context.resources.getDimensionPixelSize( + R.dimen.bubble_expanded_view_largescreen_landscape_padding + ) + // the screen is not wide enough to fit the maximum width size, so the view fills the screen + // minus left and right padding + assertThat(paddings).isEqualTo(intArrayOf(padding - positioner.pointerSize, 0, padding, 0)) + } + + @Test + fun getExpandedViewContainerPadding_smallTablet() { + val screenWidth = 500 + positioner.update( + defaultDeviceConfig.copy( + windowBounds = Rect(0, 0, screenWidth, 2000), + isLargeScreen = true, + isSmallTablet = true, + isLandscape = false + ) + ) + val paddings = + positioner.getExpandedViewContainerPadding(/* onLeft= */ true, /* isOverflow= */ false) + + // for small tablets, the view width is set to be 0.72 * screen width + val viewWidth = (screenWidth * 0.72).toInt() + val padding = (screenWidth - viewWidth) / 2 + assertThat(paddings).isEqualTo(intArrayOf(padding - positioner.pointerSize, 0, padding, 0)) + } + + private fun verifyGetBubbleBarExpandedViewBounds(onLeft: Boolean, isOverflow: Boolean) { + positioner.isShowingInBubbleBar = true + positioner.bubbleBarLocation = if (onLeft) { + BubbleBarLocation.LEFT + } else { + BubbleBarLocation.RIGHT + } val windowBounds = Rect(0, 0, 2000, 2600) val insets = Insets.of(10, 20, 5, 15) val deviceConfig = @@ -607,7 +706,7 @@ class BubblePositionerTest { positioner.update(deviceConfig) val bubbleBarHeight = 100 - positioner.bubbleBarTopOnScreen = windowBounds.bottom - insets.bottom - bubbleBarHeight + positioner.updateBubbleBarTopOnScreen(bubbleBarHeight) val expandedViewPadding = context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding) @@ -632,8 +731,14 @@ class BubblePositionerTest { val bounds = Rect() positioner.getBubbleBarExpandedViewBounds(onLeft, isOverflow, bounds) - assertThat(bounds).isEqualTo(expectedBounds) + + if (!isOverflow) { + val bounds2 = Rect() + // In bubble bar mode this should return the same bounds + positioner.getTaskViewRestBounds(bounds2) + assertThat(bounds2).isEqualTo(expectedBounds) + } } private val defaultYPosition: Float diff --git a/wmshell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt b/wmshell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt index 327e205955..da1fae9a04 100644 --- a/wmshell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt +++ b/wmshell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt @@ -23,36 +23,39 @@ import android.content.res.Resources import android.graphics.Color import android.graphics.drawable.Icon import android.os.UserHandle +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.SetFlagsRule -import android.view.IWindowManager import android.view.WindowManager -import android.view.WindowManagerGlobal import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import androidx.test.platform.app.InstrumentationRegistry import com.android.internal.logging.testing.UiEventLoggerFake -import com.android.internal.protolog.common.ProtoLog +import com.android.internal.protolog.ProtoLog import com.android.launcher3.icons.BubbleIconFactory import com.android.wm.shell.Flags import com.android.wm.shell.R +import com.android.wm.shell.bubbles.BubbleStackView.SurfaceSynchronizer +import com.android.wm.shell.bubbles.Bubbles.BubbleExpandListener import com.android.wm.shell.bubbles.Bubbles.SysuiProxy import com.android.wm.shell.bubbles.animation.AnimatableScaleMatrix import com.android.wm.shell.common.FloatingContentCoordinator -import com.android.wm.shell.common.ShellExecutor +import com.android.wm.shell.common.TestShellExecutor import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils -import com.android.wm.shell.taskview.TaskView -import com.android.wm.shell.taskview.TaskViewTaskController import com.google.common.truth.Truth.assertThat import com.google.common.util.concurrent.MoreExecutors.directExecutor import org.junit.After +import org.junit.Assert.fail import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.any import org.mockito.kotlin.mock -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags +import org.mockito.kotlin.never +import org.mockito.kotlin.spy +import org.mockito.kotlin.verify import java.util.concurrent.Semaphore import java.util.concurrent.TimeUnit import java.util.function.Consumer @@ -66,14 +69,16 @@ class BubbleStackViewTest { private val context = ApplicationProvider.getApplicationContext() private lateinit var positioner: BubblePositioner + private lateinit var bubbleLogger: BubbleLogger private lateinit var iconFactory: BubbleIconFactory private lateinit var expandedViewManager: FakeBubbleExpandedViewManager private lateinit var bubbleStackView: BubbleStackView - private lateinit var shellExecutor: ShellExecutor - private lateinit var windowManager: IWindowManager + private lateinit var shellExecutor: TestShellExecutor + private lateinit var windowManager: WindowManager private lateinit var bubbleTaskViewFactory: BubbleTaskViewFactory private lateinit var bubbleData: BubbleData private lateinit var bubbleStackViewManager: FakeBubbleStackViewManager + private lateinit var surfaceSynchronizer: FakeSurfaceSynchronizer private var sysuiProxy = mock() @Before @@ -81,9 +86,8 @@ class BubbleStackViewTest { PhysicsAnimatorTestUtils.prepareForTest() // Disable protolog tool when running the tests from studio ProtoLog.REQUIRE_PROTOLOGTOOL = false - windowManager = WindowManagerGlobal.getWindowManagerService()!! shellExecutor = TestShellExecutor() - val windowManager = context.getSystemService(WindowManager::class.java) + windowManager = context.getSystemService(WindowManager::class.java) iconFactory = BubbleIconFactory( context, @@ -95,24 +99,27 @@ class BubbleStackViewTest { ) ) positioner = BubblePositioner(context, windowManager) + bubbleLogger = BubbleLogger(UiEventLoggerFake()) bubbleData = BubbleData( context, - BubbleLogger(UiEventLoggerFake()), + bubbleLogger, positioner, BubbleEducationController(context), + shellExecutor, shellExecutor ) bubbleStackViewManager = FakeBubbleStackViewManager() expandedViewManager = FakeBubbleExpandedViewManager() - bubbleTaskViewFactory = FakeBubbleTaskViewFactory() + bubbleTaskViewFactory = FakeBubbleTaskViewFactory(context, shellExecutor) + surfaceSynchronizer = FakeSurfaceSynchronizer() bubbleStackView = BubbleStackView( context, bubbleStackViewManager, positioner, bubbleData, - null, + surfaceSynchronizer, FloatingContentCoordinator(), { sysuiProxy }, shellExecutor @@ -165,6 +172,7 @@ class BubbleStackViewTest { // This will eventually propagate an update back to the stack view, but setting the // entire pipeline is outside the scope of a unit test. assertThat(bubbleData.isExpanded).isTrue() + shellExecutor.flushAll() } assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() @@ -173,8 +181,207 @@ class BubbleStackViewTest { assertThat(lastUpdate!!.expanded).isTrue() } + @Test + fun expandStack_imeHidden() { + val bubble = createAndInflateBubble() + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + bubbleStackView.addBubble(bubble) + } + + InstrumentationRegistry.getInstrumentation().waitForIdleSync() + assertThat(bubbleStackView.bubbleCount).isEqualTo(1) + + positioner.setImeVisible(false, 0) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + // simulate a request from the bubble data listener to expand the stack + bubbleStackView.isExpanded = true + verify(sysuiProxy).onStackExpandChanged(true) + shellExecutor.flushAll() + } + + assertThat(bubbleStackViewManager.onImeHidden).isNull() + } + + @Test + fun collapseStack_imeHidden() { + val bubble = createAndInflateBubble() + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + bubbleStackView.addBubble(bubble) + } + + InstrumentationRegistry.getInstrumentation().waitForIdleSync() + assertThat(bubbleStackView.bubbleCount).isEqualTo(1) + + positioner.setImeVisible(false, 0) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + // simulate a request from the bubble data listener to expand the stack + bubbleStackView.isExpanded = true + verify(sysuiProxy).onStackExpandChanged(true) + shellExecutor.flushAll() + } + + assertThat(bubbleStackViewManager.onImeHidden).isNull() + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + // simulate a request from the bubble data listener to collapse the stack + bubbleStackView.isExpanded = false + verify(sysuiProxy).onStackExpandChanged(false) + shellExecutor.flushAll() + } + + assertThat(bubbleStackViewManager.onImeHidden).isNull() + } + + @Test + fun expandStack_waitsForIme() { + val bubble = createAndInflateBubble() + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + bubbleStackView.addBubble(bubble) + } + + InstrumentationRegistry.getInstrumentation().waitForIdleSync() + assertThat(bubbleStackView.bubbleCount).isEqualTo(1) + + positioner.setImeVisible(true, 100) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + // simulate a request from the bubble data listener to expand the stack + bubbleStackView.isExpanded = true + } + + val onImeHidden = bubbleStackViewManager.onImeHidden + assertThat(onImeHidden).isNotNull() + verify(sysuiProxy, never()).onStackExpandChanged(any()) + positioner.setImeVisible(false, 0) + InstrumentationRegistry.getInstrumentation().runOnMainSync { + onImeHidden!!.run() + verify(sysuiProxy).onStackExpandChanged(true) + shellExecutor.flushAll() + } + } + + @Test + fun collapseStack_waitsForIme() { + val bubble = createAndInflateBubble() + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + bubbleStackView.addBubble(bubble) + } + + InstrumentationRegistry.getInstrumentation().waitForIdleSync() + assertThat(bubbleStackView.bubbleCount).isEqualTo(1) + + positioner.setImeVisible(true, 100) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + // simulate a request from the bubble data listener to expand the stack + bubbleStackView.isExpanded = true + } + + var onImeHidden = bubbleStackViewManager.onImeHidden + assertThat(onImeHidden).isNotNull() + verify(sysuiProxy, never()).onStackExpandChanged(any()) + positioner.setImeVisible(false, 0) + InstrumentationRegistry.getInstrumentation().runOnMainSync { + onImeHidden!!.run() + verify(sysuiProxy).onStackExpandChanged(true) + shellExecutor.flushAll() + } + + bubbleStackViewManager.onImeHidden = null + positioner.setImeVisible(true, 100) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + // simulate a request from the bubble data listener to collapse the stack + bubbleStackView.isExpanded = false + } + + onImeHidden = bubbleStackViewManager.onImeHidden + assertThat(onImeHidden).isNotNull() + verify(sysuiProxy, never()).onStackExpandChanged(false) + positioner.setImeVisible(false, 0) + InstrumentationRegistry.getInstrumentation().runOnMainSync { + onImeHidden!!.run() + verify(sysuiProxy).onStackExpandChanged(false) + shellExecutor.flushAll() + } + } + + @EnableFlags(Flags.FLAG_ENABLE_BUBBLE_SWIPE_UP_CLEANUP) + @Test + fun expandStack_clearsImeRunnable() { + val bubble = createAndInflateBubble() + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + bubbleStackView.addBubble(bubble) + } + + InstrumentationRegistry.getInstrumentation().waitForIdleSync() + assertThat(bubbleStackView.bubbleCount).isEqualTo(1) + + // Set up a pending runnable to be cleared + bubbleStackViewManager.onImeHidden = Runnable { + fail("IME runnable should not be called when IME is hidden") + } + + positioner.setImeVisible(false, 0) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + // simulate a request from the bubble data listener to expand the stack + bubbleStackView.isExpanded = true + verify(sysuiProxy).onStackExpandChanged(true) + shellExecutor.flushAll() + } + + // Ime runnable is reset + assertThat(bubbleStackViewManager.onImeHidden).isNull() + } + + @EnableFlags(Flags.FLAG_ENABLE_BUBBLE_SWIPE_UP_CLEANUP) + @Test + fun collapseStack_clearsImeRunnable() { + val bubble = createAndInflateBubble() + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + bubbleStackView.addBubble(bubble) + } + + InstrumentationRegistry.getInstrumentation().waitForIdleSync() + assertThat(bubbleStackView.bubbleCount).isEqualTo(1) + + positioner.setImeVisible(false, 0) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + // simulate a request from the bubble data listener to expand the stack + bubbleStackView.isExpanded = true + verify(sysuiProxy).onStackExpandChanged(true) + shellExecutor.flushAll() + } + + // Set up a pending runnable to be cleared + bubbleStackViewManager.onImeHidden = Runnable { + fail("IME runnable should not be called when IME is hidden") + } + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + // simulate a request from the bubble data listener to collapse the stack + bubbleStackView.isExpanded = false + verify(sysuiProxy).onStackExpandChanged(false) + shellExecutor.flushAll() + } + + // Check that the runnable is cleared + assertThat(bubbleStackViewManager.onImeHidden).isNull() + } + @Test fun tapDifferentBubble_shouldReorder() { + surfaceSynchronizer.isActive = false val bubble1 = createAndInflateChatBubble(key = "bubble1") val bubble2 = createAndInflateChatBubble(key = "bubble2") InstrumentationRegistry.getInstrumentation().runOnMainSync { @@ -203,6 +410,7 @@ class BubbleStackViewTest { bubbleStackView.setSelectedBubble(bubble2) bubbleStackView.isExpanded = true + shellExecutor.flushAll() } assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() @@ -220,6 +428,7 @@ class BubbleStackViewTest { // tap on bubble1 to select it InstrumentationRegistry.getInstrumentation().runOnMainSync { bubble1.iconView!!.performClick() + shellExecutor.flushAll() } assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() assertThat(bubbleData.selectedBubble).isEqualTo(bubble1) @@ -230,6 +439,7 @@ class BubbleStackViewTest { // listener wired up. bubbleStackView.setSelectedBubble(bubble1) bubble1.iconView!!.performClick() + shellExecutor.flushAll() } assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() @@ -241,6 +451,147 @@ class BubbleStackViewTest { .inOrder() } + @Test + fun tapDifferentBubble_imeVisible_shouldWaitForIme() { + val bubble1 = createAndInflateChatBubble(key = "bubble1") + val bubble2 = createAndInflateChatBubble(key = "bubble2") + InstrumentationRegistry.getInstrumentation().runOnMainSync { + bubbleStackView.addBubble(bubble1) + bubbleStackView.addBubble(bubble2) + } + InstrumentationRegistry.getInstrumentation().waitForIdleSync() + + assertThat(bubbleStackView.bubbleCount).isEqualTo(2) + assertThat(bubbleData.bubbles).hasSize(2) + assertThat(bubbleData.selectedBubble).isEqualTo(bubble2) + assertThat(bubble2.iconView).isNotNull() + + val expandListener = FakeBubbleExpandListener() + bubbleStackView.setExpandListener(expandListener) + + var lastUpdate: BubbleData.Update? = null + val semaphore = Semaphore(0) + val listener = + BubbleData.Listener { update -> + lastUpdate = update + semaphore.release() + } + bubbleData.setListener(listener) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + bubble2.iconView!!.performClick() + assertThat(bubbleData.isExpanded).isTrue() + + bubbleStackView.setSelectedBubble(bubble2) + bubbleStackView.isExpanded = true + shellExecutor.flushAll() + } + + assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() + assertThat(lastUpdate!!.expanded).isTrue() + assertThat(lastUpdate!!.bubbles.map { it.key }) + .containsExactly("bubble2", "bubble1") + .inOrder() + + // wait for idle to allow the animation to start + InstrumentationRegistry.getInstrumentation().waitForIdleSync() + // wait for the expansion animation to complete before interacting with the bubbles + PhysicsAnimatorTestUtils.blockUntilAnimationsEnd( + AnimatableScaleMatrix.SCALE_X, AnimatableScaleMatrix.SCALE_Y) + + // make the IME visible and tap on bubble1 to select it + InstrumentationRegistry.getInstrumentation().runOnMainSync { + positioner.setImeVisible(true, 100) + bubble1.iconView!!.performClick() + // we have to set the selected bubble in the stack view manually because we don't have a + // listener wired up. + bubbleStackView.setSelectedBubble(bubble1) + shellExecutor.flushAll() + } + + val onImeHidden = bubbleStackViewManager.onImeHidden + assertThat(onImeHidden).isNotNull() + + assertThat(expandListener.bubblesExpandedState).isEqualTo(mapOf("bubble2" to true)) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + onImeHidden!!.run() + shellExecutor.flushAll() + } + + assertThat(expandListener.bubblesExpandedState) + .isEqualTo(mapOf("bubble1" to true, "bubble2" to false)) + assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() + assertThat(bubbleData.selectedBubble).isEqualTo(bubble1) + } + + @Test + fun tapDifferentBubble_imeHidden_updatesImmediately() { + val bubble1 = createAndInflateChatBubble(key = "bubble1") + val bubble2 = createAndInflateChatBubble(key = "bubble2") + InstrumentationRegistry.getInstrumentation().runOnMainSync { + bubbleStackView.addBubble(bubble1) + bubbleStackView.addBubble(bubble2) + } + InstrumentationRegistry.getInstrumentation().waitForIdleSync() + + assertThat(bubbleStackView.bubbleCount).isEqualTo(2) + assertThat(bubbleData.bubbles).hasSize(2) + assertThat(bubbleData.selectedBubble).isEqualTo(bubble2) + assertThat(bubble2.iconView).isNotNull() + + val expandListener = FakeBubbleExpandListener() + bubbleStackView.setExpandListener(expandListener) + + var lastUpdate: BubbleData.Update? = null + val semaphore = Semaphore(0) + val listener = + BubbleData.Listener { update -> + lastUpdate = update + semaphore.release() + } + bubbleData.setListener(listener) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + bubble2.iconView!!.performClick() + assertThat(bubbleData.isExpanded).isTrue() + + bubbleStackView.setSelectedBubble(bubble2) + bubbleStackView.isExpanded = true + shellExecutor.flushAll() + } + + assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() + assertThat(lastUpdate!!.expanded).isTrue() + assertThat(lastUpdate!!.bubbles.map { it.key }) + .containsExactly("bubble2", "bubble1") + .inOrder() + + // wait for idle to allow the animation to start + InstrumentationRegistry.getInstrumentation().waitForIdleSync() + // wait for the expansion animation to complete before interacting with the bubbles + PhysicsAnimatorTestUtils.blockUntilAnimationsEnd( + AnimatableScaleMatrix.SCALE_X, AnimatableScaleMatrix.SCALE_Y) + + // make the IME hidden and tap on bubble1 to select it + InstrumentationRegistry.getInstrumentation().runOnMainSync { + positioner.setImeVisible(false, 0) + bubble1.iconView!!.performClick() + // we have to set the selected bubble in the stack view manually because we don't have a + // listener wired up. + bubbleStackView.setSelectedBubble(bubble1) + shellExecutor.flushAll() + } + + val onImeHidden = bubbleStackViewManager.onImeHidden + assertThat(onImeHidden).isNull() + + assertThat(expandListener.bubblesExpandedState) + .isEqualTo(mapOf("bubble1" to true, "bubble2" to false)) + assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() + assertThat(bubbleData.selectedBubble).isEqualTo(bubble1) + } + @EnableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW) @Test fun testCreateStackView_noOverflowContents_noOverflow() { @@ -350,6 +701,122 @@ class BubbleStackViewTest { assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isGreaterThan(-1) } + @Test + fun removeFromWindow_stopMonitoringSwipeUpGesture() { + bubbleStackView = spy(bubbleStackView) + InstrumentationRegistry.getInstrumentation().runOnMainSync { + // No way to add to window in the test environment right now so just pretend + bubbleStackView.onDetachedFromWindow() + } + verify(bubbleStackView).stopMonitoringSwipeUpGesture() + } + + @Test + fun animateExpand_expandRunsRunnable() { + bubbleStackView = spy(bubbleStackView) + val bubble = createAndInflateChatBubble(key = "bubble") + + assertThat(bubble.expandedView).isNotNull() + + var afterTransitionRan = false + val semaphore = Semaphore(0) + + // Expand animation runs on a delay so wait for it. + val runnable = Runnable { + afterTransitionRan = true + semaphore.release() + } + + assertThat(bubbleStackView.isExpanded).isFalse() + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + bubbleStackView.addBubble(bubble) + bubbleStackView.setSelectedBubble(bubble) + bubbleStackView.animateExpand(null, runnable) + bubbleStackView.isExpanded = true + shellExecutor.flushAll() + } + + assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() + assertThat(bubbleStackView.isExpanded).isTrue() + assertThat(afterTransitionRan).isTrue() + } + + @Test + fun animateExpand_switchRunsRunnable() { + bubbleStackView = spy(bubbleStackView) + val bubble = createAndInflateChatBubble(key = "bubble") + val bubble2 = createAndInflateChatBubble(key = "bubble2") + + var afterTransitionRan = false + val semaphore = Semaphore(0) + + // Expand animation runs on a delay so wait for it. + val runnable = Runnable { + afterTransitionRan = true + semaphore.release() + } + assertThat(bubbleStackView.isExpanded).isFalse() + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + bubbleStackView.addBubble(bubble) + bubbleStackView.addBubble(bubble2) + bubbleStackView.setSelectedBubble(bubble) + bubbleStackView.isExpanded = true + shellExecutor.flushAll() + } + + assertThat(bubbleStackView.isExpanded).isTrue() + assertThat(bubbleStackView.expandedBubble!!.key).isEqualTo(bubble.key) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + bubbleStackView.animateExpand(null, runnable) + bubbleStackView.setSelectedBubble(bubble2) + shellExecutor.flushAll() + } + + assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() + assertThat(bubbleStackView.isExpanded).isTrue() + assertThat(bubbleStackView.expandedBubble!!.key).isEqualTo(bubble2.key) + assertThat(afterTransitionRan).isTrue() + } + + @Test + fun canExpandView_true_triggersContinueExpand() { + bubbleStackView = spy(bubbleStackView) + val bubble = createAndInflateChatBubble(key = "bubble") + val bubbleTransition = mock() + bubble.preparingTransition = bubbleTransition + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + bubbleStackView.addBubble(bubble) + } + + assertThat(bubbleStackView.isExpanded).isFalse() + assertThat(bubbleStackView.canExpandView(bubble)).isTrue() + verify(bubbleTransition).continueExpand() + } + + @Test + fun canExpandView_false() { + bubbleStackView = spy(bubbleStackView) + val bubble = createAndInflateChatBubble(key = "bubble") + val bubbleTransition = mock() + bubble.preparingTransition = bubbleTransition + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + bubbleStackView.addBubble(bubble) + bubbleStackView.setSelectedBubble(bubble) + bubbleStackView.isExpanded = true + shellExecutor.flushAll() + } + + assertThat(bubbleStackView.isExpanded).isTrue() + assertThat(bubbleStackView.expandedBubble!!.key).isEqualTo(bubble.key) + assertThat(bubbleStackView.canExpandView(bubble)).isFalse() + verify(bubbleTransition, never()).continueExpand() + } + private fun createAndInflateChatBubble(key: String): Bubble { val icon = Icon.createWithResource(context.resources, R.drawable.bubble_ic_overflow_button) val shortcutInfo = ShortcutInfo.Builder(context, "fakeId").setIcon(icon).build() @@ -363,6 +830,7 @@ class BubbleStackViewTest { /* taskId= */ 0, "locus", /* isDismissable= */ true, + directExecutor(), directExecutor() ) {} inflateBubble(bubble) @@ -372,7 +840,8 @@ class BubbleStackViewTest { private fun createAndInflateBubble(): Bubble { val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) val icon = Icon.createWithResource(context.resources, R.drawable.bubble_ic_overflow_button) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), icon, directExecutor()) + val bubble = + Bubble.createAppBubble(intent, UserHandle(1), icon, directExecutor(), directExecutor()) inflateBubble(bubble) return bubble } @@ -393,6 +862,7 @@ class BubbleStackViewTest { bubbleStackView, null, iconFactory, + FakeBubbleAppInfoProvider(), false ) @@ -401,6 +871,7 @@ class BubbleStackViewTest { } private class FakeBubbleStackViewManager : BubbleStackViewManager { + var onImeHidden: Runnable? = null override fun onAllBubblesAnimatedOut() {} @@ -408,55 +879,26 @@ class BubbleStackViewTest { override fun checkNotificationPanelExpandedState(callback: Consumer) {} - override fun hideCurrentInputMethod() {} - } - - private class TestShellExecutor : ShellExecutor { - - override fun execute(runnable: Runnable) { - runnable.run() + override fun hideCurrentInputMethod(onImeHidden: Runnable?) { + this.onImeHidden = onImeHidden } - override fun executeDelayed(r: Runnable, delayMillis: Long) { - r.run() - } - - override fun removeCallbacks(r: Runnable?) {} - - override fun hasCallback(r: Runnable): Boolean = false - } - - private inner class FakeBubbleTaskViewFactory : BubbleTaskViewFactory { - override fun create(): BubbleTaskView { - val taskViewTaskController = mock() - val taskView = TaskView(context, taskViewTaskController) - return BubbleTaskView(taskView, shellExecutor) + override fun clearImeHiddenRunnable() { + this.onImeHidden = null } } - private inner class FakeBubbleExpandedViewManager : BubbleExpandedViewManager { + private class FakeBubbleExpandListener : BubbleExpandListener { + val bubblesExpandedState = mutableMapOf() + override fun onBubbleExpandChanged(isExpanding: Boolean, key: String) { + bubblesExpandedState[key] = isExpanding + } + } - override val overflowBubbles: List - get() = emptyList() - - override fun setOverflowListener(listener: BubbleData.Listener) {} - - override fun collapseStack() {} - - override fun updateWindowFlagsForBackpress(intercept: Boolean) {} - - override fun promoteBubbleFromOverflow(bubble: Bubble) {} - - override fun removeBubble(key: String, reason: Int) {} - - override fun dismissBubble(bubble: Bubble, reason: Int) {} - - override fun setAppBubbleTaskId(key: String, taskId: Int) {} - - override fun isStackExpanded(): Boolean = false - - override fun isShowingAsBubbleBar(): Boolean = false - - override fun hideCurrentInputMethod() {} + private class FakeSurfaceSynchronizer : SurfaceSynchronizer { + var isActive = true + override fun syncSurfaceAndRun(callback: Runnable) { + if (isActive) callback.run() + } } } diff --git a/wmshell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewTest.kt b/wmshell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewTest.kt index 398fd554f0..18d940e9d5 100644 --- a/wmshell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewTest.kt +++ b/wmshell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewTest.kt @@ -16,39 +16,45 @@ package com.android.wm.shell.bubbles +import android.app.ActivityManager +import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.content.ComponentName import android.content.Context +import android.platform.test.flag.junit.FlagsParameterization +import android.platform.test.flag.junit.SetFlagsRule import androidx.test.core.app.ApplicationProvider -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.window.flags.Flags.FLAG_EXCLUDE_TASK_FROM_RECENTS +import com.android.wm.shell.Flags.FLAG_ENABLE_CREATE_ANY_BUBBLE +import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper import com.android.wm.shell.taskview.TaskView - import com.google.common.truth.Truth.assertThat import com.google.common.util.concurrent.MoreExecutors.directExecutor -import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.never +import org.mockito.kotlin.stub import org.mockito.kotlin.verify +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters @SmallTest -@RunWith(AndroidJUnit4::class) -class BubbleTaskViewTest { +@RunWith(ParameterizedAndroidJunit4::class) +class BubbleTaskViewTest(flags: FlagsParameterization) { + + @get:Rule + val setFlagsRule = SetFlagsRule(flags) - private lateinit var bubbleTaskView: BubbleTaskView private val context = ApplicationProvider.getApplicationContext() - private lateinit var taskView: TaskView - - @Before - fun setUp() { - taskView = mock() - bubbleTaskView = BubbleTaskView(taskView, directExecutor()) - } + private val componentName = ComponentName(context, "TestClass") + private val taskView = mock() + private val bubbleTaskView = BubbleTaskView(taskView, directExecutor()) @Test fun onTaskCreated_updatesState() { - val componentName = ComponentName(context, "TestClass") bubbleTaskView.listener.onTaskCreated(123, componentName) assertThat(bubbleTaskView.taskId).isEqualTo(123) @@ -68,25 +74,64 @@ class BubbleTaskViewTest { } bubbleTaskView.delegateListener = delegateListener - val componentName = ComponentName(context, "TestClass") - bubbleTaskView.listener.onTaskCreated(123, componentName) + bubbleTaskView.listener.onTaskCreated(123 /* taskId */, componentName) assertThat(actualTaskId).isEqualTo(123) assertThat(actualComponentName).isEqualTo(componentName) } @Test - fun cleanup_invalidTaskId_doesNotRemoveTask() { + fun cleanup_invalidTaskId_removesTask() { bubbleTaskView.cleanup() - verify(taskView, never()).removeTask() + verify(taskView).removeTask() } @Test fun cleanup_validTaskId_removesTask() { - val componentName = ComponentName(context, "TestClass") - bubbleTaskView.listener.onTaskCreated(123, componentName) + bubbleTaskView.listener.onTaskCreated(123 /* taskId */, componentName) bubbleTaskView.cleanup() + verify(taskView).removeTask() } + + @Test + fun cleanup_noneFullscreenTask_removesTask() { + bubbleTaskView.listener.onTaskCreated(123 /* taskId */, componentName) + + bubbleTaskView.cleanup() + + verify(taskView, never()).unregisterTask() + verify(taskView).removeTask() + } + + @Test + fun cleanup_fullscreenTask_removesOrUnregistersTask() { + val fullScreenTaskInfo = ActivityManager.RunningTaskInfo().apply { + configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN + } + taskView.stub { + on { taskInfo } doReturn fullScreenTaskInfo + } + bubbleTaskView.listener.onTaskCreated(123 /* taskId */, componentName) + + bubbleTaskView.cleanup() + + if (BubbleAnythingFlagHelper.enableCreateAnyBubbleWithForceExcludedFromRecents()) { + verify(taskView).unregisterTask() + verify(taskView, never()).removeTask() + } else { + verify(taskView, never()).unregisterTask() + verify(taskView).removeTask() + } + } + + companion object { + @JvmStatic + @Parameters(name = "{0}") + fun getParams() = FlagsParameterization.allCombinationsOf( + FLAG_ENABLE_CREATE_ANY_BUBBLE, + FLAG_EXCLUDE_TASK_FROM_RECENTS, + ) + } } diff --git a/wmshell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt b/wmshell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt index ace2c13105..eaa0937376 100644 --- a/wmshell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt +++ b/wmshell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt @@ -27,16 +27,16 @@ 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.common.ProtoLog +import com.android.internal.protolog.ProtoLog import com.android.wm.shell.R import com.android.wm.shell.bubbles.BubblePositioner -import com.android.wm.shell.bubbles.DeviceConfig -import com.android.wm.shell.common.bubbles.BaseBubblePinController -import com.android.wm.shell.common.bubbles.BaseBubblePinController.Companion.DROP_TARGET_ALPHA_IN_DURATION -import com.android.wm.shell.common.bubbles.BaseBubblePinController.Companion.DROP_TARGET_ALPHA_OUT_DURATION -import com.android.wm.shell.common.bubbles.BubbleBarLocation -import com.android.wm.shell.common.bubbles.BubbleBarLocation.LEFT -import com.android.wm.shell.common.bubbles.BubbleBarLocation.RIGHT +import com.android.wm.shell.shared.bubbles.BaseBubblePinController +import com.android.wm.shell.shared.bubbles.BaseBubblePinController.Companion.DROP_TARGET_ALPHA_IN_DURATION +import com.android.wm.shell.shared.bubbles.BaseBubblePinController.Companion.DROP_TARGET_ALPHA_OUT_DURATION +import com.android.wm.shell.shared.bubbles.BubbleBarLocation +import com.android.wm.shell.shared.bubbles.BubbleBarLocation.LEFT +import com.android.wm.shell.shared.bubbles.BubbleBarLocation.RIGHT +import com.android.wm.shell.shared.bubbles.DeviceConfig import com.google.common.truth.Truth.assertThat import org.junit.After import org.junit.Before @@ -74,6 +74,7 @@ class BubbleExpandedViewPinControllerTest { @Before fun setUp() { ProtoLog.REQUIRE_PROTOLOGTOOL = false + ProtoLog.init() container = FrameLayout(context) val windowManager = context.getSystemService(WindowManager::class.java) positioner = BubblePositioner(context, windowManager) @@ -85,11 +86,10 @@ class BubbleExpandedViewPinControllerTest { isSmallTablet = false, isLandscape = true, isRtl = false, - insets = Insets.of(10, 20, 30, 40) + insets = Insets.of(10, 20, 30, 40), ) positioner.update(deviceConfig) - positioner.bubbleBarTopOnScreen = - SCREEN_HEIGHT - deviceConfig.insets.bottom - BUBBLE_BAR_HEIGHT + positioner.updateBubbleBarTopOnScreen(BUBBLE_BAR_HEIGHT) controller = BubbleExpandedViewPinController(context, container, positioner) testListener = TestLocationChangeListener() controller.setListener(testListener) @@ -407,12 +407,26 @@ class BubbleExpandedViewPinControllerTest { assertThat(testListener.locationReleases).containsExactly(RIGHT) } + /** Send drag start event when on left */ + @Test + fun start_onLeft_sendStartEventOnLeft() { + getInstrumentation().runOnMainSync { controller.onDragStart(initialLocationOnLeft = true) } + assertThat(testListener.locationStart).containsExactly(LEFT) + } + + /** Send drag start event when on right */ + @Test + fun start_onRight_sendStartEventOnRight() { + getInstrumentation().runOnMainSync { controller.onDragStart(initialLocationOnLeft = false) } + assertThat(testListener.locationStart).containsExactly(RIGHT) + } + private fun getExpectedDropTargetBoundsOnLeft(): Rect = Rect().also { positioner.getBubbleBarExpandedViewBounds( true /* onLeft */, false /* isOverflowExpanded */, - it + it, ) } @@ -421,7 +435,7 @@ class BubbleExpandedViewPinControllerTest { positioner.getBubbleBarExpandedViewBounds( false /* onLeft */, false /* isOverflowExpanded */, - it + it, ) } @@ -446,8 +460,14 @@ class BubbleExpandedViewPinControllerTest { } internal class TestLocationChangeListener : BaseBubblePinController.LocationChangeListener { + val locationStart = mutableListOf() val locationChanges = mutableListOf() val locationReleases = mutableListOf() + + override fun onStart(location: BubbleBarLocation) { + locationStart.add(location) + } + override fun onChange(location: BubbleBarLocation) { locationChanges.add(location) } diff --git a/wmshell/multivalentTestsForDevice/Android.bp b/wmshell/multivalentTestsForDevice/Android.bp deleted file mode 100644 index 1ad19c9f30..0000000000 --- a/wmshell/multivalentTestsForDevice/Android.bp +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (C) 2019 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 { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_base_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_base_license"], - default_team: "trendy_team_multitasking_windowing", -} - -android_app { - name: "WindowManagerShellRobolectric", - platform_apis: true, - static_libs: [ - "WindowManager-Shell", - ], - manifest: "AndroidManifestRobolectric.xml", - use_resource_processor: true, -} - -android_robolectric_test { - name: "WMShellRobolectricTests", - instrumentation_for: "WindowManagerShellRobolectric", - upstream: true, - java_resource_dirs: [ - "robolectric/config", - ], - srcs: [ - "src/**/*.kt", - ], - // TODO(b/323188766): Include BubbleStackViewTest once the robolectric issue is fixed. - exclude_srcs: ["src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt"], - static_libs: [ - "junit", - "androidx.core_core-animation-testing", - "androidx.test.runner", - "androidx.test.rules", - "androidx.test.ext.junit", - "mockito-robolectric-prebuilt", - "mockito-kotlin2", - "truth", - ], - auto_gen_config: true, -} - -android_test { - name: "WMShellMultivalentTestsOnDevice", - srcs: [ - "src/**/*.kt", - ], - static_libs: [ - "WindowManager-Shell", - "junit", - "androidx.core_core-animation-testing", - "androidx.test.runner", - "androidx.test.rules", - "androidx.test.ext.junit", - "frameworks-base-testutils", - "mockito-kotlin2", - "mockito-target-extended-minus-junit4", - "truth", - "platform-test-annotations", - "platform-test-rules", - ], - libs: [ - "android.test.base", - "android.test.runner", - ], - jni_libs: [ - "libdexmakerjvmtiagent", - "libstaticjvmtiagent", - ], - kotlincflags: ["-Xjvm-default=all"], - optimize: { - enabled: false, - }, - test_suites: ["device-tests"], - platform_apis: true, - certificate: "platform", - aaptflags: [ - "--extra-packages", - "com.android.wm.shell", - ], - manifest: "AndroidManifest.xml", -} diff --git a/wmshell/multivalentTestsForDevice/AndroidManifest.xml b/wmshell/multivalentTestsForDevice/AndroidManifest.xml deleted file mode 100644 index f8f8338e5f..0000000000 --- a/wmshell/multivalentTestsForDevice/AndroidManifest.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - diff --git a/wmshell/multivalentTestsForDevice/AndroidManifestRobolectric.xml b/wmshell/multivalentTestsForDevice/AndroidManifestRobolectric.xml deleted file mode 100644 index ffcd7d46fb..0000000000 --- a/wmshell/multivalentTestsForDevice/AndroidManifestRobolectric.xml +++ /dev/null @@ -1,3 +0,0 @@ - - diff --git a/wmshell/multivalentTestsForDevice/AndroidTest.xml b/wmshell/multivalentTestsForDevice/AndroidTest.xml deleted file mode 100644 index 36fe8ec337..0000000000 --- a/wmshell/multivalentTestsForDevice/AndroidTest.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - diff --git a/wmshell/multivalentTestsForDevice/OWNERS b/wmshell/multivalentTestsForDevice/OWNERS deleted file mode 100644 index 24c1a3a6d4..0000000000 --- a/wmshell/multivalentTestsForDevice/OWNERS +++ /dev/null @@ -1,4 +0,0 @@ -atsjenk@google.com -liranb@google.com -madym@google.com - diff --git a/wmshell/multivalentTestsForDevice/robolectric/config/robolectric.properties b/wmshell/multivalentTestsForDevice/robolectric/config/robolectric.properties deleted file mode 100644 index 7a0527ccaa..0000000000 --- a/wmshell/multivalentTestsForDevice/robolectric/config/robolectric.properties +++ /dev/null @@ -1,2 +0,0 @@ -sdk=NEWEST_SDK - diff --git a/wmshell/multivalentTestsForDevice/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt b/wmshell/multivalentTestsForDevice/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt deleted file mode 100644 index 9e1440d571..0000000000 --- a/wmshell/multivalentTestsForDevice/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt +++ /dev/null @@ -1,670 +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 android.content.Context -import android.content.Intent -import android.content.pm.ShortcutInfo -import android.content.res.Resources -import android.graphics.Insets -import android.graphics.PointF -import android.graphics.Rect -import android.os.UserHandle -import android.view.WindowManager -import androidx.test.core.app.ApplicationProvider -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.android.internal.protolog.common.ProtoLog -import com.android.wm.shell.R -import com.android.wm.shell.bubbles.BubblePositioner.MAX_HEIGHT -import com.android.wm.shell.common.bubbles.BubbleBarLocation -import com.google.common.truth.Truth.assertThat -import com.google.common.util.concurrent.MoreExecutors.directExecutor -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith - -/** Tests operations and the resulting state managed by [BubblePositioner]. */ -@SmallTest -@RunWith(AndroidJUnit4::class) -class BubblePositionerTest { - - private lateinit var positioner: BubblePositioner - private val context = ApplicationProvider.getApplicationContext() - private val resources: Resources - get() = context.resources - - private val defaultDeviceConfig = - DeviceConfig( - windowBounds = Rect(0, 0, 1000, 2000), - isLargeScreen = false, - isSmallTablet = false, - isLandscape = false, - isRtl = false, - insets = Insets.of(0, 0, 0, 0) - ) - - @Before - fun setUp() { - ProtoLog.REQUIRE_PROTOLOGTOOL = false - val windowManager = context.getSystemService(WindowManager::class.java) - positioner = BubblePositioner(context, windowManager) - } - - @Test - fun testUpdate() { - val insets = Insets.of(10, 20, 5, 15) - val screenBounds = Rect(0, 0, 1000, 1200) - val availableRect = Rect(screenBounds) - availableRect.inset(insets) - positioner.update(defaultDeviceConfig.copy(insets = insets, windowBounds = screenBounds)) - assertThat(positioner.availableRect).isEqualTo(availableRect) - assertThat(positioner.isLandscape).isFalse() - assertThat(positioner.isLargeScreen).isFalse() - assertThat(positioner.insets).isEqualTo(insets) - } - - @Test - fun testShowBubblesVertically_phonePortrait() { - positioner.update(defaultDeviceConfig) - assertThat(positioner.showBubblesVertically()).isFalse() - } - - @Test - fun testShowBubblesVertically_phoneLandscape() { - positioner.update(defaultDeviceConfig.copy(isLandscape = true)) - assertThat(positioner.isLandscape).isTrue() - assertThat(positioner.showBubblesVertically()).isTrue() - } - - @Test - fun testShowBubblesVertically_tablet() { - positioner.update(defaultDeviceConfig.copy(isLargeScreen = true)) - assertThat(positioner.showBubblesVertically()).isTrue() - } - - /** If a resting position hasn't been set, calling it will return the default position. */ - @Test - fun testGetRestingPosition_returnsDefaultPosition() { - positioner.update(defaultDeviceConfig) - val restingPosition = positioner.getRestingPosition() - val defaultPosition = positioner.defaultStartPosition - assertThat(restingPosition).isEqualTo(defaultPosition) - } - - /** If a resting position has been set, it'll return that instead of the default position. */ - @Test - fun testGetRestingPosition_returnsRestingPosition() { - positioner.update(defaultDeviceConfig) - val restingPosition = PointF(100f, 100f) - positioner.restingPosition = restingPosition - assertThat(positioner.getRestingPosition()).isEqualTo(restingPosition) - } - - /** Test that the default resting position on phone is in upper left. */ - @Test - fun testGetRestingPosition_bubble_onPhone() { - positioner.update(defaultDeviceConfig) - val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - val restingPosition = positioner.getRestingPosition() - assertThat(restingPosition.x).isEqualTo(allowableStackRegion.left) - assertThat(restingPosition.y).isEqualTo(defaultYPosition) - } - - @Test - fun testGetRestingPosition_bubble_onPhone_RTL() { - positioner.update(defaultDeviceConfig.copy(isRtl = true)) - val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - val restingPosition = positioner.getRestingPosition() - assertThat(restingPosition.x).isEqualTo(allowableStackRegion.right) - assertThat(restingPosition.y).isEqualTo(defaultYPosition) - } - - /** Test that the default resting position on tablet is middle left. */ - @Test - fun testGetRestingPosition_chatBubble_onTablet() { - positioner.update(defaultDeviceConfig.copy(isLargeScreen = true)) - val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - val restingPosition = positioner.getRestingPosition() - assertThat(restingPosition.x).isEqualTo(allowableStackRegion.left) - assertThat(restingPosition.y).isEqualTo(defaultYPosition) - } - - @Test - fun testGetRestingPosition_chatBubble_onTablet_RTL() { - positioner.update(defaultDeviceConfig.copy(isLargeScreen = true, isRtl = true)) - val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - val restingPosition = positioner.getRestingPosition() - assertThat(restingPosition.x).isEqualTo(allowableStackRegion.right) - assertThat(restingPosition.y).isEqualTo(defaultYPosition) - } - - /** Test that the default resting position on tablet is middle right. */ - @Test - fun testGetDefaultPosition_appBubble_onTablet() { - positioner.update(defaultDeviceConfig.copy(isLargeScreen = true)) - val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - val startPosition = positioner.getDefaultStartPosition(true /* isAppBubble */) - assertThat(startPosition.x).isEqualTo(allowableStackRegion.right) - assertThat(startPosition.y).isEqualTo(defaultYPosition) - } - - @Test - fun testGetRestingPosition_appBubble_onTablet_RTL() { - positioner.update(defaultDeviceConfig.copy(isLargeScreen = true, isRtl = true)) - val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - val startPosition = positioner.getDefaultStartPosition(true /* isAppBubble */) - assertThat(startPosition.x).isEqualTo(allowableStackRegion.left) - assertThat(startPosition.y).isEqualTo(defaultYPosition) - } - - @Test - fun testGetRestingPosition_afterBoundsChange() { - positioner.update( - defaultDeviceConfig.copy(isLargeScreen = true, windowBounds = Rect(0, 0, 2000, 1600)) - ) - - // Set the resting position to the right side - var allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - val restingPosition = PointF(allowableStackRegion.right, allowableStackRegion.centerY()) - positioner.restingPosition = restingPosition - - // Now make the device smaller - positioner.update( - defaultDeviceConfig.copy(isLargeScreen = false, windowBounds = Rect(0, 0, 1000, 1600)) - ) - - // Check the resting position is on the correct side - allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - assertThat(positioner.restingPosition.x).isEqualTo(allowableStackRegion.right) - } - - @Test - fun testHasUserModifiedDefaultPosition_false() { - positioner.update(defaultDeviceConfig.copy(isLargeScreen = true, isRtl = true)) - assertThat(positioner.hasUserModifiedDefaultPosition()).isFalse() - positioner.restingPosition = positioner.defaultStartPosition - assertThat(positioner.hasUserModifiedDefaultPosition()).isFalse() - } - - @Test - fun testHasUserModifiedDefaultPosition_true() { - positioner.update(defaultDeviceConfig.copy(isLargeScreen = true, isRtl = true)) - assertThat(positioner.hasUserModifiedDefaultPosition()).isFalse() - positioner.restingPosition = PointF(0f, 100f) - assertThat(positioner.hasUserModifiedDefaultPosition()).isTrue() - } - - @Test - fun testBubbleBarExpandedViewHeightAndWidth() { - val deviceConfig = - defaultDeviceConfig.copy( - // portrait orientation - isLandscape = false, - isLargeScreen = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - - positioner.setShowingInBubbleBar(true) - positioner.update(deviceConfig) - positioner.bubbleBarTopOnScreen = 2500 - - val spaceBetweenTopInsetAndBubbleBarInLandscape = 1680 - val expandedViewVerticalSpacing = - resources.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding) - val expectedHeight = - spaceBetweenTopInsetAndBubbleBarInLandscape - 2 * expandedViewVerticalSpacing - val expectedWidth = resources.getDimensionPixelSize(R.dimen.bubble_bar_expanded_view_width) - - assertThat(positioner.getExpandedViewWidthForBubbleBar(false)).isEqualTo(expectedWidth) - assertThat(positioner.getExpandedViewHeightForBubbleBar(false)).isEqualTo(expectedHeight) - } - - @Test - fun testBubbleBarExpandedViewHeightAndWidth_screenWidthTooSmall() { - val screenWidth = 300 - val deviceConfig = - defaultDeviceConfig.copy( - // portrait orientation - isLandscape = false, - isLargeScreen = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, screenWidth, 2600) - ) - positioner.setShowingInBubbleBar(true) - positioner.update(deviceConfig) - positioner.bubbleBarTopOnScreen = 2500 - - val spaceBetweenTopInsetAndBubbleBarInLandscape = 180 - val expandedViewSpacing = - resources.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding) - val expectedHeight = spaceBetweenTopInsetAndBubbleBarInLandscape - 2 * expandedViewSpacing - val expectedWidth = screenWidth - 15 /* horizontal insets */ - 2 * expandedViewSpacing - assertThat(positioner.getExpandedViewWidthForBubbleBar(false)).isEqualTo(expectedWidth) - assertThat(positioner.getExpandedViewHeightForBubbleBar(false)).isEqualTo(expectedHeight) - } - - @Test - fun testGetExpandedViewHeight_max() { - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) - - assertThat(positioner.getExpandedViewHeight(bubble)).isEqualTo(MAX_HEIGHT) - } - - @Test - fun testGetExpandedViewHeight_customHeight_valid() { - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - val minHeight = - context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_default_height) - val bubble = - Bubble( - "key", - ShortcutInfo.Builder(context, "id").build(), - minHeight + 100 /* desiredHeight */, - 0 /* desiredHeightResId */, - "title", - 0 /* taskId */, - null /* locus */, - true /* isDismissable */, - directExecutor() - ) {} - - // Ensure the height is the same as the desired value - assertThat(positioner.getExpandedViewHeight(bubble)) - .isEqualTo(bubble.getDesiredHeight(context)) - } - - @Test - fun testGetExpandedViewHeight_customHeight_tooSmall() { - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - val bubble = - Bubble( - "key", - ShortcutInfo.Builder(context, "id").build(), - 10 /* desiredHeight */, - 0 /* desiredHeightResId */, - "title", - 0 /* taskId */, - null /* locus */, - true /* isDismissable */, - directExecutor() - ) {} - - // Ensure the height is the same as the desired value - val minHeight = - context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_default_height) - assertThat(positioner.getExpandedViewHeight(bubble)).isEqualTo(minHeight) - } - - @Test - fun testGetMaxExpandedViewHeight_onLargeTablet() { - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - val manageButtonHeight = - context.resources.getDimensionPixelSize(R.dimen.bubble_manage_button_height) - val pointerWidth = context.resources.getDimensionPixelSize(R.dimen.bubble_pointer_width) - val expandedViewPadding = - context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding) - val expectedHeight = - 1800 - 2 * 20 - manageButtonHeight - pointerWidth - expandedViewPadding * 2 - assertThat(positioner.getMaxExpandedViewHeight(false /* isOverflow */)) - .isEqualTo(expectedHeight) - } - - @Test - fun testAreBubblesBottomAligned_largeScreen_true() { - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - assertThat(positioner.areBubblesBottomAligned()).isTrue() - } - - @Test - fun testAreBubblesBottomAligned_largeScreen_landscape_false() { - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - isLandscape = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - assertThat(positioner.areBubblesBottomAligned()).isFalse() - } - - @Test - fun testAreBubblesBottomAligned_smallTablet_false() { - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - isSmallTablet = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - assertThat(positioner.areBubblesBottomAligned()).isFalse() - } - - @Test - fun testAreBubblesBottomAligned_phone_false() { - val deviceConfig = - defaultDeviceConfig.copy( - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - assertThat(positioner.areBubblesBottomAligned()).isFalse() - } - - @Test - fun testExpandedViewY_phoneLandscape() { - val deviceConfig = - defaultDeviceConfig.copy( - isLandscape = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) - - // This bubble will have max height so it'll always be top aligned - assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) - .isEqualTo(positioner.getExpandedViewYTopAligned()) - } - - @Test - fun testExpandedViewY_phonePortrait() { - val deviceConfig = - defaultDeviceConfig.copy( - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) - - // Always top aligned in phone portrait - assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) - .isEqualTo(positioner.getExpandedViewYTopAligned()) - } - - @Test - fun testExpandedViewY_smallTabletLandscape() { - val deviceConfig = - defaultDeviceConfig.copy( - isSmallTablet = true, - isLandscape = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) - - // This bubble will have max height which is always top aligned on small tablets - assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) - .isEqualTo(positioner.getExpandedViewYTopAligned()) - } - - @Test - fun testExpandedViewY_smallTabletPortrait() { - val deviceConfig = - defaultDeviceConfig.copy( - isSmallTablet = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) - - // This bubble will have max height which is always top aligned on small tablets - assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) - .isEqualTo(positioner.getExpandedViewYTopAligned()) - } - - @Test - fun testExpandedViewY_largeScreenLandscape() { - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - isLandscape = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) - - // This bubble will have max height which is always top aligned on landscape, large tablet - assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) - .isEqualTo(positioner.getExpandedViewYTopAligned()) - } - - @Test - fun testExpandedViewY_largeScreenPortrait() { - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) - - val manageButtonHeight = - context.resources.getDimensionPixelSize(R.dimen.bubble_manage_button_height) - val manageButtonPlusMargin = - manageButtonHeight + - 2 * context.resources.getDimensionPixelSize(R.dimen.bubble_manage_button_margin) - val pointerWidth = context.resources.getDimensionPixelSize(R.dimen.bubble_pointer_width) - - val expectedExpandedViewY = - positioner.availableRect.bottom - - manageButtonPlusMargin - - positioner.getExpandedViewHeightForLargeScreen() - - pointerWidth - - // Bubbles are bottom aligned on portrait, large tablet - assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) - .isEqualTo(expectedExpandedViewY) - } - - @Test - fun testGetTaskViewContentWidth_onLeft() { - positioner.update(defaultDeviceConfig.copy(insets = Insets.of(100, 0, 200, 0))) - val taskViewWidth = positioner.getTaskViewContentWidth(true /* onLeft */) - val paddings = - positioner.getExpandedViewContainerPadding(true /* onLeft */, false /* isOverflow */) - assertThat(taskViewWidth) - .isEqualTo(positioner.screenRect.width() - paddings[0] - paddings[2]) - } - - @Test - fun testGetTaskViewContentWidth_onRight() { - positioner.update(defaultDeviceConfig.copy(insets = Insets.of(100, 0, 200, 0))) - val taskViewWidth = positioner.getTaskViewContentWidth(false /* onLeft */) - val paddings = - positioner.getExpandedViewContainerPadding(false /* onLeft */, false /* isOverflow */) - assertThat(taskViewWidth) - .isEqualTo(positioner.screenRect.width() - paddings[0] - paddings[2]) - } - - @Test - fun testIsBubbleBarOnLeft_defaultsToRight() { - positioner.bubbleBarLocation = BubbleBarLocation.DEFAULT - assertThat(positioner.isBubbleBarOnLeft).isFalse() - - // Check that left and right return expected position - positioner.bubbleBarLocation = BubbleBarLocation.LEFT - assertThat(positioner.isBubbleBarOnLeft).isTrue() - positioner.bubbleBarLocation = BubbleBarLocation.RIGHT - assertThat(positioner.isBubbleBarOnLeft).isFalse() - } - - @Test - fun testIsBubbleBarOnLeft_rtlEnabled_defaultsToLeft() { - positioner.update(defaultDeviceConfig.copy(isRtl = true)) - - positioner.bubbleBarLocation = BubbleBarLocation.DEFAULT - assertThat(positioner.isBubbleBarOnLeft).isTrue() - - // Check that left and right return expected position - positioner.bubbleBarLocation = BubbleBarLocation.LEFT - assertThat(positioner.isBubbleBarOnLeft).isTrue() - positioner.bubbleBarLocation = BubbleBarLocation.RIGHT - assertThat(positioner.isBubbleBarOnLeft).isFalse() - } - - @Test - fun testGetBubbleBarExpandedViewBounds_onLeft() { - testGetBubbleBarExpandedViewBounds(onLeft = true, isOverflow = false) - } - - @Test - fun testGetBubbleBarExpandedViewBounds_onRight() { - testGetBubbleBarExpandedViewBounds(onLeft = false, isOverflow = false) - } - - @Test - fun testGetBubbleBarExpandedViewBounds_isOverflow_onLeft() { - testGetBubbleBarExpandedViewBounds(onLeft = true, isOverflow = true) - } - - @Test - fun testGetBubbleBarExpandedViewBounds_isOverflow_onRight() { - testGetBubbleBarExpandedViewBounds(onLeft = false, isOverflow = true) - } - - private fun testGetBubbleBarExpandedViewBounds(onLeft: Boolean, isOverflow: Boolean) { - positioner.setShowingInBubbleBar(true) - val windowBounds = Rect(0, 0, 2000, 2600) - val insets = Insets.of(10, 20, 5, 15) - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - isLandscape = true, - insets = insets, - windowBounds = windowBounds - ) - positioner.update(deviceConfig) - - val bubbleBarHeight = 100 - positioner.bubbleBarTopOnScreen = windowBounds.bottom - insets.bottom - bubbleBarHeight - - val expandedViewPadding = - context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding) - - val left: Int - val right: Int - if (onLeft) { - // Pin to the left, calculate right - left = deviceConfig.insets.left + expandedViewPadding - right = left + positioner.getExpandedViewWidthForBubbleBar(isOverflow) - } else { - // Pin to the right, calculate left - right = - deviceConfig.windowBounds.right - deviceConfig.insets.right - expandedViewPadding - left = right - positioner.getExpandedViewWidthForBubbleBar(isOverflow) - } - // Above the bubble bar - val bottom = positioner.bubbleBarTopOnScreen - expandedViewPadding - // Calculate right and top based on size - val top = bottom - positioner.getExpandedViewHeightForBubbleBar(isOverflow) - val expectedBounds = Rect(left, top, right, bottom) - - val bounds = Rect() - positioner.getBubbleBarExpandedViewBounds(onLeft, isOverflow, bounds) - - assertThat(bounds).isEqualTo(expectedBounds) - } - - private val defaultYPosition: Float - /** - * Calculates the Y position bubbles should be placed based on the config. Based on the - * calculations in [BubblePositioner.getDefaultStartPosition] and - * [BubbleStackView.RelativeStackPosition]. - */ - get() { - val isTablet = positioner.isLargeScreen - - // On tablet the position is centered, on phone it is an offset from the top. - val desiredY = - if (isTablet) { - positioner.screenRect.height() / 2f - positioner.bubbleSize / 2f - } else { - context.resources - .getDimensionPixelOffset(R.dimen.bubble_stack_starting_offset_y) - .toFloat() - } - // Since we're visually centering the bubbles on tablet, use total screen height rather - // than the available height. - val height = - if (isTablet) { - positioner.screenRect.height() - } else { - positioner.availableRect.height() - } - val offsetPercent = (desiredY / height).coerceIn(0f, 1f) - val allowableStackRegion = - positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - return allowableStackRegion.top + allowableStackRegion.height() * offsetPercent - } -} diff --git a/wmshell/multivalentTestsForDevice/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt b/wmshell/multivalentTestsForDevice/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt deleted file mode 100644 index 327e205955..0000000000 --- a/wmshell/multivalentTestsForDevice/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright (C) 2024 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.content.Context -import android.content.Intent -import android.content.pm.ShortcutInfo -import android.content.res.Resources -import android.graphics.Color -import android.graphics.drawable.Icon -import android.os.UserHandle -import android.platform.test.flag.junit.SetFlagsRule -import android.view.IWindowManager -import android.view.WindowManager -import android.view.WindowManagerGlobal -import androidx.test.core.app.ApplicationProvider -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import androidx.test.platform.app.InstrumentationRegistry -import com.android.internal.logging.testing.UiEventLoggerFake -import com.android.internal.protolog.common.ProtoLog -import com.android.launcher3.icons.BubbleIconFactory -import com.android.wm.shell.Flags -import com.android.wm.shell.R -import com.android.wm.shell.bubbles.Bubbles.SysuiProxy -import com.android.wm.shell.bubbles.animation.AnimatableScaleMatrix -import com.android.wm.shell.common.FloatingContentCoordinator -import com.android.wm.shell.common.ShellExecutor -import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils -import com.android.wm.shell.taskview.TaskView -import com.android.wm.shell.taskview.TaskViewTaskController -import com.google.common.truth.Truth.assertThat -import com.google.common.util.concurrent.MoreExecutors.directExecutor -import org.junit.After -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.kotlin.mock -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags -import java.util.concurrent.Semaphore -import java.util.concurrent.TimeUnit -import java.util.function.Consumer - -/** Unit tests for [BubbleStackView]. */ -@SmallTest -@RunWith(AndroidJUnit4::class) -class BubbleStackViewTest { - - @get:Rule val setFlagsRule = SetFlagsRule() - - private val context = ApplicationProvider.getApplicationContext() - private lateinit var positioner: BubblePositioner - private lateinit var iconFactory: BubbleIconFactory - private lateinit var expandedViewManager: FakeBubbleExpandedViewManager - private lateinit var bubbleStackView: BubbleStackView - private lateinit var shellExecutor: ShellExecutor - private lateinit var windowManager: IWindowManager - private lateinit var bubbleTaskViewFactory: BubbleTaskViewFactory - private lateinit var bubbleData: BubbleData - private lateinit var bubbleStackViewManager: FakeBubbleStackViewManager - private var sysuiProxy = mock() - - @Before - fun setUp() { - PhysicsAnimatorTestUtils.prepareForTest() - // Disable protolog tool when running the tests from studio - ProtoLog.REQUIRE_PROTOLOGTOOL = false - windowManager = WindowManagerGlobal.getWindowManagerService()!! - shellExecutor = TestShellExecutor() - val windowManager = context.getSystemService(WindowManager::class.java) - iconFactory = - BubbleIconFactory( - context, - context.resources.getDimensionPixelSize(R.dimen.bubble_size), - context.resources.getDimensionPixelSize(R.dimen.bubble_badge_size), - Color.BLACK, - context.resources.getDimensionPixelSize( - com.android.internal.R.dimen.importance_ring_stroke_width - ) - ) - positioner = BubblePositioner(context, windowManager) - bubbleData = - BubbleData( - context, - BubbleLogger(UiEventLoggerFake()), - positioner, - BubbleEducationController(context), - shellExecutor - ) - bubbleStackViewManager = FakeBubbleStackViewManager() - expandedViewManager = FakeBubbleExpandedViewManager() - bubbleTaskViewFactory = FakeBubbleTaskViewFactory() - bubbleStackView = - BubbleStackView( - context, - bubbleStackViewManager, - positioner, - bubbleData, - null, - FloatingContentCoordinator(), - { sysuiProxy }, - shellExecutor - ) - - context - .getSharedPreferences(context.packageName, Context.MODE_PRIVATE) - .edit() - .putBoolean(StackEducationView.PREF_STACK_EDUCATION, true) - .apply() - } - - @After - fun tearDown() { - PhysicsAnimatorTestUtils.tearDown() - } - - @Test - fun addBubble() { - val bubble = createAndInflateBubble() - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubbleStackView.addBubble(bubble) - } - InstrumentationRegistry.getInstrumentation().waitForIdleSync() - assertThat(bubbleStackView.bubbleCount).isEqualTo(1) - } - - @Test - fun tapBubbleToExpand() { - val bubble = createAndInflateBubble() - - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubbleStackView.addBubble(bubble) - } - - InstrumentationRegistry.getInstrumentation().waitForIdleSync() - assertThat(bubbleStackView.bubbleCount).isEqualTo(1) - var lastUpdate: BubbleData.Update? = null - val semaphore = Semaphore(0) - val listener = - BubbleData.Listener { update -> - lastUpdate = update - semaphore.release() - } - bubbleData.setListener(listener) - - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubble.iconView!!.performClick() - // we're checking the expanded state in BubbleData because that's the source of truth. - // This will eventually propagate an update back to the stack view, but setting the - // entire pipeline is outside the scope of a unit test. - assertThat(bubbleData.isExpanded).isTrue() - } - - assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() - assertThat(lastUpdate).isNotNull() - assertThat(lastUpdate!!.expandedChanged).isTrue() - assertThat(lastUpdate!!.expanded).isTrue() - } - - @Test - fun tapDifferentBubble_shouldReorder() { - val bubble1 = createAndInflateChatBubble(key = "bubble1") - val bubble2 = createAndInflateChatBubble(key = "bubble2") - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubbleStackView.addBubble(bubble1) - bubbleStackView.addBubble(bubble2) - } - InstrumentationRegistry.getInstrumentation().waitForIdleSync() - - assertThat(bubbleStackView.bubbleCount).isEqualTo(2) - assertThat(bubbleData.bubbles).hasSize(2) - assertThat(bubbleData.selectedBubble).isEqualTo(bubble2) - assertThat(bubble2.iconView).isNotNull() - - var lastUpdate: BubbleData.Update? = null - val semaphore = Semaphore(0) - val listener = - BubbleData.Listener { update -> - lastUpdate = update - semaphore.release() - } - bubbleData.setListener(listener) - - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubble2.iconView!!.performClick() - assertThat(bubbleData.isExpanded).isTrue() - - bubbleStackView.setSelectedBubble(bubble2) - bubbleStackView.isExpanded = true - } - - assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() - assertThat(lastUpdate!!.expanded).isTrue() - assertThat(lastUpdate!!.bubbles.map { it.key }) - .containsExactly("bubble2", "bubble1") - .inOrder() - - // wait for idle to allow the animation to start - InstrumentationRegistry.getInstrumentation().waitForIdleSync() - // wait for the expansion animation to complete before interacting with the bubbles - PhysicsAnimatorTestUtils.blockUntilAnimationsEnd( - AnimatableScaleMatrix.SCALE_X, AnimatableScaleMatrix.SCALE_Y) - - // tap on bubble1 to select it - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubble1.iconView!!.performClick() - } - assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() - assertThat(bubbleData.selectedBubble).isEqualTo(bubble1) - - // tap on bubble1 again to collapse the stack - InstrumentationRegistry.getInstrumentation().runOnMainSync { - // we have to set the selected bubble in the stack view manually because we don't have a - // listener wired up. - bubbleStackView.setSelectedBubble(bubble1) - bubble1.iconView!!.performClick() - } - - assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() - assertThat(bubbleData.selectedBubble).isEqualTo(bubble1) - assertThat(bubbleData.isExpanded).isFalse() - assertThat(lastUpdate!!.orderChanged).isTrue() - assertThat(lastUpdate!!.bubbles.map { it.key }) - .containsExactly("bubble1", "bubble2") - .inOrder() - } - - @EnableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW) - @Test - fun testCreateStackView_noOverflowContents_noOverflow() { - bubbleStackView = - BubbleStackView( - context, - bubbleStackViewManager, - positioner, - bubbleData, - null, - FloatingContentCoordinator(), - { sysuiProxy }, - shellExecutor - ) - - assertThat(bubbleData.overflowBubbles).isEmpty() - val bubbleOverflow = bubbleData.overflow - // Overflow shouldn't be attached - assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isEqualTo(-1) - } - - @EnableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW) - @Test - fun testCreateStackView_hasOverflowContents_hasOverflow() { - // Add a bubble to the overflow - val bubble1 = createAndInflateChatBubble(key = "bubble1") - bubbleData.notificationEntryUpdated(bubble1, false, false) - bubbleData.dismissBubbleWithKey(bubble1.key, Bubbles.DISMISS_USER_GESTURE) - assertThat(bubbleData.overflowBubbles).isNotEmpty() - - bubbleStackView = - BubbleStackView( - context, - bubbleStackViewManager, - positioner, - bubbleData, - null, - FloatingContentCoordinator(), - { sysuiProxy }, - shellExecutor - ) - val bubbleOverflow = bubbleData.overflow - assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isGreaterThan(-1) - } - - @DisableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW) - @Test - fun testCreateStackView_noOverflowContents_hasOverflow() { - bubbleStackView = - BubbleStackView( - context, - bubbleStackViewManager, - positioner, - bubbleData, - null, - FloatingContentCoordinator(), - { sysuiProxy }, - shellExecutor - ) - - assertThat(bubbleData.overflowBubbles).isEmpty() - val bubbleOverflow = bubbleData.overflow - assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isGreaterThan(-1) - } - - @EnableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW) - @Test - fun showOverflow_true() { - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubbleStackView.showOverflow(true) - } - InstrumentationRegistry.getInstrumentation().waitForIdleSync() - - val bubbleOverflow = bubbleData.overflow - assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isGreaterThan(-1) - } - - @EnableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW) - @Test - fun showOverflow_false() { - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubbleStackView.showOverflow(true) - } - InstrumentationRegistry.getInstrumentation().waitForIdleSync() - val bubbleOverflow = bubbleData.overflow - assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isGreaterThan(-1) - - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubbleStackView.showOverflow(false) - } - InstrumentationRegistry.getInstrumentation().waitForIdleSync() - - // The overflow should've been removed - assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isEqualTo(-1) - } - - @DisableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW) - @Test - fun showOverflow_ignored() { - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubbleStackView.showOverflow(false) - } - InstrumentationRegistry.getInstrumentation().waitForIdleSync() - - // showOverflow should've been ignored, so the overflow would be attached - val bubbleOverflow = bubbleData.overflow - assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isGreaterThan(-1) - } - - private fun createAndInflateChatBubble(key: String): Bubble { - val icon = Icon.createWithResource(context.resources, R.drawable.bubble_ic_overflow_button) - val shortcutInfo = ShortcutInfo.Builder(context, "fakeId").setIcon(icon).build() - val bubble = - Bubble( - key, - shortcutInfo, - /* desiredHeight= */ 6, - Resources.ID_NULL, - "title", - /* taskId= */ 0, - "locus", - /* isDismissable= */ true, - directExecutor() - ) {} - inflateBubble(bubble) - return bubble - } - - private fun createAndInflateBubble(): Bubble { - val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val icon = Icon.createWithResource(context.resources, R.drawable.bubble_ic_overflow_button) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), icon, directExecutor()) - inflateBubble(bubble) - return bubble - } - - private fun inflateBubble(bubble: Bubble) { - bubble.setInflateSynchronously(true) - bubbleData.notificationEntryUpdated(bubble, true, false) - - val semaphore = Semaphore(0) - val callback: BubbleViewInfoTask.Callback = - BubbleViewInfoTask.Callback { semaphore.release() } - bubble.inflate( - callback, - context, - expandedViewManager, - bubbleTaskViewFactory, - positioner, - bubbleStackView, - null, - iconFactory, - false - ) - - assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() - assertThat(bubble.isInflated).isTrue() - } - - private class FakeBubbleStackViewManager : BubbleStackViewManager { - - override fun onAllBubblesAnimatedOut() {} - - override fun updateWindowFlagsForBackpress(interceptBack: Boolean) {} - - override fun checkNotificationPanelExpandedState(callback: Consumer) {} - - override fun hideCurrentInputMethod() {} - } - - private class TestShellExecutor : ShellExecutor { - - override fun execute(runnable: Runnable) { - runnable.run() - } - - override fun executeDelayed(r: Runnable, delayMillis: Long) { - r.run() - } - - override fun removeCallbacks(r: Runnable?) {} - - override fun hasCallback(r: Runnable): Boolean = false - } - - private inner class FakeBubbleTaskViewFactory : BubbleTaskViewFactory { - override fun create(): BubbleTaskView { - val taskViewTaskController = mock() - val taskView = TaskView(context, taskViewTaskController) - return BubbleTaskView(taskView, shellExecutor) - } - } - - private inner class FakeBubbleExpandedViewManager : BubbleExpandedViewManager { - - override val overflowBubbles: List - get() = emptyList() - - override fun setOverflowListener(listener: BubbleData.Listener) {} - - override fun collapseStack() {} - - override fun updateWindowFlagsForBackpress(intercept: Boolean) {} - - override fun promoteBubbleFromOverflow(bubble: Bubble) {} - - override fun removeBubble(key: String, reason: Int) {} - - override fun dismissBubble(bubble: Bubble, reason: Int) {} - - override fun setAppBubbleTaskId(key: String, taskId: Int) {} - - override fun isStackExpanded(): Boolean = false - - override fun isShowingAsBubbleBar(): Boolean = false - - override fun hideCurrentInputMethod() {} - } -} diff --git a/wmshell/multivalentTestsForDevice/src/com/android/wm/shell/bubbles/BubbleTaskViewTest.kt b/wmshell/multivalentTestsForDevice/src/com/android/wm/shell/bubbles/BubbleTaskViewTest.kt deleted file mode 100644 index 398fd554f0..0000000000 --- a/wmshell/multivalentTestsForDevice/src/com/android/wm/shell/bubbles/BubbleTaskViewTest.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2024 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.content.ComponentName -import android.content.Context -import androidx.test.core.app.ApplicationProvider -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.android.wm.shell.taskview.TaskView - -import com.google.common.truth.Truth.assertThat -import com.google.common.util.concurrent.MoreExecutors.directExecutor -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.kotlin.mock -import org.mockito.kotlin.never -import org.mockito.kotlin.verify - -@SmallTest -@RunWith(AndroidJUnit4::class) -class BubbleTaskViewTest { - - private lateinit var bubbleTaskView: BubbleTaskView - private val context = ApplicationProvider.getApplicationContext() - private lateinit var taskView: TaskView - - @Before - fun setUp() { - taskView = mock() - bubbleTaskView = BubbleTaskView(taskView, directExecutor()) - } - - @Test - fun onTaskCreated_updatesState() { - val componentName = ComponentName(context, "TestClass") - bubbleTaskView.listener.onTaskCreated(123, componentName) - - assertThat(bubbleTaskView.taskId).isEqualTo(123) - assertThat(bubbleTaskView.componentName).isEqualTo(componentName) - assertThat(bubbleTaskView.isCreated).isTrue() - } - - @Test - fun onTaskCreated_callsDelegateListener() { - var actualTaskId = -1 - var actualComponentName: ComponentName? = null - val delegateListener = object : TaskView.Listener { - override fun onTaskCreated(taskId: Int, name: ComponentName) { - actualTaskId = taskId - actualComponentName = name - } - } - bubbleTaskView.delegateListener = delegateListener - - val componentName = ComponentName(context, "TestClass") - bubbleTaskView.listener.onTaskCreated(123, componentName) - - assertThat(actualTaskId).isEqualTo(123) - assertThat(actualComponentName).isEqualTo(componentName) - } - - @Test - fun cleanup_invalidTaskId_doesNotRemoveTask() { - bubbleTaskView.cleanup() - verify(taskView, never()).removeTask() - } - - @Test - fun cleanup_validTaskId_removesTask() { - val componentName = ComponentName(context, "TestClass") - bubbleTaskView.listener.onTaskCreated(123, componentName) - - bubbleTaskView.cleanup() - verify(taskView).removeTask() - } -} diff --git a/wmshell/multivalentTestsForDevice/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt b/wmshell/multivalentTestsForDevice/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt deleted file mode 100644 index ace2c13105..0000000000 --- a/wmshell/multivalentTestsForDevice/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Copyright (C) 2024 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.bar - -import android.content.Context -import android.graphics.Insets -import android.graphics.PointF -import android.graphics.Rect -import android.view.View -import android.view.WindowManager -import android.widget.FrameLayout -import androidx.core.animation.AnimatorTestRule -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.common.ProtoLog -import com.android.wm.shell.R -import com.android.wm.shell.bubbles.BubblePositioner -import com.android.wm.shell.bubbles.DeviceConfig -import com.android.wm.shell.common.bubbles.BaseBubblePinController -import com.android.wm.shell.common.bubbles.BaseBubblePinController.Companion.DROP_TARGET_ALPHA_IN_DURATION -import com.android.wm.shell.common.bubbles.BaseBubblePinController.Companion.DROP_TARGET_ALPHA_OUT_DURATION -import com.android.wm.shell.common.bubbles.BubbleBarLocation -import com.android.wm.shell.common.bubbles.BubbleBarLocation.LEFT -import com.android.wm.shell.common.bubbles.BubbleBarLocation.RIGHT -import com.google.common.truth.Truth.assertThat -import org.junit.After -import org.junit.Before -import org.junit.ClassRule -import org.junit.Test -import org.junit.runner.RunWith - -/** Tests for [BubbleExpandedViewPinController] */ -@SmallTest -@RunWith(AndroidJUnit4::class) -class BubbleExpandedViewPinControllerTest { - - companion object { - @JvmField @ClassRule val animatorTestRule: AnimatorTestRule = AnimatorTestRule() - - const val SCREEN_WIDTH = 2000 - const val SCREEN_HEIGHT = 1000 - - const val BUBBLE_BAR_HEIGHT = 50 - } - - private val context = ApplicationProvider.getApplicationContext() - private lateinit var positioner: BubblePositioner - private lateinit var container: FrameLayout - - private lateinit var controller: BubbleExpandedViewPinController - private lateinit var testListener: TestLocationChangeListener - - private val dropTargetView: View? - get() = container.findViewById(R.id.bubble_bar_drop_target) - - private val pointOnLeft = PointF(100f, 100f) - private val pointOnRight = PointF(1900f, 500f) - - @Before - fun setUp() { - ProtoLog.REQUIRE_PROTOLOGTOOL = false - container = FrameLayout(context) - val windowManager = context.getSystemService(WindowManager::class.java) - positioner = BubblePositioner(context, windowManager) - positioner.setShowingInBubbleBar(true) - val deviceConfig = - DeviceConfig( - windowBounds = Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), - isLargeScreen = true, - isSmallTablet = false, - isLandscape = true, - isRtl = false, - insets = Insets.of(10, 20, 30, 40) - ) - positioner.update(deviceConfig) - positioner.bubbleBarTopOnScreen = - SCREEN_HEIGHT - deviceConfig.insets.bottom - BUBBLE_BAR_HEIGHT - controller = BubbleExpandedViewPinController(context, container, positioner) - testListener = TestLocationChangeListener() - controller.setListener(testListener) - } - - @After - fun tearDown() { - getInstrumentation().runOnMainSync { controller.onDragEnd() } - waitForAnimateOut() - } - - /** Dragging on same side should not show drop target or trigger location changes */ - @Test - fun drag_stayOnRightSide() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = false) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - controller.onDragEnd() - } - waitForAnimateIn() - assertThat(dropTargetView).isNull() - assertThat(testListener.locationChanges).isEmpty() - assertThat(testListener.locationReleases).containsExactly(RIGHT) - } - - /** Dragging on same side should not show drop target or trigger location changes */ - @Test - fun drag_stayOnLeftSide() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = true) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - controller.onDragEnd() - } - waitForAnimateIn() - assertThat(dropTargetView).isNull() - assertThat(testListener.locationChanges).isEmpty() - assertThat(testListener.locationReleases).containsExactly(LEFT) - } - - /** Drag crosses to the other side. Show drop target and trigger a location change. */ - @Test - fun drag_rightToLeft() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = false) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - } - waitForAnimateIn() - - assertThat(dropTargetView).isNotNull() - assertThat(dropTargetView!!.alpha).isEqualTo(1f) - assertThat(dropTargetView!!.bounds()).isEqualTo(getExpectedDropTargetBoundsOnLeft()) - assertThat(testListener.locationChanges).containsExactly(LEFT) - assertThat(testListener.locationReleases).isEmpty() - } - - /** Drag crosses to the other side. Show drop target and trigger a location change. */ - @Test - fun drag_leftToRight() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = true) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - } - waitForAnimateIn() - - assertThat(dropTargetView).isNotNull() - assertThat(dropTargetView!!.alpha).isEqualTo(1f) - assertThat(dropTargetView!!.bounds()).isEqualTo(getExpectedDropTargetBoundsOnRight()) - assertThat(testListener.locationChanges).containsExactly(RIGHT) - assertThat(testListener.locationReleases).isEmpty() - } - - /** - * Drop target does not initially show on the side that the drag starts. Check that it shows up - * after the dragging the view to other side and back to the initial side. - */ - @Test - fun drag_rightToLeftToRight() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = false) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNull() - - getInstrumentation().runOnMainSync { controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) } - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - - getInstrumentation().runOnMainSync { - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - } - waitForAnimateOut() - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - assertThat(dropTargetView!!.alpha).isEqualTo(1f) - assertThat(dropTargetView!!.bounds()).isEqualTo(getExpectedDropTargetBoundsOnRight()) - assertThat(testListener.locationChanges).containsExactly(LEFT, RIGHT).inOrder() - assertThat(testListener.locationReleases).isEmpty() - } - - /** - * Drop target does not initially show on the side that the drag starts. Check that it shows up - * after the dragging the view to other side and back to the initial side. - */ - @Test - fun drag_leftToRightToLeft() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = true) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNull() - - getInstrumentation().runOnMainSync { - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - - getInstrumentation().runOnMainSync { controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) } - waitForAnimateOut() - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - assertThat(dropTargetView!!.alpha).isEqualTo(1f) - assertThat(dropTargetView!!.bounds()).isEqualTo(getExpectedDropTargetBoundsOnLeft()) - assertThat(testListener.locationChanges).containsExactly(RIGHT, LEFT).inOrder() - assertThat(testListener.locationReleases).isEmpty() - } - - /** - * Drag from right to left, but stay in exclusion rect around the dismiss view. Drop target - * should not show and location change should not trigger. - */ - @Test - fun drag_rightToLeft_inExclusionRect() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = false) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - // Exclusion rect is around the bottom center area of the screen - controller.onDragUpdate(SCREEN_WIDTH / 2f - 50, SCREEN_HEIGHT - 100f) - } - waitForAnimateIn() - assertThat(dropTargetView).isNull() - assertThat(testListener.locationChanges).isEmpty() - assertThat(testListener.locationReleases).isEmpty() - } - - /** - * Drag from left to right, but stay in exclusion rect around the dismiss view. Drop target - * should not show and location change should not trigger. - */ - @Test - fun drag_leftToRight_inExclusionRect() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = true) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - // Exclusion rect is around the bottom center area of the screen - controller.onDragUpdate(SCREEN_WIDTH / 2f + 50, SCREEN_HEIGHT - 100f) - } - waitForAnimateIn() - assertThat(dropTargetView).isNull() - assertThat(testListener.locationChanges).isEmpty() - assertThat(testListener.locationReleases).isEmpty() - } - - /** - * Drag to dismiss target and back to the same side should not cause the drop target to show. - */ - @Test - fun drag_rightToDismissToRight() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = false) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - controller.onStuckToDismissTarget() - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNull() - assertThat(testListener.locationChanges).isEmpty() - assertThat(testListener.locationReleases).isEmpty() - } - - /** - * Drag to dismiss target and back to the same side should not cause the drop target to show. - */ - @Test - fun drag_leftToDismissToLeft() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = true) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - controller.onStuckToDismissTarget() - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNull() - assertThat(testListener.locationChanges).isEmpty() - assertThat(testListener.locationReleases).isEmpty() - } - - /** Drag to dismiss target and other side should show drop target on the other side. */ - @Test - fun drag_rightToDismissToLeft() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = false) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - controller.onStuckToDismissTarget() - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - assertThat(dropTargetView!!.alpha).isEqualTo(1f) - assertThat(dropTargetView!!.bounds()).isEqualTo(getExpectedDropTargetBoundsOnLeft()) - - assertThat(testListener.locationChanges).containsExactly(LEFT) - assertThat(testListener.locationReleases).isEmpty() - } - - /** Drag to dismiss target and other side should show drop target on the other side. */ - @Test - fun drag_leftToDismissToRight() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = true) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - controller.onStuckToDismissTarget() - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - assertThat(dropTargetView!!.alpha).isEqualTo(1f) - assertThat(dropTargetView!!.bounds()).isEqualTo(getExpectedDropTargetBoundsOnRight()) - - assertThat(testListener.locationChanges).containsExactly(RIGHT) - assertThat(testListener.locationReleases).isEmpty() - } - - /** - * Drag to dismiss should trigger a location change to the initial location, if the current - * location is different. And hide the drop target. - */ - @Test - fun drag_rightToLeftToDismiss() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = false) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - assertThat(dropTargetView!!.alpha).isEqualTo(1f) - - getInstrumentation().runOnMainSync { controller.onStuckToDismissTarget() } - waitForAnimateOut() - assertThat(dropTargetView!!.alpha).isEqualTo(0f) - - assertThat(testListener.locationChanges).containsExactly(LEFT, RIGHT).inOrder() - assertThat(testListener.locationReleases).isEmpty() - } - - /** - * Drag to dismiss should trigger a location change to the initial location, if the current - * location is different. And hide the drop target. - */ - @Test - fun drag_leftToRightToDismiss() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = true) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - assertThat(dropTargetView!!.alpha).isEqualTo(1f) - getInstrumentation().runOnMainSync { controller.onStuckToDismissTarget() } - waitForAnimateOut() - assertThat(dropTargetView!!.alpha).isEqualTo(0f) - assertThat(testListener.locationChanges).containsExactly(RIGHT, LEFT).inOrder() - assertThat(testListener.locationReleases).isEmpty() - } - - /** Finishing drag should remove drop target and send location update. */ - @Test - fun drag_rightToLeftRelease() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = false) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - - getInstrumentation().runOnMainSync { controller.onDragEnd() } - waitForAnimateOut() - assertThat(dropTargetView).isNull() - assertThat(testListener.locationChanges).containsExactly(LEFT) - assertThat(testListener.locationReleases).containsExactly(LEFT) - } - - /** Finishing drag should remove drop target and send location update. */ - @Test - fun drag_leftToRightRelease() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = true) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - - getInstrumentation().runOnMainSync { controller.onDragEnd() } - waitForAnimateOut() - assertThat(dropTargetView).isNull() - assertThat(testListener.locationChanges).containsExactly(RIGHT) - assertThat(testListener.locationReleases).containsExactly(RIGHT) - } - - private fun getExpectedDropTargetBoundsOnLeft(): Rect = - Rect().also { - positioner.getBubbleBarExpandedViewBounds( - true /* onLeft */, - false /* isOverflowExpanded */, - it - ) - } - - private fun getExpectedDropTargetBoundsOnRight(): Rect = - Rect().also { - positioner.getBubbleBarExpandedViewBounds( - false /* onLeft */, - false /* isOverflowExpanded */, - it - ) - } - - private fun waitForAnimateIn() { - // Advance animator for on-device test - getInstrumentation().runOnMainSync { - animatorTestRule.advanceTimeBy(DROP_TARGET_ALPHA_IN_DURATION) - } - } - - private fun waitForAnimateOut() { - // Advance animator for on-device test - getInstrumentation().runOnMainSync { - animatorTestRule.advanceTimeBy(DROP_TARGET_ALPHA_OUT_DURATION) - } - } - - private fun View.bounds(): Rect { - return Rect(0, 0, layoutParams.width, layoutParams.height).also { rect -> - rect.offsetTo(x.toInt(), y.toInt()) - } - } - - internal class TestLocationChangeListener : BaseBubblePinController.LocationChangeListener { - val locationChanges = mutableListOf() - val locationReleases = mutableListOf() - override fun onChange(location: BubbleBarLocation) { - locationChanges.add(location) - } - - override fun onRelease(location: BubbleBarLocation) { - locationReleases.add(location) - } - } -} diff --git a/wmshell/multivalentTestsForDeviceless/Android.bp b/wmshell/multivalentTestsForDeviceless/Android.bp deleted file mode 100644 index 1ad19c9f30..0000000000 --- a/wmshell/multivalentTestsForDeviceless/Android.bp +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (C) 2019 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 { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "frameworks_base_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["frameworks_base_license"], - default_team: "trendy_team_multitasking_windowing", -} - -android_app { - name: "WindowManagerShellRobolectric", - platform_apis: true, - static_libs: [ - "WindowManager-Shell", - ], - manifest: "AndroidManifestRobolectric.xml", - use_resource_processor: true, -} - -android_robolectric_test { - name: "WMShellRobolectricTests", - instrumentation_for: "WindowManagerShellRobolectric", - upstream: true, - java_resource_dirs: [ - "robolectric/config", - ], - srcs: [ - "src/**/*.kt", - ], - // TODO(b/323188766): Include BubbleStackViewTest once the robolectric issue is fixed. - exclude_srcs: ["src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt"], - static_libs: [ - "junit", - "androidx.core_core-animation-testing", - "androidx.test.runner", - "androidx.test.rules", - "androidx.test.ext.junit", - "mockito-robolectric-prebuilt", - "mockito-kotlin2", - "truth", - ], - auto_gen_config: true, -} - -android_test { - name: "WMShellMultivalentTestsOnDevice", - srcs: [ - "src/**/*.kt", - ], - static_libs: [ - "WindowManager-Shell", - "junit", - "androidx.core_core-animation-testing", - "androidx.test.runner", - "androidx.test.rules", - "androidx.test.ext.junit", - "frameworks-base-testutils", - "mockito-kotlin2", - "mockito-target-extended-minus-junit4", - "truth", - "platform-test-annotations", - "platform-test-rules", - ], - libs: [ - "android.test.base", - "android.test.runner", - ], - jni_libs: [ - "libdexmakerjvmtiagent", - "libstaticjvmtiagent", - ], - kotlincflags: ["-Xjvm-default=all"], - optimize: { - enabled: false, - }, - test_suites: ["device-tests"], - platform_apis: true, - certificate: "platform", - aaptflags: [ - "--extra-packages", - "com.android.wm.shell", - ], - manifest: "AndroidManifest.xml", -} diff --git a/wmshell/multivalentTestsForDeviceless/AndroidManifest.xml b/wmshell/multivalentTestsForDeviceless/AndroidManifest.xml deleted file mode 100644 index f8f8338e5f..0000000000 --- a/wmshell/multivalentTestsForDeviceless/AndroidManifest.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - diff --git a/wmshell/multivalentTestsForDeviceless/AndroidManifestRobolectric.xml b/wmshell/multivalentTestsForDeviceless/AndroidManifestRobolectric.xml deleted file mode 100644 index ffcd7d46fb..0000000000 --- a/wmshell/multivalentTestsForDeviceless/AndroidManifestRobolectric.xml +++ /dev/null @@ -1,3 +0,0 @@ - - diff --git a/wmshell/multivalentTestsForDeviceless/AndroidTest.xml b/wmshell/multivalentTestsForDeviceless/AndroidTest.xml deleted file mode 100644 index 36fe8ec337..0000000000 --- a/wmshell/multivalentTestsForDeviceless/AndroidTest.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - diff --git a/wmshell/multivalentTestsForDeviceless/OWNERS b/wmshell/multivalentTestsForDeviceless/OWNERS deleted file mode 100644 index 24c1a3a6d4..0000000000 --- a/wmshell/multivalentTestsForDeviceless/OWNERS +++ /dev/null @@ -1,4 +0,0 @@ -atsjenk@google.com -liranb@google.com -madym@google.com - diff --git a/wmshell/multivalentTestsForDeviceless/robolectric/config/robolectric.properties b/wmshell/multivalentTestsForDeviceless/robolectric/config/robolectric.properties deleted file mode 100644 index 7a0527ccaa..0000000000 --- a/wmshell/multivalentTestsForDeviceless/robolectric/config/robolectric.properties +++ /dev/null @@ -1,2 +0,0 @@ -sdk=NEWEST_SDK - diff --git a/wmshell/multivalentTestsForDeviceless/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt b/wmshell/multivalentTestsForDeviceless/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt deleted file mode 100644 index 9e1440d571..0000000000 --- a/wmshell/multivalentTestsForDeviceless/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt +++ /dev/null @@ -1,670 +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 android.content.Context -import android.content.Intent -import android.content.pm.ShortcutInfo -import android.content.res.Resources -import android.graphics.Insets -import android.graphics.PointF -import android.graphics.Rect -import android.os.UserHandle -import android.view.WindowManager -import androidx.test.core.app.ApplicationProvider -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.android.internal.protolog.common.ProtoLog -import com.android.wm.shell.R -import com.android.wm.shell.bubbles.BubblePositioner.MAX_HEIGHT -import com.android.wm.shell.common.bubbles.BubbleBarLocation -import com.google.common.truth.Truth.assertThat -import com.google.common.util.concurrent.MoreExecutors.directExecutor -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith - -/** Tests operations and the resulting state managed by [BubblePositioner]. */ -@SmallTest -@RunWith(AndroidJUnit4::class) -class BubblePositionerTest { - - private lateinit var positioner: BubblePositioner - private val context = ApplicationProvider.getApplicationContext() - private val resources: Resources - get() = context.resources - - private val defaultDeviceConfig = - DeviceConfig( - windowBounds = Rect(0, 0, 1000, 2000), - isLargeScreen = false, - isSmallTablet = false, - isLandscape = false, - isRtl = false, - insets = Insets.of(0, 0, 0, 0) - ) - - @Before - fun setUp() { - ProtoLog.REQUIRE_PROTOLOGTOOL = false - val windowManager = context.getSystemService(WindowManager::class.java) - positioner = BubblePositioner(context, windowManager) - } - - @Test - fun testUpdate() { - val insets = Insets.of(10, 20, 5, 15) - val screenBounds = Rect(0, 0, 1000, 1200) - val availableRect = Rect(screenBounds) - availableRect.inset(insets) - positioner.update(defaultDeviceConfig.copy(insets = insets, windowBounds = screenBounds)) - assertThat(positioner.availableRect).isEqualTo(availableRect) - assertThat(positioner.isLandscape).isFalse() - assertThat(positioner.isLargeScreen).isFalse() - assertThat(positioner.insets).isEqualTo(insets) - } - - @Test - fun testShowBubblesVertically_phonePortrait() { - positioner.update(defaultDeviceConfig) - assertThat(positioner.showBubblesVertically()).isFalse() - } - - @Test - fun testShowBubblesVertically_phoneLandscape() { - positioner.update(defaultDeviceConfig.copy(isLandscape = true)) - assertThat(positioner.isLandscape).isTrue() - assertThat(positioner.showBubblesVertically()).isTrue() - } - - @Test - fun testShowBubblesVertically_tablet() { - positioner.update(defaultDeviceConfig.copy(isLargeScreen = true)) - assertThat(positioner.showBubblesVertically()).isTrue() - } - - /** If a resting position hasn't been set, calling it will return the default position. */ - @Test - fun testGetRestingPosition_returnsDefaultPosition() { - positioner.update(defaultDeviceConfig) - val restingPosition = positioner.getRestingPosition() - val defaultPosition = positioner.defaultStartPosition - assertThat(restingPosition).isEqualTo(defaultPosition) - } - - /** If a resting position has been set, it'll return that instead of the default position. */ - @Test - fun testGetRestingPosition_returnsRestingPosition() { - positioner.update(defaultDeviceConfig) - val restingPosition = PointF(100f, 100f) - positioner.restingPosition = restingPosition - assertThat(positioner.getRestingPosition()).isEqualTo(restingPosition) - } - - /** Test that the default resting position on phone is in upper left. */ - @Test - fun testGetRestingPosition_bubble_onPhone() { - positioner.update(defaultDeviceConfig) - val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - val restingPosition = positioner.getRestingPosition() - assertThat(restingPosition.x).isEqualTo(allowableStackRegion.left) - assertThat(restingPosition.y).isEqualTo(defaultYPosition) - } - - @Test - fun testGetRestingPosition_bubble_onPhone_RTL() { - positioner.update(defaultDeviceConfig.copy(isRtl = true)) - val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - val restingPosition = positioner.getRestingPosition() - assertThat(restingPosition.x).isEqualTo(allowableStackRegion.right) - assertThat(restingPosition.y).isEqualTo(defaultYPosition) - } - - /** Test that the default resting position on tablet is middle left. */ - @Test - fun testGetRestingPosition_chatBubble_onTablet() { - positioner.update(defaultDeviceConfig.copy(isLargeScreen = true)) - val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - val restingPosition = positioner.getRestingPosition() - assertThat(restingPosition.x).isEqualTo(allowableStackRegion.left) - assertThat(restingPosition.y).isEqualTo(defaultYPosition) - } - - @Test - fun testGetRestingPosition_chatBubble_onTablet_RTL() { - positioner.update(defaultDeviceConfig.copy(isLargeScreen = true, isRtl = true)) - val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - val restingPosition = positioner.getRestingPosition() - assertThat(restingPosition.x).isEqualTo(allowableStackRegion.right) - assertThat(restingPosition.y).isEqualTo(defaultYPosition) - } - - /** Test that the default resting position on tablet is middle right. */ - @Test - fun testGetDefaultPosition_appBubble_onTablet() { - positioner.update(defaultDeviceConfig.copy(isLargeScreen = true)) - val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - val startPosition = positioner.getDefaultStartPosition(true /* isAppBubble */) - assertThat(startPosition.x).isEqualTo(allowableStackRegion.right) - assertThat(startPosition.y).isEqualTo(defaultYPosition) - } - - @Test - fun testGetRestingPosition_appBubble_onTablet_RTL() { - positioner.update(defaultDeviceConfig.copy(isLargeScreen = true, isRtl = true)) - val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - val startPosition = positioner.getDefaultStartPosition(true /* isAppBubble */) - assertThat(startPosition.x).isEqualTo(allowableStackRegion.left) - assertThat(startPosition.y).isEqualTo(defaultYPosition) - } - - @Test - fun testGetRestingPosition_afterBoundsChange() { - positioner.update( - defaultDeviceConfig.copy(isLargeScreen = true, windowBounds = Rect(0, 0, 2000, 1600)) - ) - - // Set the resting position to the right side - var allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - val restingPosition = PointF(allowableStackRegion.right, allowableStackRegion.centerY()) - positioner.restingPosition = restingPosition - - // Now make the device smaller - positioner.update( - defaultDeviceConfig.copy(isLargeScreen = false, windowBounds = Rect(0, 0, 1000, 1600)) - ) - - // Check the resting position is on the correct side - allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - assertThat(positioner.restingPosition.x).isEqualTo(allowableStackRegion.right) - } - - @Test - fun testHasUserModifiedDefaultPosition_false() { - positioner.update(defaultDeviceConfig.copy(isLargeScreen = true, isRtl = true)) - assertThat(positioner.hasUserModifiedDefaultPosition()).isFalse() - positioner.restingPosition = positioner.defaultStartPosition - assertThat(positioner.hasUserModifiedDefaultPosition()).isFalse() - } - - @Test - fun testHasUserModifiedDefaultPosition_true() { - positioner.update(defaultDeviceConfig.copy(isLargeScreen = true, isRtl = true)) - assertThat(positioner.hasUserModifiedDefaultPosition()).isFalse() - positioner.restingPosition = PointF(0f, 100f) - assertThat(positioner.hasUserModifiedDefaultPosition()).isTrue() - } - - @Test - fun testBubbleBarExpandedViewHeightAndWidth() { - val deviceConfig = - defaultDeviceConfig.copy( - // portrait orientation - isLandscape = false, - isLargeScreen = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - - positioner.setShowingInBubbleBar(true) - positioner.update(deviceConfig) - positioner.bubbleBarTopOnScreen = 2500 - - val spaceBetweenTopInsetAndBubbleBarInLandscape = 1680 - val expandedViewVerticalSpacing = - resources.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding) - val expectedHeight = - spaceBetweenTopInsetAndBubbleBarInLandscape - 2 * expandedViewVerticalSpacing - val expectedWidth = resources.getDimensionPixelSize(R.dimen.bubble_bar_expanded_view_width) - - assertThat(positioner.getExpandedViewWidthForBubbleBar(false)).isEqualTo(expectedWidth) - assertThat(positioner.getExpandedViewHeightForBubbleBar(false)).isEqualTo(expectedHeight) - } - - @Test - fun testBubbleBarExpandedViewHeightAndWidth_screenWidthTooSmall() { - val screenWidth = 300 - val deviceConfig = - defaultDeviceConfig.copy( - // portrait orientation - isLandscape = false, - isLargeScreen = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, screenWidth, 2600) - ) - positioner.setShowingInBubbleBar(true) - positioner.update(deviceConfig) - positioner.bubbleBarTopOnScreen = 2500 - - val spaceBetweenTopInsetAndBubbleBarInLandscape = 180 - val expandedViewSpacing = - resources.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding) - val expectedHeight = spaceBetweenTopInsetAndBubbleBarInLandscape - 2 * expandedViewSpacing - val expectedWidth = screenWidth - 15 /* horizontal insets */ - 2 * expandedViewSpacing - assertThat(positioner.getExpandedViewWidthForBubbleBar(false)).isEqualTo(expectedWidth) - assertThat(positioner.getExpandedViewHeightForBubbleBar(false)).isEqualTo(expectedHeight) - } - - @Test - fun testGetExpandedViewHeight_max() { - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) - - assertThat(positioner.getExpandedViewHeight(bubble)).isEqualTo(MAX_HEIGHT) - } - - @Test - fun testGetExpandedViewHeight_customHeight_valid() { - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - val minHeight = - context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_default_height) - val bubble = - Bubble( - "key", - ShortcutInfo.Builder(context, "id").build(), - minHeight + 100 /* desiredHeight */, - 0 /* desiredHeightResId */, - "title", - 0 /* taskId */, - null /* locus */, - true /* isDismissable */, - directExecutor() - ) {} - - // Ensure the height is the same as the desired value - assertThat(positioner.getExpandedViewHeight(bubble)) - .isEqualTo(bubble.getDesiredHeight(context)) - } - - @Test - fun testGetExpandedViewHeight_customHeight_tooSmall() { - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - val bubble = - Bubble( - "key", - ShortcutInfo.Builder(context, "id").build(), - 10 /* desiredHeight */, - 0 /* desiredHeightResId */, - "title", - 0 /* taskId */, - null /* locus */, - true /* isDismissable */, - directExecutor() - ) {} - - // Ensure the height is the same as the desired value - val minHeight = - context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_default_height) - assertThat(positioner.getExpandedViewHeight(bubble)).isEqualTo(minHeight) - } - - @Test - fun testGetMaxExpandedViewHeight_onLargeTablet() { - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - val manageButtonHeight = - context.resources.getDimensionPixelSize(R.dimen.bubble_manage_button_height) - val pointerWidth = context.resources.getDimensionPixelSize(R.dimen.bubble_pointer_width) - val expandedViewPadding = - context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding) - val expectedHeight = - 1800 - 2 * 20 - manageButtonHeight - pointerWidth - expandedViewPadding * 2 - assertThat(positioner.getMaxExpandedViewHeight(false /* isOverflow */)) - .isEqualTo(expectedHeight) - } - - @Test - fun testAreBubblesBottomAligned_largeScreen_true() { - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - assertThat(positioner.areBubblesBottomAligned()).isTrue() - } - - @Test - fun testAreBubblesBottomAligned_largeScreen_landscape_false() { - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - isLandscape = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - assertThat(positioner.areBubblesBottomAligned()).isFalse() - } - - @Test - fun testAreBubblesBottomAligned_smallTablet_false() { - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - isSmallTablet = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - assertThat(positioner.areBubblesBottomAligned()).isFalse() - } - - @Test - fun testAreBubblesBottomAligned_phone_false() { - val deviceConfig = - defaultDeviceConfig.copy( - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - assertThat(positioner.areBubblesBottomAligned()).isFalse() - } - - @Test - fun testExpandedViewY_phoneLandscape() { - val deviceConfig = - defaultDeviceConfig.copy( - isLandscape = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) - - // This bubble will have max height so it'll always be top aligned - assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) - .isEqualTo(positioner.getExpandedViewYTopAligned()) - } - - @Test - fun testExpandedViewY_phonePortrait() { - val deviceConfig = - defaultDeviceConfig.copy( - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) - - // Always top aligned in phone portrait - assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) - .isEqualTo(positioner.getExpandedViewYTopAligned()) - } - - @Test - fun testExpandedViewY_smallTabletLandscape() { - val deviceConfig = - defaultDeviceConfig.copy( - isSmallTablet = true, - isLandscape = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) - - // This bubble will have max height which is always top aligned on small tablets - assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) - .isEqualTo(positioner.getExpandedViewYTopAligned()) - } - - @Test - fun testExpandedViewY_smallTabletPortrait() { - val deviceConfig = - defaultDeviceConfig.copy( - isSmallTablet = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) - - // This bubble will have max height which is always top aligned on small tablets - assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) - .isEqualTo(positioner.getExpandedViewYTopAligned()) - } - - @Test - fun testExpandedViewY_largeScreenLandscape() { - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - isLandscape = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) - - // This bubble will have max height which is always top aligned on landscape, large tablet - assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) - .isEqualTo(positioner.getExpandedViewYTopAligned()) - } - - @Test - fun testExpandedViewY_largeScreenPortrait() { - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - insets = Insets.of(10, 20, 5, 15), - windowBounds = Rect(0, 0, 1800, 2600) - ) - positioner.update(deviceConfig) - - val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) - - val manageButtonHeight = - context.resources.getDimensionPixelSize(R.dimen.bubble_manage_button_height) - val manageButtonPlusMargin = - manageButtonHeight + - 2 * context.resources.getDimensionPixelSize(R.dimen.bubble_manage_button_margin) - val pointerWidth = context.resources.getDimensionPixelSize(R.dimen.bubble_pointer_width) - - val expectedExpandedViewY = - positioner.availableRect.bottom - - manageButtonPlusMargin - - positioner.getExpandedViewHeightForLargeScreen() - - pointerWidth - - // Bubbles are bottom aligned on portrait, large tablet - assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) - .isEqualTo(expectedExpandedViewY) - } - - @Test - fun testGetTaskViewContentWidth_onLeft() { - positioner.update(defaultDeviceConfig.copy(insets = Insets.of(100, 0, 200, 0))) - val taskViewWidth = positioner.getTaskViewContentWidth(true /* onLeft */) - val paddings = - positioner.getExpandedViewContainerPadding(true /* onLeft */, false /* isOverflow */) - assertThat(taskViewWidth) - .isEqualTo(positioner.screenRect.width() - paddings[0] - paddings[2]) - } - - @Test - fun testGetTaskViewContentWidth_onRight() { - positioner.update(defaultDeviceConfig.copy(insets = Insets.of(100, 0, 200, 0))) - val taskViewWidth = positioner.getTaskViewContentWidth(false /* onLeft */) - val paddings = - positioner.getExpandedViewContainerPadding(false /* onLeft */, false /* isOverflow */) - assertThat(taskViewWidth) - .isEqualTo(positioner.screenRect.width() - paddings[0] - paddings[2]) - } - - @Test - fun testIsBubbleBarOnLeft_defaultsToRight() { - positioner.bubbleBarLocation = BubbleBarLocation.DEFAULT - assertThat(positioner.isBubbleBarOnLeft).isFalse() - - // Check that left and right return expected position - positioner.bubbleBarLocation = BubbleBarLocation.LEFT - assertThat(positioner.isBubbleBarOnLeft).isTrue() - positioner.bubbleBarLocation = BubbleBarLocation.RIGHT - assertThat(positioner.isBubbleBarOnLeft).isFalse() - } - - @Test - fun testIsBubbleBarOnLeft_rtlEnabled_defaultsToLeft() { - positioner.update(defaultDeviceConfig.copy(isRtl = true)) - - positioner.bubbleBarLocation = BubbleBarLocation.DEFAULT - assertThat(positioner.isBubbleBarOnLeft).isTrue() - - // Check that left and right return expected position - positioner.bubbleBarLocation = BubbleBarLocation.LEFT - assertThat(positioner.isBubbleBarOnLeft).isTrue() - positioner.bubbleBarLocation = BubbleBarLocation.RIGHT - assertThat(positioner.isBubbleBarOnLeft).isFalse() - } - - @Test - fun testGetBubbleBarExpandedViewBounds_onLeft() { - testGetBubbleBarExpandedViewBounds(onLeft = true, isOverflow = false) - } - - @Test - fun testGetBubbleBarExpandedViewBounds_onRight() { - testGetBubbleBarExpandedViewBounds(onLeft = false, isOverflow = false) - } - - @Test - fun testGetBubbleBarExpandedViewBounds_isOverflow_onLeft() { - testGetBubbleBarExpandedViewBounds(onLeft = true, isOverflow = true) - } - - @Test - fun testGetBubbleBarExpandedViewBounds_isOverflow_onRight() { - testGetBubbleBarExpandedViewBounds(onLeft = false, isOverflow = true) - } - - private fun testGetBubbleBarExpandedViewBounds(onLeft: Boolean, isOverflow: Boolean) { - positioner.setShowingInBubbleBar(true) - val windowBounds = Rect(0, 0, 2000, 2600) - val insets = Insets.of(10, 20, 5, 15) - val deviceConfig = - defaultDeviceConfig.copy( - isLargeScreen = true, - isLandscape = true, - insets = insets, - windowBounds = windowBounds - ) - positioner.update(deviceConfig) - - val bubbleBarHeight = 100 - positioner.bubbleBarTopOnScreen = windowBounds.bottom - insets.bottom - bubbleBarHeight - - val expandedViewPadding = - context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding) - - val left: Int - val right: Int - if (onLeft) { - // Pin to the left, calculate right - left = deviceConfig.insets.left + expandedViewPadding - right = left + positioner.getExpandedViewWidthForBubbleBar(isOverflow) - } else { - // Pin to the right, calculate left - right = - deviceConfig.windowBounds.right - deviceConfig.insets.right - expandedViewPadding - left = right - positioner.getExpandedViewWidthForBubbleBar(isOverflow) - } - // Above the bubble bar - val bottom = positioner.bubbleBarTopOnScreen - expandedViewPadding - // Calculate right and top based on size - val top = bottom - positioner.getExpandedViewHeightForBubbleBar(isOverflow) - val expectedBounds = Rect(left, top, right, bottom) - - val bounds = Rect() - positioner.getBubbleBarExpandedViewBounds(onLeft, isOverflow, bounds) - - assertThat(bounds).isEqualTo(expectedBounds) - } - - private val defaultYPosition: Float - /** - * Calculates the Y position bubbles should be placed based on the config. Based on the - * calculations in [BubblePositioner.getDefaultStartPosition] and - * [BubbleStackView.RelativeStackPosition]. - */ - get() { - val isTablet = positioner.isLargeScreen - - // On tablet the position is centered, on phone it is an offset from the top. - val desiredY = - if (isTablet) { - positioner.screenRect.height() / 2f - positioner.bubbleSize / 2f - } else { - context.resources - .getDimensionPixelOffset(R.dimen.bubble_stack_starting_offset_y) - .toFloat() - } - // Since we're visually centering the bubbles on tablet, use total screen height rather - // than the available height. - val height = - if (isTablet) { - positioner.screenRect.height() - } else { - positioner.availableRect.height() - } - val offsetPercent = (desiredY / height).coerceIn(0f, 1f) - val allowableStackRegion = - positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) - return allowableStackRegion.top + allowableStackRegion.height() * offsetPercent - } -} diff --git a/wmshell/multivalentTestsForDeviceless/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt b/wmshell/multivalentTestsForDeviceless/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt deleted file mode 100644 index 327e205955..0000000000 --- a/wmshell/multivalentTestsForDeviceless/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright (C) 2024 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.content.Context -import android.content.Intent -import android.content.pm.ShortcutInfo -import android.content.res.Resources -import android.graphics.Color -import android.graphics.drawable.Icon -import android.os.UserHandle -import android.platform.test.flag.junit.SetFlagsRule -import android.view.IWindowManager -import android.view.WindowManager -import android.view.WindowManagerGlobal -import androidx.test.core.app.ApplicationProvider -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import androidx.test.platform.app.InstrumentationRegistry -import com.android.internal.logging.testing.UiEventLoggerFake -import com.android.internal.protolog.common.ProtoLog -import com.android.launcher3.icons.BubbleIconFactory -import com.android.wm.shell.Flags -import com.android.wm.shell.R -import com.android.wm.shell.bubbles.Bubbles.SysuiProxy -import com.android.wm.shell.bubbles.animation.AnimatableScaleMatrix -import com.android.wm.shell.common.FloatingContentCoordinator -import com.android.wm.shell.common.ShellExecutor -import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils -import com.android.wm.shell.taskview.TaskView -import com.android.wm.shell.taskview.TaskViewTaskController -import com.google.common.truth.Truth.assertThat -import com.google.common.util.concurrent.MoreExecutors.directExecutor -import org.junit.After -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.kotlin.mock -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags -import java.util.concurrent.Semaphore -import java.util.concurrent.TimeUnit -import java.util.function.Consumer - -/** Unit tests for [BubbleStackView]. */ -@SmallTest -@RunWith(AndroidJUnit4::class) -class BubbleStackViewTest { - - @get:Rule val setFlagsRule = SetFlagsRule() - - private val context = ApplicationProvider.getApplicationContext() - private lateinit var positioner: BubblePositioner - private lateinit var iconFactory: BubbleIconFactory - private lateinit var expandedViewManager: FakeBubbleExpandedViewManager - private lateinit var bubbleStackView: BubbleStackView - private lateinit var shellExecutor: ShellExecutor - private lateinit var windowManager: IWindowManager - private lateinit var bubbleTaskViewFactory: BubbleTaskViewFactory - private lateinit var bubbleData: BubbleData - private lateinit var bubbleStackViewManager: FakeBubbleStackViewManager - private var sysuiProxy = mock() - - @Before - fun setUp() { - PhysicsAnimatorTestUtils.prepareForTest() - // Disable protolog tool when running the tests from studio - ProtoLog.REQUIRE_PROTOLOGTOOL = false - windowManager = WindowManagerGlobal.getWindowManagerService()!! - shellExecutor = TestShellExecutor() - val windowManager = context.getSystemService(WindowManager::class.java) - iconFactory = - BubbleIconFactory( - context, - context.resources.getDimensionPixelSize(R.dimen.bubble_size), - context.resources.getDimensionPixelSize(R.dimen.bubble_badge_size), - Color.BLACK, - context.resources.getDimensionPixelSize( - com.android.internal.R.dimen.importance_ring_stroke_width - ) - ) - positioner = BubblePositioner(context, windowManager) - bubbleData = - BubbleData( - context, - BubbleLogger(UiEventLoggerFake()), - positioner, - BubbleEducationController(context), - shellExecutor - ) - bubbleStackViewManager = FakeBubbleStackViewManager() - expandedViewManager = FakeBubbleExpandedViewManager() - bubbleTaskViewFactory = FakeBubbleTaskViewFactory() - bubbleStackView = - BubbleStackView( - context, - bubbleStackViewManager, - positioner, - bubbleData, - null, - FloatingContentCoordinator(), - { sysuiProxy }, - shellExecutor - ) - - context - .getSharedPreferences(context.packageName, Context.MODE_PRIVATE) - .edit() - .putBoolean(StackEducationView.PREF_STACK_EDUCATION, true) - .apply() - } - - @After - fun tearDown() { - PhysicsAnimatorTestUtils.tearDown() - } - - @Test - fun addBubble() { - val bubble = createAndInflateBubble() - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubbleStackView.addBubble(bubble) - } - InstrumentationRegistry.getInstrumentation().waitForIdleSync() - assertThat(bubbleStackView.bubbleCount).isEqualTo(1) - } - - @Test - fun tapBubbleToExpand() { - val bubble = createAndInflateBubble() - - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubbleStackView.addBubble(bubble) - } - - InstrumentationRegistry.getInstrumentation().waitForIdleSync() - assertThat(bubbleStackView.bubbleCount).isEqualTo(1) - var lastUpdate: BubbleData.Update? = null - val semaphore = Semaphore(0) - val listener = - BubbleData.Listener { update -> - lastUpdate = update - semaphore.release() - } - bubbleData.setListener(listener) - - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubble.iconView!!.performClick() - // we're checking the expanded state in BubbleData because that's the source of truth. - // This will eventually propagate an update back to the stack view, but setting the - // entire pipeline is outside the scope of a unit test. - assertThat(bubbleData.isExpanded).isTrue() - } - - assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() - assertThat(lastUpdate).isNotNull() - assertThat(lastUpdate!!.expandedChanged).isTrue() - assertThat(lastUpdate!!.expanded).isTrue() - } - - @Test - fun tapDifferentBubble_shouldReorder() { - val bubble1 = createAndInflateChatBubble(key = "bubble1") - val bubble2 = createAndInflateChatBubble(key = "bubble2") - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubbleStackView.addBubble(bubble1) - bubbleStackView.addBubble(bubble2) - } - InstrumentationRegistry.getInstrumentation().waitForIdleSync() - - assertThat(bubbleStackView.bubbleCount).isEqualTo(2) - assertThat(bubbleData.bubbles).hasSize(2) - assertThat(bubbleData.selectedBubble).isEqualTo(bubble2) - assertThat(bubble2.iconView).isNotNull() - - var lastUpdate: BubbleData.Update? = null - val semaphore = Semaphore(0) - val listener = - BubbleData.Listener { update -> - lastUpdate = update - semaphore.release() - } - bubbleData.setListener(listener) - - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubble2.iconView!!.performClick() - assertThat(bubbleData.isExpanded).isTrue() - - bubbleStackView.setSelectedBubble(bubble2) - bubbleStackView.isExpanded = true - } - - assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() - assertThat(lastUpdate!!.expanded).isTrue() - assertThat(lastUpdate!!.bubbles.map { it.key }) - .containsExactly("bubble2", "bubble1") - .inOrder() - - // wait for idle to allow the animation to start - InstrumentationRegistry.getInstrumentation().waitForIdleSync() - // wait for the expansion animation to complete before interacting with the bubbles - PhysicsAnimatorTestUtils.blockUntilAnimationsEnd( - AnimatableScaleMatrix.SCALE_X, AnimatableScaleMatrix.SCALE_Y) - - // tap on bubble1 to select it - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubble1.iconView!!.performClick() - } - assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() - assertThat(bubbleData.selectedBubble).isEqualTo(bubble1) - - // tap on bubble1 again to collapse the stack - InstrumentationRegistry.getInstrumentation().runOnMainSync { - // we have to set the selected bubble in the stack view manually because we don't have a - // listener wired up. - bubbleStackView.setSelectedBubble(bubble1) - bubble1.iconView!!.performClick() - } - - assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() - assertThat(bubbleData.selectedBubble).isEqualTo(bubble1) - assertThat(bubbleData.isExpanded).isFalse() - assertThat(lastUpdate!!.orderChanged).isTrue() - assertThat(lastUpdate!!.bubbles.map { it.key }) - .containsExactly("bubble1", "bubble2") - .inOrder() - } - - @EnableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW) - @Test - fun testCreateStackView_noOverflowContents_noOverflow() { - bubbleStackView = - BubbleStackView( - context, - bubbleStackViewManager, - positioner, - bubbleData, - null, - FloatingContentCoordinator(), - { sysuiProxy }, - shellExecutor - ) - - assertThat(bubbleData.overflowBubbles).isEmpty() - val bubbleOverflow = bubbleData.overflow - // Overflow shouldn't be attached - assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isEqualTo(-1) - } - - @EnableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW) - @Test - fun testCreateStackView_hasOverflowContents_hasOverflow() { - // Add a bubble to the overflow - val bubble1 = createAndInflateChatBubble(key = "bubble1") - bubbleData.notificationEntryUpdated(bubble1, false, false) - bubbleData.dismissBubbleWithKey(bubble1.key, Bubbles.DISMISS_USER_GESTURE) - assertThat(bubbleData.overflowBubbles).isNotEmpty() - - bubbleStackView = - BubbleStackView( - context, - bubbleStackViewManager, - positioner, - bubbleData, - null, - FloatingContentCoordinator(), - { sysuiProxy }, - shellExecutor - ) - val bubbleOverflow = bubbleData.overflow - assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isGreaterThan(-1) - } - - @DisableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW) - @Test - fun testCreateStackView_noOverflowContents_hasOverflow() { - bubbleStackView = - BubbleStackView( - context, - bubbleStackViewManager, - positioner, - bubbleData, - null, - FloatingContentCoordinator(), - { sysuiProxy }, - shellExecutor - ) - - assertThat(bubbleData.overflowBubbles).isEmpty() - val bubbleOverflow = bubbleData.overflow - assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isGreaterThan(-1) - } - - @EnableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW) - @Test - fun showOverflow_true() { - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubbleStackView.showOverflow(true) - } - InstrumentationRegistry.getInstrumentation().waitForIdleSync() - - val bubbleOverflow = bubbleData.overflow - assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isGreaterThan(-1) - } - - @EnableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW) - @Test - fun showOverflow_false() { - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubbleStackView.showOverflow(true) - } - InstrumentationRegistry.getInstrumentation().waitForIdleSync() - val bubbleOverflow = bubbleData.overflow - assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isGreaterThan(-1) - - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubbleStackView.showOverflow(false) - } - InstrumentationRegistry.getInstrumentation().waitForIdleSync() - - // The overflow should've been removed - assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isEqualTo(-1) - } - - @DisableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW) - @Test - fun showOverflow_ignored() { - InstrumentationRegistry.getInstrumentation().runOnMainSync { - bubbleStackView.showOverflow(false) - } - InstrumentationRegistry.getInstrumentation().waitForIdleSync() - - // showOverflow should've been ignored, so the overflow would be attached - val bubbleOverflow = bubbleData.overflow - assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isGreaterThan(-1) - } - - private fun createAndInflateChatBubble(key: String): Bubble { - val icon = Icon.createWithResource(context.resources, R.drawable.bubble_ic_overflow_button) - val shortcutInfo = ShortcutInfo.Builder(context, "fakeId").setIcon(icon).build() - val bubble = - Bubble( - key, - shortcutInfo, - /* desiredHeight= */ 6, - Resources.ID_NULL, - "title", - /* taskId= */ 0, - "locus", - /* isDismissable= */ true, - directExecutor() - ) {} - inflateBubble(bubble) - return bubble - } - - private fun createAndInflateBubble(): Bubble { - val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) - val icon = Icon.createWithResource(context.resources, R.drawable.bubble_ic_overflow_button) - val bubble = Bubble.createAppBubble(intent, UserHandle(1), icon, directExecutor()) - inflateBubble(bubble) - return bubble - } - - private fun inflateBubble(bubble: Bubble) { - bubble.setInflateSynchronously(true) - bubbleData.notificationEntryUpdated(bubble, true, false) - - val semaphore = Semaphore(0) - val callback: BubbleViewInfoTask.Callback = - BubbleViewInfoTask.Callback { semaphore.release() } - bubble.inflate( - callback, - context, - expandedViewManager, - bubbleTaskViewFactory, - positioner, - bubbleStackView, - null, - iconFactory, - false - ) - - assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() - assertThat(bubble.isInflated).isTrue() - } - - private class FakeBubbleStackViewManager : BubbleStackViewManager { - - override fun onAllBubblesAnimatedOut() {} - - override fun updateWindowFlagsForBackpress(interceptBack: Boolean) {} - - override fun checkNotificationPanelExpandedState(callback: Consumer) {} - - override fun hideCurrentInputMethod() {} - } - - private class TestShellExecutor : ShellExecutor { - - override fun execute(runnable: Runnable) { - runnable.run() - } - - override fun executeDelayed(r: Runnable, delayMillis: Long) { - r.run() - } - - override fun removeCallbacks(r: Runnable?) {} - - override fun hasCallback(r: Runnable): Boolean = false - } - - private inner class FakeBubbleTaskViewFactory : BubbleTaskViewFactory { - override fun create(): BubbleTaskView { - val taskViewTaskController = mock() - val taskView = TaskView(context, taskViewTaskController) - return BubbleTaskView(taskView, shellExecutor) - } - } - - private inner class FakeBubbleExpandedViewManager : BubbleExpandedViewManager { - - override val overflowBubbles: List - get() = emptyList() - - override fun setOverflowListener(listener: BubbleData.Listener) {} - - override fun collapseStack() {} - - override fun updateWindowFlagsForBackpress(intercept: Boolean) {} - - override fun promoteBubbleFromOverflow(bubble: Bubble) {} - - override fun removeBubble(key: String, reason: Int) {} - - override fun dismissBubble(bubble: Bubble, reason: Int) {} - - override fun setAppBubbleTaskId(key: String, taskId: Int) {} - - override fun isStackExpanded(): Boolean = false - - override fun isShowingAsBubbleBar(): Boolean = false - - override fun hideCurrentInputMethod() {} - } -} diff --git a/wmshell/multivalentTestsForDeviceless/src/com/android/wm/shell/bubbles/BubbleTaskViewTest.kt b/wmshell/multivalentTestsForDeviceless/src/com/android/wm/shell/bubbles/BubbleTaskViewTest.kt deleted file mode 100644 index 398fd554f0..0000000000 --- a/wmshell/multivalentTestsForDeviceless/src/com/android/wm/shell/bubbles/BubbleTaskViewTest.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2024 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.content.ComponentName -import android.content.Context -import androidx.test.core.app.ApplicationProvider -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.android.wm.shell.taskview.TaskView - -import com.google.common.truth.Truth.assertThat -import com.google.common.util.concurrent.MoreExecutors.directExecutor -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.kotlin.mock -import org.mockito.kotlin.never -import org.mockito.kotlin.verify - -@SmallTest -@RunWith(AndroidJUnit4::class) -class BubbleTaskViewTest { - - private lateinit var bubbleTaskView: BubbleTaskView - private val context = ApplicationProvider.getApplicationContext() - private lateinit var taskView: TaskView - - @Before - fun setUp() { - taskView = mock() - bubbleTaskView = BubbleTaskView(taskView, directExecutor()) - } - - @Test - fun onTaskCreated_updatesState() { - val componentName = ComponentName(context, "TestClass") - bubbleTaskView.listener.onTaskCreated(123, componentName) - - assertThat(bubbleTaskView.taskId).isEqualTo(123) - assertThat(bubbleTaskView.componentName).isEqualTo(componentName) - assertThat(bubbleTaskView.isCreated).isTrue() - } - - @Test - fun onTaskCreated_callsDelegateListener() { - var actualTaskId = -1 - var actualComponentName: ComponentName? = null - val delegateListener = object : TaskView.Listener { - override fun onTaskCreated(taskId: Int, name: ComponentName) { - actualTaskId = taskId - actualComponentName = name - } - } - bubbleTaskView.delegateListener = delegateListener - - val componentName = ComponentName(context, "TestClass") - bubbleTaskView.listener.onTaskCreated(123, componentName) - - assertThat(actualTaskId).isEqualTo(123) - assertThat(actualComponentName).isEqualTo(componentName) - } - - @Test - fun cleanup_invalidTaskId_doesNotRemoveTask() { - bubbleTaskView.cleanup() - verify(taskView, never()).removeTask() - } - - @Test - fun cleanup_validTaskId_removesTask() { - val componentName = ComponentName(context, "TestClass") - bubbleTaskView.listener.onTaskCreated(123, componentName) - - bubbleTaskView.cleanup() - verify(taskView).removeTask() - } -} diff --git a/wmshell/multivalentTestsForDeviceless/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt b/wmshell/multivalentTestsForDeviceless/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt deleted file mode 100644 index ace2c13105..0000000000 --- a/wmshell/multivalentTestsForDeviceless/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Copyright (C) 2024 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.bar - -import android.content.Context -import android.graphics.Insets -import android.graphics.PointF -import android.graphics.Rect -import android.view.View -import android.view.WindowManager -import android.widget.FrameLayout -import androidx.core.animation.AnimatorTestRule -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.common.ProtoLog -import com.android.wm.shell.R -import com.android.wm.shell.bubbles.BubblePositioner -import com.android.wm.shell.bubbles.DeviceConfig -import com.android.wm.shell.common.bubbles.BaseBubblePinController -import com.android.wm.shell.common.bubbles.BaseBubblePinController.Companion.DROP_TARGET_ALPHA_IN_DURATION -import com.android.wm.shell.common.bubbles.BaseBubblePinController.Companion.DROP_TARGET_ALPHA_OUT_DURATION -import com.android.wm.shell.common.bubbles.BubbleBarLocation -import com.android.wm.shell.common.bubbles.BubbleBarLocation.LEFT -import com.android.wm.shell.common.bubbles.BubbleBarLocation.RIGHT -import com.google.common.truth.Truth.assertThat -import org.junit.After -import org.junit.Before -import org.junit.ClassRule -import org.junit.Test -import org.junit.runner.RunWith - -/** Tests for [BubbleExpandedViewPinController] */ -@SmallTest -@RunWith(AndroidJUnit4::class) -class BubbleExpandedViewPinControllerTest { - - companion object { - @JvmField @ClassRule val animatorTestRule: AnimatorTestRule = AnimatorTestRule() - - const val SCREEN_WIDTH = 2000 - const val SCREEN_HEIGHT = 1000 - - const val BUBBLE_BAR_HEIGHT = 50 - } - - private val context = ApplicationProvider.getApplicationContext() - private lateinit var positioner: BubblePositioner - private lateinit var container: FrameLayout - - private lateinit var controller: BubbleExpandedViewPinController - private lateinit var testListener: TestLocationChangeListener - - private val dropTargetView: View? - get() = container.findViewById(R.id.bubble_bar_drop_target) - - private val pointOnLeft = PointF(100f, 100f) - private val pointOnRight = PointF(1900f, 500f) - - @Before - fun setUp() { - ProtoLog.REQUIRE_PROTOLOGTOOL = false - container = FrameLayout(context) - val windowManager = context.getSystemService(WindowManager::class.java) - positioner = BubblePositioner(context, windowManager) - positioner.setShowingInBubbleBar(true) - val deviceConfig = - DeviceConfig( - windowBounds = Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), - isLargeScreen = true, - isSmallTablet = false, - isLandscape = true, - isRtl = false, - insets = Insets.of(10, 20, 30, 40) - ) - positioner.update(deviceConfig) - positioner.bubbleBarTopOnScreen = - SCREEN_HEIGHT - deviceConfig.insets.bottom - BUBBLE_BAR_HEIGHT - controller = BubbleExpandedViewPinController(context, container, positioner) - testListener = TestLocationChangeListener() - controller.setListener(testListener) - } - - @After - fun tearDown() { - getInstrumentation().runOnMainSync { controller.onDragEnd() } - waitForAnimateOut() - } - - /** Dragging on same side should not show drop target or trigger location changes */ - @Test - fun drag_stayOnRightSide() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = false) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - controller.onDragEnd() - } - waitForAnimateIn() - assertThat(dropTargetView).isNull() - assertThat(testListener.locationChanges).isEmpty() - assertThat(testListener.locationReleases).containsExactly(RIGHT) - } - - /** Dragging on same side should not show drop target or trigger location changes */ - @Test - fun drag_stayOnLeftSide() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = true) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - controller.onDragEnd() - } - waitForAnimateIn() - assertThat(dropTargetView).isNull() - assertThat(testListener.locationChanges).isEmpty() - assertThat(testListener.locationReleases).containsExactly(LEFT) - } - - /** Drag crosses to the other side. Show drop target and trigger a location change. */ - @Test - fun drag_rightToLeft() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = false) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - } - waitForAnimateIn() - - assertThat(dropTargetView).isNotNull() - assertThat(dropTargetView!!.alpha).isEqualTo(1f) - assertThat(dropTargetView!!.bounds()).isEqualTo(getExpectedDropTargetBoundsOnLeft()) - assertThat(testListener.locationChanges).containsExactly(LEFT) - assertThat(testListener.locationReleases).isEmpty() - } - - /** Drag crosses to the other side. Show drop target and trigger a location change. */ - @Test - fun drag_leftToRight() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = true) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - } - waitForAnimateIn() - - assertThat(dropTargetView).isNotNull() - assertThat(dropTargetView!!.alpha).isEqualTo(1f) - assertThat(dropTargetView!!.bounds()).isEqualTo(getExpectedDropTargetBoundsOnRight()) - assertThat(testListener.locationChanges).containsExactly(RIGHT) - assertThat(testListener.locationReleases).isEmpty() - } - - /** - * Drop target does not initially show on the side that the drag starts. Check that it shows up - * after the dragging the view to other side and back to the initial side. - */ - @Test - fun drag_rightToLeftToRight() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = false) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNull() - - getInstrumentation().runOnMainSync { controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) } - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - - getInstrumentation().runOnMainSync { - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - } - waitForAnimateOut() - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - assertThat(dropTargetView!!.alpha).isEqualTo(1f) - assertThat(dropTargetView!!.bounds()).isEqualTo(getExpectedDropTargetBoundsOnRight()) - assertThat(testListener.locationChanges).containsExactly(LEFT, RIGHT).inOrder() - assertThat(testListener.locationReleases).isEmpty() - } - - /** - * Drop target does not initially show on the side that the drag starts. Check that it shows up - * after the dragging the view to other side and back to the initial side. - */ - @Test - fun drag_leftToRightToLeft() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = true) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNull() - - getInstrumentation().runOnMainSync { - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - - getInstrumentation().runOnMainSync { controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) } - waitForAnimateOut() - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - assertThat(dropTargetView!!.alpha).isEqualTo(1f) - assertThat(dropTargetView!!.bounds()).isEqualTo(getExpectedDropTargetBoundsOnLeft()) - assertThat(testListener.locationChanges).containsExactly(RIGHT, LEFT).inOrder() - assertThat(testListener.locationReleases).isEmpty() - } - - /** - * Drag from right to left, but stay in exclusion rect around the dismiss view. Drop target - * should not show and location change should not trigger. - */ - @Test - fun drag_rightToLeft_inExclusionRect() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = false) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - // Exclusion rect is around the bottom center area of the screen - controller.onDragUpdate(SCREEN_WIDTH / 2f - 50, SCREEN_HEIGHT - 100f) - } - waitForAnimateIn() - assertThat(dropTargetView).isNull() - assertThat(testListener.locationChanges).isEmpty() - assertThat(testListener.locationReleases).isEmpty() - } - - /** - * Drag from left to right, but stay in exclusion rect around the dismiss view. Drop target - * should not show and location change should not trigger. - */ - @Test - fun drag_leftToRight_inExclusionRect() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = true) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - // Exclusion rect is around the bottom center area of the screen - controller.onDragUpdate(SCREEN_WIDTH / 2f + 50, SCREEN_HEIGHT - 100f) - } - waitForAnimateIn() - assertThat(dropTargetView).isNull() - assertThat(testListener.locationChanges).isEmpty() - assertThat(testListener.locationReleases).isEmpty() - } - - /** - * Drag to dismiss target and back to the same side should not cause the drop target to show. - */ - @Test - fun drag_rightToDismissToRight() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = false) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - controller.onStuckToDismissTarget() - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNull() - assertThat(testListener.locationChanges).isEmpty() - assertThat(testListener.locationReleases).isEmpty() - } - - /** - * Drag to dismiss target and back to the same side should not cause the drop target to show. - */ - @Test - fun drag_leftToDismissToLeft() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = true) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - controller.onStuckToDismissTarget() - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNull() - assertThat(testListener.locationChanges).isEmpty() - assertThat(testListener.locationReleases).isEmpty() - } - - /** Drag to dismiss target and other side should show drop target on the other side. */ - @Test - fun drag_rightToDismissToLeft() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = false) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - controller.onStuckToDismissTarget() - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - assertThat(dropTargetView!!.alpha).isEqualTo(1f) - assertThat(dropTargetView!!.bounds()).isEqualTo(getExpectedDropTargetBoundsOnLeft()) - - assertThat(testListener.locationChanges).containsExactly(LEFT) - assertThat(testListener.locationReleases).isEmpty() - } - - /** Drag to dismiss target and other side should show drop target on the other side. */ - @Test - fun drag_leftToDismissToRight() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = true) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - controller.onStuckToDismissTarget() - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - assertThat(dropTargetView!!.alpha).isEqualTo(1f) - assertThat(dropTargetView!!.bounds()).isEqualTo(getExpectedDropTargetBoundsOnRight()) - - assertThat(testListener.locationChanges).containsExactly(RIGHT) - assertThat(testListener.locationReleases).isEmpty() - } - - /** - * Drag to dismiss should trigger a location change to the initial location, if the current - * location is different. And hide the drop target. - */ - @Test - fun drag_rightToLeftToDismiss() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = false) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - assertThat(dropTargetView!!.alpha).isEqualTo(1f) - - getInstrumentation().runOnMainSync { controller.onStuckToDismissTarget() } - waitForAnimateOut() - assertThat(dropTargetView!!.alpha).isEqualTo(0f) - - assertThat(testListener.locationChanges).containsExactly(LEFT, RIGHT).inOrder() - assertThat(testListener.locationReleases).isEmpty() - } - - /** - * Drag to dismiss should trigger a location change to the initial location, if the current - * location is different. And hide the drop target. - */ - @Test - fun drag_leftToRightToDismiss() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = true) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - assertThat(dropTargetView!!.alpha).isEqualTo(1f) - getInstrumentation().runOnMainSync { controller.onStuckToDismissTarget() } - waitForAnimateOut() - assertThat(dropTargetView!!.alpha).isEqualTo(0f) - assertThat(testListener.locationChanges).containsExactly(RIGHT, LEFT).inOrder() - assertThat(testListener.locationReleases).isEmpty() - } - - /** Finishing drag should remove drop target and send location update. */ - @Test - fun drag_rightToLeftRelease() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = false) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - - getInstrumentation().runOnMainSync { controller.onDragEnd() } - waitForAnimateOut() - assertThat(dropTargetView).isNull() - assertThat(testListener.locationChanges).containsExactly(LEFT) - assertThat(testListener.locationReleases).containsExactly(LEFT) - } - - /** Finishing drag should remove drop target and send location update. */ - @Test - fun drag_leftToRightRelease() { - getInstrumentation().runOnMainSync { - controller.onDragStart(initialLocationOnLeft = true) - controller.onDragUpdate(pointOnLeft.x, pointOnLeft.y) - controller.onDragUpdate(pointOnRight.x, pointOnRight.y) - } - waitForAnimateIn() - assertThat(dropTargetView).isNotNull() - - getInstrumentation().runOnMainSync { controller.onDragEnd() } - waitForAnimateOut() - assertThat(dropTargetView).isNull() - assertThat(testListener.locationChanges).containsExactly(RIGHT) - assertThat(testListener.locationReleases).containsExactly(RIGHT) - } - - private fun getExpectedDropTargetBoundsOnLeft(): Rect = - Rect().also { - positioner.getBubbleBarExpandedViewBounds( - true /* onLeft */, - false /* isOverflowExpanded */, - it - ) - } - - private fun getExpectedDropTargetBoundsOnRight(): Rect = - Rect().also { - positioner.getBubbleBarExpandedViewBounds( - false /* onLeft */, - false /* isOverflowExpanded */, - it - ) - } - - private fun waitForAnimateIn() { - // Advance animator for on-device test - getInstrumentation().runOnMainSync { - animatorTestRule.advanceTimeBy(DROP_TARGET_ALPHA_IN_DURATION) - } - } - - private fun waitForAnimateOut() { - // Advance animator for on-device test - getInstrumentation().runOnMainSync { - animatorTestRule.advanceTimeBy(DROP_TARGET_ALPHA_OUT_DURATION) - } - } - - private fun View.bounds(): Rect { - return Rect(0, 0, layoutParams.width, layoutParams.height).also { rect -> - rect.offsetTo(x.toInt(), y.toInt()) - } - } - - internal class TestLocationChangeListener : BaseBubblePinController.LocationChangeListener { - val locationChanges = mutableListOf() - val locationReleases = mutableListOf() - override fun onChange(location: BubbleBarLocation) { - locationChanges.add(location) - } - - override fun onRelease(location: BubbleBarLocation) { - locationReleases.add(location) - } - } -} diff --git a/wmshell/res/drawable/bubble_ic_create_bubble.xml b/wmshell/res/drawable/bubble_ic_create_bubble.xml index 920671a242..c9de8b81c0 100644 --- a/wmshell/res/drawable/bubble_ic_create_bubble.xml +++ b/wmshell/res/drawable/bubble_ic_create_bubble.xml @@ -15,11 +15,11 @@ ~ limitations under the License. --> + android:width="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960"> + android:pathData="m464,480 l-90,-90q-11,-11 -11.5,-27.5T374,334q11,-11 28,-11t28,11l90,89v-49q0,-17 11.5,-28.5T560,334q17,0 28.5,11.5T600,374v146q0,17 -11.5,28.5T560,560L414,560q-17,0 -28.5,-11.5T374,520q0,-17 11.5,-28.5T414,480h50ZM760,800q-50,0 -85,-35t-35,-85q0,-50 35,-85t85,-35q50,0 85,35t35,85q0,50 -35,85t-85,35ZM160,800q-33,0 -56.5,-23.5T80,720v-480q0,-33 23.5,-56.5T160,160h640q33,0 56.5,23.5T880,240v200q0,17 -11.5,28.5T840,480q-17,0 -28.5,-11.5T800,440v-200L160,240v480h360q17,0 28.5,11.5T560,760q0,17 -11.5,28.5T520,800L160,800Z" + android:fillColor="#FF000000"/> diff --git a/wmshell/res/drawable/bubble_ic_stop_bubble.xml b/wmshell/res/drawable/bubble_ic_stop_bubble.xml index 8609576ce7..b06112266d 100644 --- a/wmshell/res/drawable/bubble_ic_stop_bubble.xml +++ b/wmshell/res/drawable/bubble_ic_stop_bubble.xml @@ -15,11 +15,11 @@ ~ limitations under the License. --> + android:width="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960"> + android:pathData="M160,800q-33,0 -56.5,-23.5T80,720v-480q0,-33 23.5,-56.5T160,160h640q33,0 56.5,23.5T880,240v200q0,17 -11.5,28.5T840,480q-17,0 -28.5,-11.5T800,440v-200L160,240v480h360q17,0 28.5,11.5T560,760q0,17 -11.5,28.5T520,800L160,800ZM496,400 L586,490q11,11 11,27.5T586,546q-12,12 -28.5,12T529,546l-89,-89v49q0,17 -11.5,28.5T400,546q-17,0 -28.5,-11.5T360,506v-146q0,-17 11.5,-28.5T400,320h146q17,0 28.5,11.5T586,360q0,17 -11.5,28.5T546,400h-50ZM760,800q-50,0 -85,-35t-35,-85q0,-50 35,-85t85,-35q50,0 85,35t35,85q0,50 -35,85t-85,35Z" + android:fillColor="#FF000000"/> diff --git a/wmshell/res/layout/desktop_mode_app_header.xml b/wmshell/res/layout/desktop_mode_app_header.xml index b898e4b06c..04681a8ba9 100644 --- a/wmshell/res/layout/desktop_mode_app_header.xml +++ b/wmshell/res/layout/desktop_mode_app_header.xml @@ -60,6 +60,20 @@ android:focusable="false" tools:text="Gmail"/> + + @@ -164,12 +165,33 @@ android:src="@drawable/desktop_mode_ic_handle_menu_change_aspect_ratio" style="@style/DesktopModeHandleMenuActionButton"/> - + + + + + + - - - - - - + diff --git a/wmshell/res/layout/letterbox_restart_dialog_layout.xml b/wmshell/res/layout/letterbox_restart_dialog_layout.xml index 462a49ccb1..33af38bbf6 100644 --- a/wmshell/res/layout/letterbox_restart_dialog_layout.xml +++ b/wmshell/res/layout/letterbox_restart_dialog_layout.xml @@ -50,6 +50,7 @@ android:orientation="vertical"> + + "Hierdie app kan net in 1 venster oopgemaak word" "App sal dalk nie op \'n sekondêre skerm werk nie." "App steun nie begin op sekondêre skerms nie." + "App steun nie borrel nie" "Skermverdeler" "Skermverdeler" "Volskerm links" @@ -133,12 +134,18 @@ "Bestuur vensters" "Verander aspekverhouding" "Optimeer aansig" + "Fout-ikoon" "Maak toe" "Maak kieslys toe" "%1$s (werkskermvensters)" "Maksimeer skerm" "Verander grootte" "App kan nie hierheen geskuif word nie" + "Maak tans nuwe appvenster oop" + "Maak tans appvenster toe" + "Minimeer tans appvenster" + "%1$s (gefokus)" + "%1$s (nie gefokus nie)" "Meesleurend" "Stel terug" "Maksimeer" diff --git a/wmshell/res/values-am/strings.xml b/wmshell/res/values-am/strings.xml index 97aa47f3e1..df65c5592c 100644 --- a/wmshell/res/values-am/strings.xml +++ b/wmshell/res/values-am/strings.xml @@ -36,6 +36,7 @@ "ይህ መተግበሪያ መከፈት የሚችለው በ1 መስኮት ብቻ ነው" "መተግበሪያ በሁለተኛ ማሳያ ላይ ላይሠራ ይችላል።" "መተግበሪያ በሁለተኛ ማሳያዎች ላይ ማስጀመርን አይደግፍም።" + "መተግበሪያ ዓረፋን አይደግፍም" "የተከፈለ የማያ ገፅ ከፋይ" "የተከፈለ የማያ ገፅ ከፋይ" "የግራ ሙሉ ማያ ገፅ" @@ -133,12 +134,18 @@ "መስኮቶችን አስተዳድር" "ምጥጥነ ገፅታ ለውጥ" "ዕይታን አትባ" + "የስህተት አዶ" "ዝጋ" "ምናሌ ዝጋ" "%1$s (ዴስክቶፕ መስኮት)" "የማያ ገጹ መጠን አሳድግ" "መጠን ቀይር" "መተግበሪያ ወደዚህ መንቀሳቀስ አይችልም" + "አዲስ የመተግበሪያ መስኮት በመክፈት ላይ" + "የመተግበሪያ መስኮትን በመዝጋት ላይ" + "የመተግበሪያ መስኮትን በማሳነስ ላይ" + "%1$s (ትኩረት የተደረገበት)" + "%1$s (ትኩረት ያልተደረገበት)" "አስማጭ" "ወደነበረበት መልስ" "አሳድግ" diff --git a/wmshell/res/values-ar/strings.xml b/wmshell/res/values-ar/strings.xml index 1de9ce0199..93a69b1895 100644 --- a/wmshell/res/values-ar/strings.xml +++ b/wmshell/res/values-ar/strings.xml @@ -36,6 +36,7 @@ "لا يمكن فتح هذا التطبيق إلا في نافذة واحدة." "قد لا يعمل التطبيق على شاشة عرض ثانوية." "لا يمكن تشغيل التطبيق على شاشات عرض ثانوية." + "لا يتيح التطبيق إظهار المهام على شكل فقاعة" "أداة تقسيم الشاشة" "أداة تقسيم الشاشة" "عرض النافذة اليسرى بملء الشاشة" @@ -133,12 +134,18 @@ "إدارة النوافذ" "تغيير نسبة العرض إلى الارتفاع" "تحسين طريقة العرض" + "رمز الخطأ" "إغلاق" "إغلاق القائمة" "‫%1$s (عرض المحتوى في النافذة الحالية على سطح المكتب)" "تكبير الشاشة إلى أقصى حدّ" "تغيير الحجم" "لا يمكن نقل التطبيق إلى هنا" + "جارٍ فتح نافذة تطبيق جديدة" + "جارٍ إغلاق نافذة التطبيق" + "جارٍ تصغير نافذة التطبيق" + "‫\"%1$s\" (تم التركيز عليه)" + "‫%1$s (غير مركّز عليه)" "مجسَّم" "استعادة" "تكبير" diff --git a/wmshell/res/values-as/strings.xml b/wmshell/res/values-as/strings.xml index 96f2aaaf1e..297bc7253a 100644 --- a/wmshell/res/values-as/strings.xml +++ b/wmshell/res/values-as/strings.xml @@ -36,6 +36,7 @@ "এই এপ্‌টো কেৱল ১ খন ৱিণ্ড’ত খুলিব পাৰি" "গৌণ ডিছপ্লেত এপে সঠিকভাৱে কাম নকৰিব পাৰে।" "গৌণ ডিছপ্লেত এপ্ লঞ্চ কৰিব নোৱাৰি।" + "এপে বাবল সমৰ্থন নকৰে" "স্প্লিট স্ক্ৰীনৰ বিভাজক" "স্প্লিট স্ক্ৰীনৰ বিভাজক" "বাওঁফালৰ স্ক্ৰীনখন সম্পূৰ্ণ স্ক্ৰীন কৰক" @@ -133,12 +134,18 @@ "ৱিণ্ড’ পৰিচালনা কৰক" "আকাৰৰ অনুপাত সলনি কৰক" "ভিউ অপ্টিমাইজ কৰক" + "আসোঁৱাহৰ চিহ্ন" "বন্ধ কৰক" "মেনু বন্ধ কৰক" "%1$s (ডেস্কটপ ৱিণ্ড’ৱিং)" "স্ক্ৰীন মেক্সিমাইজ কৰক" "আকাৰ সলনি কৰক" "ইয়ালৈ এপ্‌টো আনিব নোৱাৰি" + "নতুন এপৰ ৱিণ্ড’ খুলি থকা হৈছে" + "এপৰ ৱিণ্ড’ বন্ধ কৰি থকা হৈছে" + "এপৰ ৱিণ্ড’ মিনিমাইজ কৰা হৈছে" + "%1$s (ফ’কাছ কৰা)" + "%1$s (ফ’কাছ কৰা নাই)" "ইমাৰ্ছিভ" "পুনঃস্থাপন কৰক" "মেক্সিমাইজ কৰক" diff --git a/wmshell/res/values-az/strings.xml b/wmshell/res/values-az/strings.xml index 72736edd77..a1a3288615 100644 --- a/wmshell/res/values-az/strings.xml +++ b/wmshell/res/values-az/strings.xml @@ -36,6 +36,7 @@ "Bu tətbiq yalnız 1 pəncərədə açıla bilər" "Tətbiq ikinci ekranda işləməyə bilər." "Tətbiq ikinci ekranda başlamağı dəstəkləmir." + "Tətbiq qabarcığı dəstəkləmir" "Bölünmüş ekran ayırıcısı" "Bölünmüş ekran ayırıcısı" "Sol tam ekran" @@ -133,12 +134,18 @@ "Pəncərələri idarə edin" "Tərəflər nisbətini dəyişin" "Görünüşü optimallaşdırın" + "Xəta ikonası" "Bağlayın" "Menyunu bağlayın" "%1$s (Masaüstü pəncərə rejimi)" "Ekranı maksimum böyüdün" "Ölçüsünü dəyişin" "Tətbiqi bura köçürmək mümkün deyil" + "Yeni tətbiq pəncərəsi açılır" + "Tətbiq pəncərəsi bağlanır" + "Tətbiq pəncərəsi kiçildilir" + "%1$s (Fokuslanmış)" + "%1$s (Fokuslanmamış)" "İmmersiv" "Bərpa edin" "Böyüdün" diff --git a/wmshell/res/values-b+sr+Latn/strings.xml b/wmshell/res/values-b+sr+Latn/strings.xml index ac1be357d9..9ef65c942a 100644 --- a/wmshell/res/values-b+sr+Latn/strings.xml +++ b/wmshell/res/values-b+sr+Latn/strings.xml @@ -36,6 +36,7 @@ "Ova aplikacija može da se otvori samo u jednom prozoru" "Aplikacija možda neće funkcionisati na sekundarnom ekranu." "Aplikacija ne podržava pokretanje na sekundarnim ekranima." + "Aplikacija ne podržava oblačić" "Razdelnik podeljenog ekrana" "Razdelnik podeljenog ekrana" "Režim celog ekrana za levi ekran" @@ -77,14 +78,14 @@ "Odbaci oblačić" "Prebaci na ceo ekran" "Ne koristi oblačiće za konverzaciju" - "Ćaskajte u oblačićima" + "Četujte u oblačićima" "Nove konverzacije se prikazuju kao plutajuće ikone ili oblačići. Dodirnite da biste otvorili oblačić. Prevucite da biste ga premestili." "Kontrolišite oblačiće u bilo kom trenutku" "Dodirnite Upravljajte da biste isključili oblačiće iz ove aplikacije" "Važi" "Nema nedavnih oblačića" "Ovde se prikazuju nedavni i odbačeni oblačići" - "Ćaskajte u oblačićima" + "Četujte u oblačićima" "Nove konverzacije se pojavljuju kao ikone u donjem uglu ekrana. Dodirnite da biste ih proširili ili prevucite da biste ih odbacili." "Kontrolišite oblačiće u svakom trenutku" "Dodirnite ovde i odredite koje aplikacije i konverzacije mogu da imaju oblačić" @@ -133,12 +134,18 @@ "Upravljajte prozorima" "Promeni razmeru" "Optimizujte prikaz" + "Ikona greške" "Zatvorite" "Zatvorite meni" "%1$s (prikaz računarskih prozora)" "Povećaj ekran" "Prilagodi" "Aplikacija ne može da se premesti ovde" + "Otvara se novi prozor aplikacije" + "Zatvara se prozor aplikacije" + "Umanjuje se prozor aplikacije" + "%1$s (fokusirano)" + "%1$s (nije fokusirano)" "Imerzivno" "Vrati" "Uvećaj" diff --git a/wmshell/res/values-be/strings.xml b/wmshell/res/values-be/strings.xml index 2a2bd9683e..db2d164c95 100644 --- a/wmshell/res/values-be/strings.xml +++ b/wmshell/res/values-be/strings.xml @@ -36,6 +36,7 @@ "Гэту праграму можна адкрыць толькі ў адным акне" "Праграма можа не працаваць на дадатковых экранах." "Праграма не падтрымлівае запуск на дадатковых экранах." + "У праграме не падтрымліваецца ўсплывальны чат" "Раздзяляльнік падзеленага экрана" "Раздзяляльнік падзеленага экрана" "Левы экран – поўнаэкранны рэжым" @@ -133,12 +134,18 @@ "Кіраваць вокнамі" "Змяніць суадносіны бакоў" "Аптымізаваць прагляд" + "Значок памылкі" "Закрыць" "Закрыць меню" "%1$s (рэжым вокнаў працоўнага стала)" "Разгарнуць на ўвесь экран" "Змяніць памер" "Нельга перамясціць сюды праграму" + "Адкрываецца новае акно праграмы" + "Закрываецца акно праграмы" + "Згортваецца акно праграмы" + "%1$s (у фокусе)" + "%1$s (не ў фокусе)" "З эфектам прысутнасці" "Аднавіць" "Разгарнуць" diff --git a/wmshell/res/values-bg/strings.xml b/wmshell/res/values-bg/strings.xml index f5a93d0eb5..dcd55d7248 100644 --- a/wmshell/res/values-bg/strings.xml +++ b/wmshell/res/values-bg/strings.xml @@ -36,6 +36,7 @@ "Това приложение може да се отвори само в 1 прозорец" "Възможно е приложението да не работи на алтернативни дисплеи." "Приложението не поддържа използването на алтернативни дисплеи." + "Приложението не поддържа балончета" "Разделител в режима за разделен екран" "Разделител в режима за разделен екран" "Ляв екран: Показване на цял екран" @@ -133,12 +134,18 @@ "Управление на прозорците" "Промяна на съотношението" "Оптимизиране на изгледа" + "Икона за грешка" "Затваряне" "Затваряне на менюто" "%1$s (режим за настолни компютри)" "Увеличаване на екрана" "Нов размер" "Приложението не може да бъде преместено тук" + "Отваря се нов прозорец на приложението" + "Прозорецът на приложението се затваря" + "Прозорецът на приложението се намалява" + "%1$s (притежава фокуса)" + "%1$s (не притежава фокуса)" "Реалистично" "Възстановяване" "Увеличаване" diff --git a/wmshell/res/values-bn/strings.xml b/wmshell/res/values-bn/strings.xml index 2cc109c8a0..a031c24d88 100644 --- a/wmshell/res/values-bn/strings.xml +++ b/wmshell/res/values-bn/strings.xml @@ -36,6 +36,7 @@ "এই অ্যাপটি শুধুমাত্র ১টি উইন্ডোতে খোলা যেতে পারে" "সেকেন্ডারি ডিসপ্লেতে অ্যাপটি কাজ নাও করতে পারে।" "সেকেন্ডারি ডিসপ্লেতে অ্যাপ লঞ্চ করা যাবে না।" + "অ্যাপে বাবল কাজ করে না" "স্প্লিট স্ক্রিন বিভাজক" "স্প্লিট স্ক্রিন বিভাজক" "বাঁ দিকের অংশ নিয়ে পূর্ণ স্ক্রিন" @@ -133,12 +134,18 @@ "উইন্ডো ম্যানেজ করুন" "অ্যাস্পেক্ট রেশিও পরিবর্তন করুন" "ভিউ অপ্টিমাইজ করুন" + "সমস্যার আইকন" "বন্ধ করুন" "\'মেনু\' বন্ধ করুন" "%1$s (ডেস্কটপ উইন্ডোইং)" "স্ক্রিন বড় করুন" "ছোট বড় করুন" "অ্যাপটি এখানে সরানো যাবে না" + "নতুন অ্যাপ উইন্ডো খোলা হচ্ছে" + "অ্যাপের উইন্ডো বন্ধ করা হচ্ছে" + "অ্যাপ উইন্ডো ছোট করা হয়েছে" + "%1$s (ফোকাস করা হয়েছে)" + "%1$s (ফোকাস করা নেই)" "ইমারসিভ" "ফিরিয়ে আনুন" "বড় করুন" diff --git a/wmshell/res/values-bs/strings.xml b/wmshell/res/values-bs/strings.xml index 34b23ba9e1..9bce493380 100644 --- a/wmshell/res/values-bs/strings.xml +++ b/wmshell/res/values-bs/strings.xml @@ -36,6 +36,7 @@ "Ova aplikacija se može otvoriti samo u 1 prozoru" "Aplikacija možda neće raditi na sekundarnom ekranu." "Aplikacija ne podržava pokretanje na sekundarnim ekranima." + "Aplikacija ne podržava oblačić" "Razdjelnik podijeljenog ekrana" "Razdjelnik podijeljenog ekrana" "Lijevo cijeli ekran" @@ -133,12 +134,18 @@ "Upravljanje prozorima" "Promjena formata slike" "Optimiziranje prikaza" + "Ikona greške" "Zatvaranje" "Zatvaranje menija" "%1$s (računarski prikaz prozora)" "Maksimiziraj ekran" "Promijeni veličinu" "Ne možete premjestiti aplikaciju ovdje" + "Otvaranje novog prozora aplikacije" + "Zatvaranje prozora aplikacije" + "Minimiziranje prozora aplikacije" + "%1$s (fokusirano)" + "%1$s (nije fokusirano)" "Uvjerljivo" "Vraćanje" "Maksimiziraj" diff --git a/wmshell/res/values-ca/strings.xml b/wmshell/res/values-ca/strings.xml index ccb12b31af..cfa93554d3 100644 --- a/wmshell/res/values-ca/strings.xml +++ b/wmshell/res/values-ca/strings.xml @@ -36,6 +36,7 @@ "Aquesta aplicació només pot obrir-se en 1 finestra" "És possible que l\'aplicació no funcioni en una pantalla secundària." "L\'aplicació no es pot obrir en pantalles secundàries." + "L\'aplicació no admet la bombolla" "Separador de pantalla dividida" "Separador de pantalla dividida" "Pantalla esquerra completa" @@ -133,12 +134,18 @@ "Gestiona les finestres" "Canvia la relació d\'aspecte" "Visualització d\'Optimize" + "Icona d\'error" "Tanca" "Tanca el menú" "%1$s (sistema de finestres de tipus escriptori)" "Maximitza la pantalla" "Canvia la mida" "L\'aplicació no es pot moure aquí" + "S\'està obrint una finestra nova de l\'aplicació" + "S\'està tancant la finestra de l\'aplicació" + "S\'està minimitzant la finestra de l\'aplicació" + "%1$s (té el focus)" + "%1$s (no té el focus)" "Immersiu" "Restaura" "Maximitza" diff --git a/wmshell/res/values-cs/strings.xml b/wmshell/res/values-cs/strings.xml index 9d9d127284..4f1ac77539 100644 --- a/wmshell/res/values-cs/strings.xml +++ b/wmshell/res/values-cs/strings.xml @@ -36,6 +36,7 @@ "Tuto aplikaci lze otevřít jen v jednom okně" "Aplikace na sekundárním displeji nemusí fungovat." "Aplikace nepodporuje spuštění na sekundárních displejích." + "Aplikace bublinu nepodporuje" "Čára rozdělující obrazovku" "Čára rozdělující obrazovku" "Levá část na celou obrazovku" @@ -133,12 +134,18 @@ "Spravovat okna" "Změnit poměr stran" "Optimalizovat zobrazení" + "Ikona chyby" "Zavřít" "Zavřít nabídku" "%1$s (okna na ploše)" "Maximalizovat obrazovku" "Změnit velikost" "Aplikaci sem nelze přesunout" + "Otevírání nového okna aplikace" + "Zavírání okna aplikace" + "Minimalizace okna aplikace" + "%1$s (označeno)" + "%1$s (neoznačeno)" "Pohlcující" "Obnovit" "Maximalizovat" diff --git a/wmshell/res/values-da/strings.xml b/wmshell/res/values-da/strings.xml index 17cb246033..07ae6e9b51 100644 --- a/wmshell/res/values-da/strings.xml +++ b/wmshell/res/values-da/strings.xml @@ -36,6 +36,7 @@ "Denne app kan kun åbnes i 1 vindue" "Appen fungerer muligvis ikke på sekundære skærme." "Appen kan ikke åbnes på sekundære skærme." + "Appen understøtter ikke bobler" "Adskiller til opdelt skærm" "Adskiller til opdelt skærm" "Vis venstre del i fuld skærm" @@ -133,12 +134,18 @@ "Administrer vinduer" "Skift billedformat" "Optimer visning" + "Fejlikon" "Luk" "Luk menu" "%1$s (vinduer på skrivebordet)" "Maksimér skærm" "Tilpas størrelse" "Apps kan ikke flyttes hertil" + "Et nyt appvindue er åbnet" + "Lukker appvindue" + "Appvinduet er minimeret" + "%1$s (fremhævet)" + "%1$s (ikke fremhævet)" "Opslugende" "Gendan" "Maksimér" diff --git a/wmshell/res/values-de/strings.xml b/wmshell/res/values-de/strings.xml index c84d01437e..9a4b4529f2 100644 --- a/wmshell/res/values-de/strings.xml +++ b/wmshell/res/values-de/strings.xml @@ -36,6 +36,7 @@ "Diese App kann nur in einem einzigen Fenster geöffnet werden" "Die App funktioniert auf einem sekundären Display möglicherweise nicht." "Die App unterstützt den Start auf sekundären Displays nicht." + "App unterstützt keine Bubbles" "Bildschirmteiler" "Bildschirmteiler" "Vollbild links" @@ -133,12 +134,18 @@ "Fenster verwalten" "Seitenverhältnis ändern" "Ansicht optimieren" + "Fehlersymbol" "Schließen" "Menü schließen" "%1$s (Desktop-Freiform-Fenster)" "Bildschirm maximieren" "Größe ändern" "Die App kann nicht hierher verschoben werden" + "Neues App-Fenster wird geöffnet" + "App-Fenster wird geschlossen" + "App-Fenster wird minimiert" + "%1$s (Fokussiert)" + "%1$s (Nicht fokussiert)" "Immersiv" "Wiederherstellen" "Maximieren" diff --git a/wmshell/res/values-el/strings.xml b/wmshell/res/values-el/strings.xml index 9faf44bcc1..a85b1ceed1 100644 --- a/wmshell/res/values-el/strings.xml +++ b/wmshell/res/values-el/strings.xml @@ -36,6 +36,7 @@ "Αυτή η εφαρμογή μπορεί να ανοίξει μόνο σε ένα παράθυρο" "Η εφαρμογή ίσως να μην λειτουργήσει σε δευτερεύουσα οθόνη." "Η εφαρμογή δεν υποστηρίζει την εκκίνηση σε δευτερεύουσες οθόνες." + "Η εφαρμογή δεν υποστηρίζει συννεφάκια" "Διαχωριστικό οθόνης" "Διαχωριστικό οθόνης" "Αριστερή πλήρης οθόνη" @@ -133,12 +134,18 @@ "Διαχείριση παραθύρων" "Αλλαγή λόγου διαστάσεων" "Βελτιστοποίηση προβολής" + "Εικονίδιο σφάλματος" "Κλείσιμο" "Κλείσιμο μενού" "%1$s (Προσαρμογή σε παράθυρο στην επιφάνεια εργασίας)" "Μεγιστοποίηση οθόνης" "Αλλαγή μεγέθους" "Δεν είναι δυνατή η μετακίνηση της εφαρμογής εδώ" + "Άνοιγμα νέου παραθύρου εφαρμογής" + "Κλείσιμο παραθύρου εφαρμογής" + "Ελαχιστοποίηση παραθύρου εφαρμογής" + "%1$s (Με εστίαση)" + "%1$s (Χωρίς εστίαση)" "Καθηλωτικό" "Επαναφορά" "Μεγιστοποίηση" diff --git a/wmshell/res/values-en-rAU/strings.xml b/wmshell/res/values-en-rAU/strings.xml index dcc055449f..8a19f39182 100644 --- a/wmshell/res/values-en-rAU/strings.xml +++ b/wmshell/res/values-en-rAU/strings.xml @@ -36,6 +36,7 @@ "This app can only be opened in one window" "App may not work on a secondary display." "App does not support launch on secondary displays." + "App does not support bubble" "Split screen divider" "Split screen divider" "Left full screen" @@ -133,12 +134,18 @@ "Manage windows" "Change aspect ratio" "Optimise view" + "Error icon" "Close" "Close menu" "%1$s (Desktop windowing)" "Maximise screen" "Resize" "App can\'t be moved here" + "Opening new app window" + "Closing app window" + "Minimising app window" + "%1$s (focused)" + "%1$s (not focused)" "Immersive" "Restore" "Maximise" diff --git a/wmshell/res/values-en-rCA/strings.xml b/wmshell/res/values-en-rCA/strings.xml index 3e2de7cd3b..094203d8cb 100644 --- a/wmshell/res/values-en-rCA/strings.xml +++ b/wmshell/res/values-en-rCA/strings.xml @@ -36,6 +36,7 @@ "This app can only be opened in 1 window" "App may not work on a secondary display." "App does not support launch on secondary displays." + "App does not support bubble" "Split screen divider" "Split screen divider" "Left full screen" @@ -133,12 +134,18 @@ "Manage Windows" "Change aspect ratio" "Optimize View" + "Error Icon" "Close" "Close Menu" "%1$s (Desktop windowing)" "Maximize Screen" "Resize" "App can\'t be moved here" + "Opening new app window" + "Closing app window" + "Minimizing app window" + "%1$s (Focused)" + "%1$s (Not Focused)" "Immersive" "Restore" "Maximize" diff --git a/wmshell/res/values-en-rGB/strings.xml b/wmshell/res/values-en-rGB/strings.xml index dcc055449f..8a19f39182 100644 --- a/wmshell/res/values-en-rGB/strings.xml +++ b/wmshell/res/values-en-rGB/strings.xml @@ -36,6 +36,7 @@ "This app can only be opened in one window" "App may not work on a secondary display." "App does not support launch on secondary displays." + "App does not support bubble" "Split screen divider" "Split screen divider" "Left full screen" @@ -133,12 +134,18 @@ "Manage windows" "Change aspect ratio" "Optimise view" + "Error icon" "Close" "Close menu" "%1$s (Desktop windowing)" "Maximise screen" "Resize" "App can\'t be moved here" + "Opening new app window" + "Closing app window" + "Minimising app window" + "%1$s (focused)" + "%1$s (not focused)" "Immersive" "Restore" "Maximise" diff --git a/wmshell/res/values-en-rIN/strings.xml b/wmshell/res/values-en-rIN/strings.xml index dcc055449f..8a19f39182 100644 --- a/wmshell/res/values-en-rIN/strings.xml +++ b/wmshell/res/values-en-rIN/strings.xml @@ -36,6 +36,7 @@ "This app can only be opened in one window" "App may not work on a secondary display." "App does not support launch on secondary displays." + "App does not support bubble" "Split screen divider" "Split screen divider" "Left full screen" @@ -133,12 +134,18 @@ "Manage windows" "Change aspect ratio" "Optimise view" + "Error icon" "Close" "Close menu" "%1$s (Desktop windowing)" "Maximise screen" "Resize" "App can\'t be moved here" + "Opening new app window" + "Closing app window" + "Minimising app window" + "%1$s (focused)" + "%1$s (not focused)" "Immersive" "Restore" "Maximise" diff --git a/wmshell/res/values-es-rUS/strings.xml b/wmshell/res/values-es-rUS/strings.xml index 0f048a5324..66a4b10e2c 100644 --- a/wmshell/res/values-es-rUS/strings.xml +++ b/wmshell/res/values-es-rUS/strings.xml @@ -36,6 +36,7 @@ "Esta app solo puede estar abierta en 1 ventana" "Es posible que la app no funcione en una pantalla secundaria." "La app no puede iniciarse en pantallas secundarias." + "La app no admite la burbuja" "Divisor de pantalla dividida" "Divisor de pantalla dividida" "Pantalla izquierda completa" @@ -133,12 +134,18 @@ "Administrar ventanas" "Cambiar relación de aspecto" "Optimizar vista" + "Ícono de error" "Cerrar" "Cerrar menú" "%1$s (renderización en ventanas de escritorio)" "Maximizar pantalla" "Dividir pantalla" "No se puede mover la app aquí" + "Abriendo una nueva ventana de la app" + "Cerrando la ventana de la app" + "Minimizando la ventana de la app" + "%1$s (enfocada)" + "%1$s (sin enfocar)" "Inmersivo" "Restablecer" "Maximizar" diff --git a/wmshell/res/values-es/strings.xml b/wmshell/res/values-es/strings.xml index ab2b70e7cd..ca500a77c6 100644 --- a/wmshell/res/values-es/strings.xml +++ b/wmshell/res/values-es/strings.xml @@ -36,6 +36,7 @@ "Esta aplicación solo puede abrirse en una ventana" "Es posible que la aplicación no funcione en una pantalla secundaria." "La aplicación no se puede abrir en pantallas secundarias." + "La aplicación no es compatible con burbujas" "Divisor de pantalla dividida" "Divisor de pantalla dividida" "Pantalla izquierda completa" @@ -133,12 +134,18 @@ "Gestionar ventanas" "Cambiar relación de aspecto" "Optimizar vista" + "Icono de error" "Cerrar" "Cerrar menú" "%1$s (modo Ventanas)" "Maximizar pantalla" "Dividir pantalla" "La aplicación no se puede mover aquí" + "Abriendo nueva ventana de la aplicación" + "Cerrando ventana de la aplicación" + "Minimizando ventana de la aplicación" + "%1$s (enfocada)" + "%1$s (no enfocada)" "Inmersivo" "Restaurar" "Maximizar" diff --git a/wmshell/res/values-et/strings.xml b/wmshell/res/values-et/strings.xml index 3560439318..541240bd8a 100644 --- a/wmshell/res/values-et/strings.xml +++ b/wmshell/res/values-et/strings.xml @@ -36,6 +36,7 @@ "Selle rakenduse saab avada ainult ühes aknas" "Rakendus ei pruugi teisesel ekraanil töötada." "Rakendus ei toeta teisestel ekraanidel käivitamist." + "Rakendus ei toeta mulle" "Jagatud ekraanikuva jaotur" "Jagatud ekraanikuva jaotur" "Vasak täisekraan" @@ -133,12 +134,18 @@ "Akende haldamine" "Kuvasuhte muutmine" "Vaate optimeerimine" + "Veaikoon" "Sule" "Sule menüü" "%1$s (töölaua aknad)" "Kuva täisekraanil" "Suuruse muutmine" "Rakendust ei saa siia teisaldada" + "Rakenduse avamine uues aknas" + "Rakenduse akna sulgemine" + "Rakenduse akna minimeerimine" + "%1$s (fookuses)" + "%1$s (mitte fookuses)" "Mahuta" "Taasta" "Maksimeeri" diff --git a/wmshell/res/values-eu/strings.xml b/wmshell/res/values-eu/strings.xml index 7a2e11a63e..c3530db55a 100644 --- a/wmshell/res/values-eu/strings.xml +++ b/wmshell/res/values-eu/strings.xml @@ -36,6 +36,7 @@ "Leiho bakar batean ireki daiteke aplikazioa" "Baliteke aplikazioak ez funtzionatzea bigarren mailako pantailetan." "Aplikazioa ezin da exekutatu bigarren mailako pantailatan." + "Aplikazioak ez ditu onartzen burbuilak" "Pantaila-zatitzailea" "Pantaila-zatitzailea" "Ezarri ezkerraldea pantaila osoan" @@ -133,12 +134,18 @@ "Kudeatu leihoak" "Aldatu aspektu-erlazioa" "Optimizatu ikuspegia" + "Errore-ikonoa" "Itxi" "Itxi menua" "%1$s (ordenagailuan leihoak erabiltzeko modua)" "Handitu pantaila" "Aldatu tamaina" "Aplikazioa ezin da hona ekarri" + "Ireki da aplikazioaren leiho berri bat" + "Aplikazioaren leihoa ixten" + "Minimizatu da aplikazioaren leihoa" + "%1$s (fokuratuta)" + "%1$s (fokuratu gabe)" "Murgiltzailea" "Leheneratu" "Maximizatu" diff --git a/wmshell/res/values-fa/strings.xml b/wmshell/res/values-fa/strings.xml index 0b11c8d5bc..f889737796 100644 --- a/wmshell/res/values-fa/strings.xml +++ b/wmshell/res/values-fa/strings.xml @@ -36,6 +36,7 @@ "این برنامه فقط در ۱ پنجره می‌تواند باز شود" "ممکن است برنامه در نمایشگر ثانویه کار نکند." "برنامه از راه‌اندازی در نمایشگرهای ثانویه پشتیبانی نمی‌کند." + "این برنامه از حبابک پشتیبانی نمی‌کند" "تقسیم‌کننده صفحهٔ دونیمه" "تقسیم‌کننده صفحهٔ دونیمه" "تمام‌صفحه چپ" @@ -133,12 +134,18 @@ "مدیریت کردن پنجره‌ها" "تغییر نسبت ابعادی" "بهینه‌سازی نما" + "نماد خطا" "بستن" "بستن منو" "%1$s (پردازش پنجره‌ای رایانه)" "بزرگ کردن صفحه" "تغییر اندازه" "برنامه را نمی‌توان به اینجا منتقل کرد" + "باز کردن پنجره برنامه جدید" + "بستن پنجره برنامه" + "کوچک کردن پنجره برنامه" + "‫%1$s (کانونی‌شده)" + "‫%1$s (کانونی‌نشده)" "فراگیر" "بازیابی" "بزرگ کردن" diff --git a/wmshell/res/values-fi/strings.xml b/wmshell/res/values-fi/strings.xml index d50d693041..a33939e17e 100644 --- a/wmshell/res/values-fi/strings.xml +++ b/wmshell/res/values-fi/strings.xml @@ -36,6 +36,7 @@ "Tämän sovelluksen voi avata vain yhdessä ikkunassa" "Sovellus ei ehkä toimi toissijaisella näytöllä." "Sovellus ei tue käynnistämistä toissijaisilla näytöillä." + "Sovellus ei tue kuplia" "Näytönjakaja" "Näytönjakaja" "Vasen koko näytölle" @@ -133,12 +134,18 @@ "Hallinnoi ikkunoita" "Vaihda kuvasuhdetta" "Optimoi näkymä" + "Virhekuvake" "Sulje" "Sulje valikko" "%1$s (työpöydän ikkunointi)" "Suurenna näyttö" "Muuta kokoa" "Sovellusta ei voi siirtää tänne" + "Avataan uutta sovellusikkunaa" + "Suljetaan sovellusikkunaa" + "Pienennetään sovellusikkunaa" + "%1$s (Keskitetty)" + "%1$s (Ei keskitetty)" "Immersiivinen" "Palauta" "Suurenna" diff --git a/wmshell/res/values-fr-rCA/strings.xml b/wmshell/res/values-fr-rCA/strings.xml index 5a81df2b32..d5612ec98d 100644 --- a/wmshell/res/values-fr-rCA/strings.xml +++ b/wmshell/res/values-fr-rCA/strings.xml @@ -36,6 +36,7 @@ "Cette appli ne peut être ouverte que dans une seule fenêtre." "Il est possible que l\'appli ne fonctionne pas sur un écran secondaire." "L\'appli ne peut pas être lancée sur des écrans secondaires." + "L\'appli ne prend pas en charge la bulle" "Séparateur d\'écran partagé" "Séparateur d\'écran partagé" "Plein écran à la gauche" @@ -133,12 +134,18 @@ "Gérer les fenêtres" "Modifier les proportions" "Optimiser l\'affichage" + "Icône d\'erreur" "Fermer" "Fermer le menu" "%1$s (fenêtrage du bureau)" "Agrandir l\'écran" "Redimensionner" "Impossible de déplacer l\'appli ici" + "Ouverture d\'une nouvelle fenêtre d\'appli en cours…" + "Fermeture de la fenêtre de l\'appli en cours…" + "Réduction de la fenêtre d\'appli en cours…" + "%1$s (mise en évidence)" + "%1$s (non mise en évidence)" "Immersif" "Restaurer" "Agrandir" diff --git a/wmshell/res/values-fr/strings.xml b/wmshell/res/values-fr/strings.xml index 6c260d166b..0868fa0e83 100644 --- a/wmshell/res/values-fr/strings.xml +++ b/wmshell/res/values-fr/strings.xml @@ -36,6 +36,7 @@ "Cette appli ne peut être ouverte que dans 1 fenêtre" "Il est possible que l\'application ne fonctionne pas sur un écran secondaire." "L\'application ne peut pas être lancée sur des écrans secondaires." + "L\'appli n\'est pas compatible avec les bulles" "Séparateur d\'écran partagé" "Séparateur d\'écran partagé" "Écran de gauche en plein écran" @@ -55,7 +56,7 @@ "Affichée en haut" "Affichée en haut" "Utilisation du mode une main" - "Pour quitter, balayez l\'écran de bas en haut ou appuyez n\'importe où au-dessus de l\'application" + "Pour quitter, balayez vers le haut depuis le bas de l\'écran ou appuyez n\'importe où au-dessus de l\'application" "Démarrer le mode une main" "Quitter le mode une main" "Paramètres des bulles de %1$s" @@ -133,12 +134,18 @@ "Gérer les fenêtres" "Modifier le format" "Optimiser l\'affichage" + "Icône Erreur" "Fermer" "Fermer le menu" "%1$s (fenêtrage de bureau)" "Mettre en plein écran" "Redimensionner" "Impossible de déplacer l\'appli ici" + "Ouverture d\'une nouvelle fenêtre de l\'application" + "Fermeture de la fenêtre de l\'application" + "Réduction de la fenêtre de l\'application" + "%1$s (sélectionné)" + "%1$s (non sélectionné)" "Immersif" "Restaurer" "Agrandir" diff --git a/wmshell/res/values-gl/strings.xml b/wmshell/res/values-gl/strings.xml index b9ccf765c8..5edadbacb3 100644 --- a/wmshell/res/values-gl/strings.xml +++ b/wmshell/res/values-gl/strings.xml @@ -36,6 +36,7 @@ "Esta aplicación só se pode abrir en 1 ventá" "É posible que a aplicación non funcione nunha pantalla secundaria." "A aplicación non se pode iniciar en pantallas secundarias." + "A aplicación non admite as burbullas" "Divisor de pantalla dividida" "Divisor de pantalla dividida" "Pantalla completa á esquerda" @@ -133,12 +134,18 @@ "Xestionar as ventás" "Cambiar a proporción" "Optimizar a vista" + "Icona de erro" "Pechar" "Pechar o menú" "%1$s (modo con ventás tipo ordenador)" "Maximizar pantalla" "Cambiar tamaño" "Non se pode mover aquí a aplicación" + "Abrindo nova ventá da aplicación" + "Pechando ventá da aplicación" + "Minimizando ventá da aplicación" + "%1$s (enfocada)" + "%1$s (non enfocada)" "Envolvente" "Restaurar" "Maximizar" diff --git a/wmshell/res/values-gu/strings.xml b/wmshell/res/values-gu/strings.xml index 50bf7b5fcf..857446be11 100644 --- a/wmshell/res/values-gu/strings.xml +++ b/wmshell/res/values-gu/strings.xml @@ -36,6 +36,7 @@ "આ ઍપ માત્ર 1 વિન્ડોમાં ખોલી શકાય છે" "ઍપ્લિકેશન ગૌણ ડિસ્પ્લે પર કદાચ કામ ન કરે." "ઍપ્લિકેશન ગૌણ ડિસ્પ્લે પર લૉન્ચનું સમર્થન કરતી નથી." + "ઍપ બબલને સપોર્ટ કરતી નથી" "સ્ક્રીનને વિભાજિત કરતું વિભાજક" "સ્ક્રીનને વિભાજિત કરતું વિભાજક" "ડાબી પૂર્ણ સ્ક્રીન" @@ -133,12 +134,18 @@ "વિન્ડો મેનેજ કરો" "સાપેક્ષ ગુણોત્તર બદલો" "વ્યૂ ઑપ્ટિમાઇઝ કરો" + "ભૂલનું આઇકન" "બંધ કરો" "મેનૂ બંધ કરો" "%1$s (ડેસ્કટૉપ વિન્ડોઇંગ)" "સ્ક્રીન કરો મોટી કરો" "કદ બદલો" "ઍપ અહીં ખસેડી શકાતી નથી" + "નવી વિન્ડો ખોલવી" + "ઍપની વિન્ડો બંધ કરી રહ્યાં છીએ" + "ઍપ વિન્ડો ન્યૂનતમ કરવી" + "%1$s (ફોકસ કરેલ)" + "%1$s (ફોકસ ન કરેલી)" "ઇમર્સિવ" "રિસ્ટોર કરો" "મોટું કરો" diff --git a/wmshell/res/values-hi/strings.xml b/wmshell/res/values-hi/strings.xml index a0dd30bc2f..89a2249c8e 100644 --- a/wmshell/res/values-hi/strings.xml +++ b/wmshell/res/values-hi/strings.xml @@ -36,6 +36,7 @@ "इस ऐप्लिकेशन को सिर्फ़ एक विंडो में खोला जा सकता है" "हो सकता है कि ऐप प्राइमरी (मुख्य) डिस्प्ले के अलावा बाकी दूसरे डिस्प्ले पर काम न करे." "प्राइमरी (मुख्य) डिस्प्ले के अलावा बाकी दूसरे डिस्प्ले पर ऐप लॉन्च नहीं किया जा सकता." + "इस ऐप्लिकेशन पर बबल की सुविधा काम नहीं करती" "स्प्लिट स्क्रीन डिवाइडर मोड" "स्प्लिट स्क्रीन डिवाइडर मोड" "बाईं स्क्रीन को फ़ुल स्क्रीन बनाएं" @@ -133,12 +134,18 @@ "विंडो मैनेज करें" "आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) बदलें" "व्यू को ऑप्टिमाइज़ करें" + "गड़बड़ी का आइकॉन" "बंद करें" "मेन्यू बंद करें" "%1$s (डेस्कटॉप विंडोविंग)" "स्क्रीन को बड़ा करें" "साइज़ बदलें" "ऐप्लिकेशन को यहां मूव नहीं किया जा सकता" + "ऐप्लिकेशन की नई विंडो खोली जा रही है" + "ऐप्लिकेशन की विंडो बंद की जा रही है" + "ऐप्लिकेशन की विंडो को छोटा किया जा रहा है" + "%1$s (फ़ोकस किया गया)" + "%1$s (फ़ोकस नहीं किया गया)" "इमर्सिव" "वापस लाएं" "बड़ा करें" diff --git a/wmshell/res/values-hr/strings.xml b/wmshell/res/values-hr/strings.xml index c9e4d13f74..c0393b34c2 100644 --- a/wmshell/res/values-hr/strings.xml +++ b/wmshell/res/values-hr/strings.xml @@ -36,6 +36,7 @@ "Ova se aplikacija može otvoriti samo u jednom prozoru" "Aplikacija možda neće funkcionirati na sekundarnom zaslonu." "Aplikacija ne podržava pokretanje na sekundarnim zaslonima." + "Aplikacija ne podržava oblačić" "Razdjelnik podijeljenog zaslona" "Razdjelnik podijeljenog zaslona" "Lijevi zaslon u cijeli zaslon" @@ -133,12 +134,18 @@ "Upravljanje prozorima" "Promijeni omjer slike" "Optimiziraj prikaz" + "Ikona pogreške" "Zatvorite" "Zatvorite izbornik" "%1$s (prikaz u prozorima na računalu)" "Maksimalno povećaj zaslon" "Promijeni veličinu" "Aplikacija se ne može premjestiti ovdje" + "Otvaranje novog prozora aplikacije" + "Zatvaranje prozora aplikacije" + "Minimiziranje prozora aplikacije" + "%1$s (fokusirano)" + "%1$s (nije fokusirano)" "Interaktivno" "Vrati" "Maksimiziraj" diff --git a/wmshell/res/values-hu/strings.xml b/wmshell/res/values-hu/strings.xml index 6dae47f83d..ea2ddc94ca 100644 --- a/wmshell/res/values-hu/strings.xml +++ b/wmshell/res/values-hu/strings.xml @@ -36,6 +36,7 @@ "Ez az alkalmazás csak egy ablakban nyitható meg" "Előfordulhat, hogy az alkalmazás nem működik másodlagos kijelzőn." "Az alkalmazást nem lehet másodlagos kijelzőn elindítani." + "Az alkalmazás nem támogatja a buborékot" "Elválasztó az osztott képernyős nézetben" "Elválasztó az osztott képernyős nézetben" "Bal oldali teljes képernyőre" @@ -133,12 +134,18 @@ "Ablakok kezelése" "Méretarány módosítása" "Nézet optimalizálása" + "Hiba ikon" "Bezárás" "Menü bezárása" "%1$s (Asztali ablakkezelési mód)" "Képernyő méretének maximalizálása" "Átméretezés" "Az alkalmazás nem helyezhető át ide" + "Új alkalmazásablak megnyitása…" + "Alkalmazásablak bezárása" + "Alkalmazásablak kis méretre állítása…" + "%1$s (Fókuszált)" + "%1$s (Nincs fókuszban)" "Magával ragadó" "Visszaállítás" "Teljes méret" diff --git a/wmshell/res/values-hy/strings.xml b/wmshell/res/values-hy/strings.xml index b32bb946fa..8721d574e8 100644 --- a/wmshell/res/values-hy/strings.xml +++ b/wmshell/res/values-hy/strings.xml @@ -36,6 +36,7 @@ "Այս հավելվածը հնարավոր է բացել միայն մեկ պատուհանում" "Հավելվածը կարող է չաշխատել լրացուցիչ էկրանի վրա" "Հավելվածը չի աջակցում գործարկումը լրացուցիչ էկրանների վրա" + "Հավելվածը չի աջակցում ամպիկ" "Տրոհված էկրանի բաժանիչ" "Տրոհված էկրանի բաժանիչ" "Ձախ էկրանը՝ լիաէկրան" @@ -133,12 +134,18 @@ "Կառավարել պատուհանները" "Փոխել կողմերի հարաբերակցությունը" "Օպտիմալացնել" + "Սխալի պատկերակ" "Փակել" "Փակել ընտրացանկը" "%1$s (համակարգչային պատուհաններ)" "Ծավալել էկրանը" "Փոխել չափը" "Հավելվածը հնարավոր չէ տեղափոխել այստեղ" + "Հավելվածի նոր պատուհանը բացվում է" + "Հավելվածի պատուհանը փակվում է" + "Հավելվածի պատուհանը ծալվում է" + "Ընտրված է %1$s հավելվածը" + "%1$s հավելվածն ընտրված չէ" "Ներկայության էֆեկտով" "Վերականգնել" "Ծավալել" diff --git a/wmshell/res/values-in/strings.xml b/wmshell/res/values-in/strings.xml index 14c6113a98..ba6c8fc5c4 100644 --- a/wmshell/res/values-in/strings.xml +++ b/wmshell/res/values-in/strings.xml @@ -36,6 +36,7 @@ "Aplikasi ini hanya dapat dibuka di 1 jendela" "Aplikasi mungkin tidak berfungsi pada layar sekunder." "Aplikasi tidak mendukung peluncuran pada layar sekunder." + "Aplikasi tidak mendukung balon" "Pembagi layar terpisah" "Pembagi layar terpisah" "Layar penuh di kiri" @@ -133,12 +134,18 @@ "Kelola Jendela" "Ubah rasio aspek" "Optimalkan Tampilan" + "Ikon Error" "Tutup" "Tutup Menu" "%1$s (Mode jendela desktop)" "Perbesar Layar" "Ubah ukuran" "Aplikasi tidak dapat dipindahkan ke sini" + "Membuka jendela aplikasi baru" + "Menutup jendela aplikasi" + "Meminimalkan jendela aplikasi" + "%1$s (Difokuskan)" + "%1$s (Tidak Difokuskan)" "Imersif" "Pulihkan" "Maksimalkan" diff --git a/wmshell/res/values-is/strings.xml b/wmshell/res/values-is/strings.xml index 9e61839c86..74ade660c6 100644 --- a/wmshell/res/values-is/strings.xml +++ b/wmshell/res/values-is/strings.xml @@ -36,6 +36,7 @@ "Aðeins er hægt að opna þetta forrit í 1 glugga" "Hugsanlegt er að forritið virki ekki á öðrum skjá." "Forrit styður ekki opnun á öðrum skjá." + "Forrit styður ekki blöðru" "Skilrúm skjáskiptingar" "Skilrúm skjáskiptingar" "Vinstri á öllum skjánum" @@ -133,12 +134,18 @@ "Stjórna gluggum" "Breyta myndhlutfalli" "Fínstilla yfirlit" + "Villutákn" "Loka" "Loka valmynd" "%1$s (gluggastilling í tölvu)" "Stækka skjá" "Breyta stærð" "Ekki er hægt að færa forritið hingað" + "Opnar nýjan forritsglugga" + "Lokar forritsglugga" + "Minnkar forritsglugga" + "%1$s (í fókus)" + "%1$s (ekki í fókus)" "Umlykjandi" "Endurheimta" "Stækka" diff --git a/wmshell/res/values-it/strings.xml b/wmshell/res/values-it/strings.xml index 34b66b127b..ad3f0d3e5a 100644 --- a/wmshell/res/values-it/strings.xml +++ b/wmshell/res/values-it/strings.xml @@ -36,6 +36,7 @@ "Questa app può essere aperta soltanto in 1 finestra" "L\'app potrebbe non funzionare su un display secondario." "L\'app non supporta l\'avvio su display secondari." + "L\'app non supporta la riduzione a icona" "Strumento per schermo diviso" "Strumento per schermo diviso" "Schermata sinistra a schermo intero" @@ -133,12 +134,18 @@ "Gestisci finestre" "Cambia proporzioni" "Ottimizza visualizzazione" + "Icona di errore" "Chiudi" "Chiudi il menu" "%1$s (app in finestre)" "Massimizza schermo" "Ridimensiona" "Impossibile spostare l\'app qui" + "Apertura di una nuova finestra dell\'app" + "Chiusura della finestra app in corso…" + "Riduzione a icona della finestra dell\'app" + "%1$s (selezionata)" + "%1$s (non selezionata)" "Immersivo" "Ripristina" "Ingrandisci" diff --git a/wmshell/res/values-iw/strings.xml b/wmshell/res/values-iw/strings.xml index e02b706b11..1cccdb9cc4 100644 --- a/wmshell/res/values-iw/strings.xml +++ b/wmshell/res/values-iw/strings.xml @@ -36,6 +36,7 @@ "ניתן לפתוח את האפליקציה הזו רק בחלון אחד" "ייתכן שהאפליקציה לא תפעל במסך משני." "האפליקציה אינה תומכת בהפעלה במסכים משניים." + "האפליקציה לא תומכת בבועה" "מחלק מסך מפוצל" "מחלק מסך מפוצל" "מסך שמאלי מלא" @@ -133,12 +134,18 @@ "ניהול החלונות" "שינוי יחס הגובה-רוחב" "אופטימיזציה של התצוגה" + "סמל שגיאה" "סגירה" "סגירת התפריט" "‫%1$s (שינוי דינמי של חלונות במחשב)" "הגדלת המסך" "שינוי הגודל" "לא ניתן להעביר את האפליקציה לכאן" + "נפתח חלון חדש באפליקציה" + "החלון של האפליקציה עומד להיסגר" + "חלון האפליקציה התמזער" + "‫%1$s (במיקוד)" + "‫%1$s (לא במיקוד)" "הטמעה" "שחזור" "הגדלה" diff --git a/wmshell/res/values-ja/strings.xml b/wmshell/res/values-ja/strings.xml index 19ac853d48..d2857861af 100644 --- a/wmshell/res/values-ja/strings.xml +++ b/wmshell/res/values-ja/strings.xml @@ -36,6 +36,7 @@ "このアプリはウィンドウが 1 つの場合のみ開くことができます" "アプリはセカンダリ ディスプレイでは動作しないことがあります。" "アプリはセカンダリ ディスプレイでの起動に対応していません。" + "アプリがふきだしに対応していません" "分割画面の分割線" "分割画面の分割線" "左全画面" @@ -133,12 +134,18 @@ "ウィンドウを管理する" "アスペクト比を変更" "ビューを最適化" + "エラーアイコン" "閉じる" "メニューを閉じる" "%1$s(デスクトップ ウィンドウ)" "画面の最大化" "サイズ変更" "アプリはここに移動できません" + "新しいアプリ ウィンドウを開いています" + "アプリのウィンドウを閉じています" + "アプリ ウィンドウを最小化しています" + "%1$s(フォーカス)" + "%1$s(非フォーカス)" "没入モード" "復元" "最大化" diff --git a/wmshell/res/values-ka/strings.xml b/wmshell/res/values-ka/strings.xml index 97e5b8b22f..f604879e5a 100644 --- a/wmshell/res/values-ka/strings.xml +++ b/wmshell/res/values-ka/strings.xml @@ -36,6 +36,7 @@ "ამ აპის გახსნა შესაძლებელია მხოლოდ 1 ფანჯარაში" "აპმა შეიძლება არ იმუშაოს მეორეულ ეკრანზე." "აპს არ გააჩნია მეორეული ეკრანის მხარდაჭერა." + "ბუშტი არ არის მხარდაჭერილი აპის მიერ" "ეკრანის გაყოფის გამყოფი" "ეკრანის გაყოფის გამყოფი" "მარცხენა ნაწილის სრულ ეკრანზე გაშლა" @@ -133,12 +134,18 @@ "ფანჯრების მართვა" "თანაფარდობის შეცვლა" "ხედის ოპტიმიზება" + "შეცდომის ხატულა" "დახურვა" "მენიუს დახურვა" "%1$s (დესკტოპის ფანჯრის რეჟიმი)" "აპლიკაციის გაშლა სრულ ეკრანზე" "ზომის შეცვლა" "აპის აქ გადატანა შეუძლებელია" + "აპის ახალი ფანჯარა იხსნება" + "მიმდინარეობს აპის ფანჯრის დახურვა" + "აპის ფანჯარა იკეცება" + "%1$s (ფოკუსირებული)" + "%1$s (ფოკუსის გარეთ)" "იმერსიული" "აღდგენა" "მაქსიმალურად გაშლა" diff --git a/wmshell/res/values-kk/strings.xml b/wmshell/res/values-kk/strings.xml index 21f0496588..d96485c65f 100644 --- a/wmshell/res/values-kk/strings.xml +++ b/wmshell/res/values-kk/strings.xml @@ -36,6 +36,7 @@ "Бұл қолданбаны тек 1 терезеден ашуға болады." "Қолданба қосымша дисплейде жұмыс істемеуі мүмкін." "Қолданба қосымша дисплейлерде іске қосуды қолдамайды." + "Қолданба қалқыма терезеге қолдау көрсетпейді." "Экранды бөлу режимінің бөлгіші" "Экранды бөлу режимінің бөлгіші" "Сол жағын толық экранға шығару" @@ -133,12 +134,18 @@ "Терезелерді басқару" "Арақатынасты өзгерту" "Көріністі оңтайландыру" + "Қате белгішесі" "Жабу" "Мәзірді жабу" "%1$s (компьютерлік терезелер режимі)" "Экранды ұлғайту" "Өлшемін өзгерту" "Қолданба бұл жерге қойылмайды." + "Жаңа қолданба терезесін ашу" + "Қолданба терезесі жабылып жатыр" + "Қолданба терезесін кішірейту" + "%1$s (ерекшеленген)" + "%1$s (ерекшеленбеген)" "Иммерсивтік әсер" "Қалпына келтіру" "Жаю" diff --git a/wmshell/res/values-km/strings.xml b/wmshell/res/values-km/strings.xml index 99817c07f9..1fb1aaca9e 100644 --- a/wmshell/res/values-km/strings.xml +++ b/wmshell/res/values-km/strings.xml @@ -36,6 +36,7 @@ "អាចបើកកម្មវិធីនេះបានតែក្នុងវិនដូ 1 ប៉ុណ្ណោះ" "កម្មវិធីនេះ​ប្រហែល​ជាមិនដំណើរការ​នៅលើ​អេក្រង់បន្ទាប់បន្សំទេ។" "កម្មវិធី​នេះមិន​អាច​ចាប់ផ្តើម​នៅលើ​អេក្រង់បន្ទាប់បន្សំបានទេ។" + "កម្មវិធីមិនអាចប្រើផ្ទាំងសារបានទេ" "បន្ទាត់ខណ្ឌចែកក្នុងមុខងារ​បំបែកអេក្រង់" "បន្ទាត់ខណ្ឌចែកក្នុងមុខងារ​បំបែកអេក្រង់" "អេក្រង់ពេញខាងឆ្វេង" @@ -133,12 +134,18 @@ "គ្រប់គ្រង​វិនដូ" "ប្ដូរ​​សមាមាត្រ" "បង្កើនប្រសិទ្ធភាពការមើល" + "រូបបញ្ហា" "បិទ" "បិទ​ម៉ឺនុយ" "%1$s (មុខងារវិនដូកុំព្យូទ័រ)" "ពង្រីកអេក្រង់" "ប្ដូរ​ទំហំ" "មិនអាចផ្លាស់ទីកម្មវិធីមកទីនេះបានទេ" + "ការបើកវិនដូកម្មវិធីថ្មី" + "កំពុងបិទវិនដូកម្មវិធី" + "ការបង្រួមវិនដូកម្មវិធី" + "%1$s (បានផ្ដោត)" + "%1$s (មិនបានផ្ដោត)" "ជក់ចិត្ត" "ស្ដារ" "ពង្រីក" diff --git a/wmshell/res/values-kn/strings.xml b/wmshell/res/values-kn/strings.xml index 5c465bfa94..178eca199e 100644 --- a/wmshell/res/values-kn/strings.xml +++ b/wmshell/res/values-kn/strings.xml @@ -36,6 +36,7 @@ "ಈ ಆ್ಯಪ್ ಅನ್ನು 1 ವಿಂಡೋದಲ್ಲಿ ಮಾತ್ರ ತೆರೆಯಬಹುದು" "ಸೆಕೆಂಡರಿ ಡಿಸ್‌ಪ್ಲೇಗಳಲ್ಲಿ ಆ್ಯಪ್ ಕಾರ್ಯ ನಿರ್ವಹಿಸದೇ ಇರಬಹುದು." "ಸೆಕೆಂಡರಿ ಡಿಸ್‌ಪ್ಲೇಗಳಲ್ಲಿ ಪ್ರಾರಂಭಿಸುವಿಕೆಯನ್ನು ಆ್ಯಪ್ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ." + "ಬಬಲ್ ಅನ್ನು ಆ್ಯಪ್ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ" "ಸ್ಪ್ಲಿಟ್‌ ಸ್ಕ್ರೀನ್ ಡಿವೈಡರ್" "ಸ್ಪ್ಲಿಟ್‌ ಸ್ಕ್ರೀನ್ ಡಿವೈಡರ್" "ಎಡ ಫುಲ್ ಸ್ಕ್ರೀನ್" @@ -133,12 +134,18 @@ "ವಿಂಡೋಗಳನ್ನು ನಿರ್ವಹಿಸಿ" "ದೃಶ್ಯಾನುಪಾತವನ್ನು ಬದಲಾಯಿಸಿ" "ವೀಕ್ಷಣೆಯನ್ನು ಆಪ್ಟಿಮೈಸ್ ಮಾಡಿ" + "ದೋಷದ ಐಕಾನ್" "ಮುಚ್ಚಿ" "ಮೆನು ಮುಚ್ಚಿ" "%1$s (ಡೆಸ್ಕ್‌ಟಾಪ್ ವಿಂಡೋಯಿಂಗ್)" "ಸ್ಕ್ರೀನ್ ಅನ್ನು ಮ್ಯಾಕ್ಸಿಮೈಸ್ ಮಾಡಿ" "ಮರುಗಾತ್ರಗೊಳಿಸಿ" "ಆ್ಯಪ್ ಅನ್ನು ಇಲ್ಲಿಗೆ ಸರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ" + "ಹೊಸ ಆ್ಯಪ್ ವಿಂಡೋವನ್ನು ತೆರೆಯಲಾಗುತ್ತಿದೆ" + "ಆ್ಯಪ್ ವಿಂಡೋವನ್ನು ಮುಚ್ಚಲಾಗುತ್ತಿದೆ" + "ಆ್ಯಪ್ ವಿಂಡೋವನ್ನು ಮಿನಿಮೈಸ್ ಮಾಡಲಾಗುತ್ತಿದೆ" + "%1$s (ಫೋಕಸ್ ಮಾಡಲಾಗಿದೆ)" + "%1$s (ಫೋಕಸ್ ಮಾಡಲಾಗಿಲ್ಲ)" "ಇಮ್ಮರ್ಸಿವ್" "ಮರುಸ್ಥಾಪಿಸಿ" "ಮ್ಯಾಕ್ಸಿಮೈಸ್ ಮಾಡಿ" diff --git a/wmshell/res/values-kn/strings_tv.xml b/wmshell/res/values-kn/strings_tv.xml index efb79306cb..2e62e4f0d5 100644 --- a/wmshell/res/values-kn/strings_tv.xml +++ b/wmshell/res/values-kn/strings_tv.xml @@ -21,7 +21,7 @@ "(ಶೀರ್ಷಿಕೆ ರಹಿತ ಕಾರ್ಯಕ್ರಮ)" "ಮುಚ್ಚಿರಿ" "ಫುಲ್ ಸ್ಕ್ರೀನ್" - "ಸರಿಸಿ" + "ಮೂವ್" "ವಿಸ್ತೃತಗೊಳಿಸಿ" "ಕುಗ್ಗಿಸಿ" "ಕಂಟ್ರೋಲ್‌ಗಳಿಗಾಗಿ ""ಹೋಮ್"" ಅನ್ನು ಎರಡು ಬಾರಿ ಒತ್ತಿರಿ" diff --git a/wmshell/res/values-ko/strings.xml b/wmshell/res/values-ko/strings.xml index d856438a53..8787ddb323 100644 --- a/wmshell/res/values-ko/strings.xml +++ b/wmshell/res/values-ko/strings.xml @@ -36,6 +36,7 @@ "이 앱은 창 1개에서만 열 수 있습니다." "앱이 보조 디스플레이에서 작동하지 않을 수도 있습니다." "앱이 보조 디스플레이에서의 실행을 지원하지 않습니다." + "앱이 풍선을 지원하지 않습니다." "화면 분할기" "화면 분할기" "왼쪽 화면 전체화면" @@ -133,12 +134,18 @@ "창 관리" "가로세로 비율 변경" "뷰 최적화" + "오류 아이콘" "닫기" "메뉴 닫기" "%1$s(데스크톱 윈도윙)" "화면 최대화" "크기 조절" "앱을 여기로 이동할 수 없음" + "새 앱 창 열기" + "앱 창 닫기" + "앱 창 최소화" + "%1$s(포커스)" + "%1$s(포커스되지 않음)" "몰입형" "복원" "최대화하기" diff --git a/wmshell/res/values-ky/strings.xml b/wmshell/res/values-ky/strings.xml index 8c15c6a9c2..c3b63d22f3 100644 --- a/wmshell/res/values-ky/strings.xml +++ b/wmshell/res/values-ky/strings.xml @@ -36,6 +36,7 @@ "Бул колдонмону 1 терезеде гана ачууга болот" "Колдонмо кошумча экранда иштебей коюшу мүмкүн." "Колдонмону кошумча экрандарда иштетүүгө болбойт." + "Колдонмо көбүкчөнү колдоого албайт" "Экранды бөлгүч" "Экранды бөлгүч" "Сол жактагы экранды толук экран режимине өткөрүү" @@ -133,12 +134,18 @@ "Терезелерди тескөө" "Тараптардын катнашын өзгөртүү" "Көрүнүштү оптималдаштыруу" + "Ката сүрөтчөсү" "Жабуу" "Менюну жабуу" "%1$s (Иш тактанын терезелери)" "Экранды чоңойтуу" "Өлчөмүн өзгөртүү" "Колдонмону бул жерге жылдырууга болбойт" + "Колдонмонун жаңы терезесин ачуу" + "Колдонмо терезеси жабылууда" + "Колдонмонун терезесин кичирейтүү" + "%1$s (Иштеп жатат)" + "%1$s (Иштебей турат)" "Сүңгүтүүчү" "Калыбына келтирүү" "Чоңойтуу" diff --git a/wmshell/res/values-lo/strings.xml b/wmshell/res/values-lo/strings.xml index f3e6f81d50..b3e9ffcc56 100644 --- a/wmshell/res/values-lo/strings.xml +++ b/wmshell/res/values-lo/strings.xml @@ -36,6 +36,7 @@ "ແອັບນີ້ສາມາດເປີດໄດ້ໃນ 1 ໜ້າຈໍເທົ່ານັ້ນ" "ແອັບອາດບໍ່ສາມາດໃຊ້ໄດ້ໃນໜ້າຈໍທີສອງ." "ແອັບບໍ່ຮອງຮັບການເປີດໃນໜ້າຈໍທີສອງ." + "ແອັບບໍ່ຮອງຮັບຟອງ" "ເສັ້ນແບ່ງໜ້າຈໍ" "ເສັ້ນແບ່ງໜ້າຈໍ" "ເຕັມໜ້າຈໍຊ້າຍ" @@ -133,12 +134,18 @@ "ຈັດການໜ້າຈໍ" "ປ່ຽນອັດຕາສ່ວນຮູບ" "ມຸມມອງເພີ່ມປະສິດທິພາບ" + "ໄອຄອນຂໍ້ຜິດພາດ" "ປິດ" "ປິດເມນູ" "%1$s (ໜ້າຈໍເດັສທັອບ)" "ປັບຈໍໃຫຍ່ສຸດ" "ປັບຂະໜາດ" "ບໍ່ສາມາດຍ້າຍແອັບມາບ່ອນນີ້ໄດ້" + "ກຳລັງເປີດໜ້າຈໍແອັບໃໝ່" + "ກຳລັງປິດໜ້າຈໍແອັບ" + "ກຳລັງຫຍໍ້ໜ້າຈໍແອັບ" + "%1$s (ໂຟກັສ)" + "%1$s (ບໍ່ໂຟກັສ)" "ສົມຈິງ" "ກູ້ຄືນ" "ຂະຫຍາຍໃຫຍ່ສຸດ" diff --git a/wmshell/res/values-lt/strings.xml b/wmshell/res/values-lt/strings.xml index d22db2e0a7..821d9efe47 100644 --- a/wmshell/res/values-lt/strings.xml +++ b/wmshell/res/values-lt/strings.xml @@ -36,6 +36,7 @@ "Šią programą galima atidaryti tik viename lange" "Programa gali neveikti antriniame ekrane." "Programa nepalaiko paleisties antriniuose ekranuose." + "Programa nepalaiko pokalbio debesėlio" "Išskaidyto ekrano režimo daliklis" "Išskaidyto ekrano režimo daliklis" "Kairysis ekranas viso ekrano režimu" @@ -133,12 +134,18 @@ "Tvarkyti langus" "Keisti kraštinių santykį" "Optimizuoti rodinį" + "Klaidos piktograma" "Uždaryti" "Uždaryti meniu" "„%1$s“ (versijos staliniams kompiuteriams rodinys)" "Išskleisti ekraną" "Pakeisti dydį" "Programos negalima perkelti čia" + "Atidaromas naujas programos langas" + "Uždaromas programos langas" + "Sumažinamas programos langas" + "„%1$s“ (paryškinta)" + "„%1$s“ (neparyškinta)" "Įtraukiantis" "Atkurti" "Padidinti" diff --git a/wmshell/res/values-lv/strings.xml b/wmshell/res/values-lv/strings.xml index 0e9d4e4668..2d75741995 100644 --- a/wmshell/res/values-lv/strings.xml +++ b/wmshell/res/values-lv/strings.xml @@ -36,6 +36,7 @@ "Šo lietotni var atvērt tikai vienā logā" "Lietotne, iespējams, nedarbosies sekundārajā displejā." "Lietotnē netiek atbalstīta palaišana sekundārajos displejos." + "Lietotnē netiek atbalstīts burbulis" "Ekrāna sadalītājs" "Ekrāna sadalītājs" "Kreisā daļa pa visu ekrānu" @@ -133,12 +134,18 @@ "Pārvaldīt logus" "Mainīt malu attiecību" "Optimizēt skatu" + "Kļūdas ikona" "Aizvērt" "Aizvērt izvēlni" "%1$s (darbvirsmas logošana)" "Maksimizēt ekrānu" "Mainīt lielumu" "Lietotni nevar pārvietot šeit." + "Tiek atvērts jauns lietotnes logs" + "Tiek aizvērts lietotnes logs" + "Tiek minimizēts lietotnes logs" + "%1$s (fokusā)" + "%1$s (nav fokusā)" "Iekļaujoši" "Atjaunot" "Maksimizēt" diff --git a/wmshell/res/values-mk/strings.xml b/wmshell/res/values-mk/strings.xml index 1b7fe571d4..c6328befba 100644 --- a/wmshell/res/values-mk/strings.xml +++ b/wmshell/res/values-mk/strings.xml @@ -36,6 +36,7 @@ "Апликацијава може да се отвори само во еден прозорец" "Апликацијата може да не функционира на друг екран." "Апликацијата не поддржува стартување на други екрани." + "Апликацијата не поддржува балонче" "Разделник на поделен екран" "Разделник на поделен екран" "Левиот на цел екран" @@ -133,12 +134,18 @@ "Управувајте со прозорците" "Промени го соодносот" "Оптимизирај го приказот" + "Икона за грешка" "Затворете" "Затворете го менито" "%1$s (режим со прозорци на работната површина)" "Максимизирај го екранот" "Смени големина" "Апликацијата не може да се премести овде" + "Отворање нов прозорец на апликацијата" + "Се затвора прозорецот на апликацијата" + "Минимизирање на прозорецот на апликацијата" + "%1$s (фокусирано)" + "%1$s (не е фокусирано)" "Реалистично" "Врати" "Максимизирај" diff --git a/wmshell/res/values-ml/strings.xml b/wmshell/res/values-ml/strings.xml index 01b9dee890..6e10ce4642 100644 --- a/wmshell/res/values-ml/strings.xml +++ b/wmshell/res/values-ml/strings.xml @@ -36,6 +36,7 @@ "ഈ ആപ്പ് ഒരു വിൻഡോയിൽ മാത്രമേ തുറക്കാനാകൂ" "രണ്ടാം ഡിസ്‌പ്ലേയിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല." "രണ്ടാം ഡിസ്‌പ്ലേകളിൽ സമാരംഭിക്കുന്നതിനെ ആപ്പ് അനുവദിക്കുന്നില്ല." + "ബബിളിനെ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല" "സ്‌ക്രീൻ വിഭജന മോഡ് ഡിവൈഡർ" "സ്‌ക്രീൻ വിഭജന മോഡ് ഡിവൈഡർ" "ഇടത് പൂർണ്ണ സ്ക്രീൻ" @@ -133,12 +134,18 @@ "വിൻഡോകൾ മാനേജ് ചെയ്യുക" "വീക്ഷണ അനുപാതം മാറ്റുക" "കാഴ്‌ച ഒപ്റ്റിമൈസ് ചെയ്യുക" + "പിശക് ഐക്കൺ" "അടയ്ക്കുക" "മെനു അടയ്ക്കുക" "%1$s (ഡെസ്ക്ടോപ്പ് വിൻഡോയിംഗ്)" "സ്‌ക്രീൻ വലുതാക്കുക" "വലുപ്പം മാറ്റുക" "ആപ്പ് ഇവിടേക്ക് നീക്കാനാകില്ല" + "പുതിയ ആപ്പ് വിൻഡോ തുറക്കുന്നു" + "ആപ്പ് വിൻഡോ അടയ്‌ക്കുന്നു" + "ആപ്പ് വിൻഡോ മിനിമൈസ് ചെയ്യുന്നു" + "%1$s (ഫോക്കസ് ചെയ്‌തവ)" + "%1$s (ഫോക്കസ് ചെയ്യാത്തവ)" "ഇമേഴ്‌സീവ്" "പുനഃസ്ഥാപിക്കുക" "വലുതാക്കുക" diff --git a/wmshell/res/values-mn/strings.xml b/wmshell/res/values-mn/strings.xml index 8486c9e83f..5bf953a7cd 100644 --- a/wmshell/res/values-mn/strings.xml +++ b/wmshell/res/values-mn/strings.xml @@ -36,6 +36,7 @@ "Энэ аппыг зөвхөн 1 цонхонд нээх боломжтой" "Апп хоёрдогч дэлгэцэд ажиллахгүй." "Аппыг хоёрдогч дэлгэцэд эхлүүлэх боломжгүй." + "Апп бөмбөлгийг дэмждэггүй" "Дэлгэцийг хуваах хуваагч" "Дэлгэцийг хуваах хуваагч" "Зүүн талын бүтэн дэлгэц" @@ -133,12 +134,18 @@ "Цонхнуудыг удирдах" "Аспектын харьцааг өөрчлөх" "Харагдах байдлыг оновчлох" + "Алдааны дүрс тэмдэг" "Хаах" "Цэсийг хаах" "%1$s (Дэлгэцийн цонх үүсгэх онцлог)" "Дэлгэцийг томруулах" "Хэмжээг өөрчлөх" "Аппыг ийш зөөх боломжгүй" + "Аппын шинэ цонхыг нээж байна" + "Аппын цонхыг хааж байна" + "Аппын цонхыг жижгэрүүлж байна" + "%1$s (сонгосон)" + "%1$s (сонгоогүй)" "Бодит мэт" "Сэргээх" "Томруулах" diff --git a/wmshell/res/values-mr/strings.xml b/wmshell/res/values-mr/strings.xml index 2cb04aca30..5dd4013a0a 100644 --- a/wmshell/res/values-mr/strings.xml +++ b/wmshell/res/values-mr/strings.xml @@ -36,6 +36,7 @@ "हे अ‍ॅप फक्त एका विंडोमध्ये उघडले जाऊ शकते" "दुसऱ्या डिस्प्लेवर अ‍ॅप कदाचित चालणार नाही." "दुसऱ्या डिस्प्लेवर अ‍ॅप लाँच होणार नाही." + "अ‍ॅप बबलला सपोर्ट करत नाही" "स्प्लिट स्क्रीन विभाजक" "स्प्लिट स्क्रीन विभाजक" "डावी फुल स्क्रीन" @@ -133,12 +134,18 @@ "विंडो व्यवस्थापित करा" "आस्पेक्ट रेशो बदला" "दृश्य ऑप्टिमाइझ करा" + "एरर आयकन" "बंद करा" "मेनू बंद करा" "%1$s (डेस्कटॉप विंडोइंग)" "स्क्रीन मोठी करा" "आकार बदला" "अ‍ॅप इथे हलवू शकत नाही" + "नवीन अ‍ॅप विंडो उघडत आहे" + "अ‍ॅपची विंडो बंद करत आहे" + "अ‍ॅप विंडो लहान करत आहे" + "%1$s (फोकस केलेले)" + "%1$s (फोकस न केलेले)" "इमर्सिव्ह" "रिस्टोअर करा" "मोठे करा" diff --git a/wmshell/res/values-ms/strings.xml b/wmshell/res/values-ms/strings.xml index 1f6cb3bf4b..1ac684f890 100644 --- a/wmshell/res/values-ms/strings.xml +++ b/wmshell/res/values-ms/strings.xml @@ -36,6 +36,7 @@ "Apl ini hanya boleh dibuka dalam 1 tetingkap" "Apl mungkin tidak berfungsi pada paparan kedua." "Apl tidak menyokong pelancaran pada paparan kedua." + "Apl tidak menyokong gelembung" "Pembahagi skrin pisah" "Pembahagi skrin pisah" "Skrin penuh kiri" @@ -133,12 +134,18 @@ "Urus Tetingkap" "Tukar nisbah bidang" "Optimumkan Paparan" + "Ikon Ralat" "Tutup" "Tutup Menu" "%1$s (Tetingkap desktop)" "Maksimumkan Skrin" "Ubah saiz" "Apl tidak boleh dialihkan ke sini" + "Membuka tetingkap apl baharu" + "Menutup tetingkap apl" + "Meminimumkan tetingkap apl" + "%1$s (Terfokus)" + "%1$s (Tidak terfokus)" "Mengasyikkan" "Pulihkan" "Maksimumkan" diff --git a/wmshell/res/values-my/strings.xml b/wmshell/res/values-my/strings.xml index 684a52bd39..35f4588546 100644 --- a/wmshell/res/values-my/strings.xml +++ b/wmshell/res/values-my/strings.xml @@ -36,6 +36,7 @@ "ဤအက်ပ်ကို ဝင်းဒိုး ၁ ခုတွင်သာ ဖွင့်နိုင်သည်" "ဤအက်ပ်အနေဖြင့် ဒုတိယဖန်သားပြင်ပေါ်တွင် အလုပ်လုပ်မည် မဟုတ်ပါ။" "ဤအက်ပ်အနေဖြင့် ဖွင့်ရန်စနစ်ကို ဒုတိယဖန်သားပြင်မှ အသုံးပြုရန် ပံ့ပိုးမထားပါ။" + "အက်ပ်သည် ပူဖောင်းကွက်ကို မပံ့ပိုးပါ" "မျက်နှာပြင် ခွဲ၍ပြသခြင်း ပိုင်းခြားစနစ်" "မျက်နှာပြင် ခွဲ၍ပြသခြင်း ပိုင်းခြားစနစ်" "ဘယ်ဘက် မျက်နှာပြင်အပြည့်" @@ -133,12 +134,18 @@ "ဝင်းဒိုးများ စီမံရန်" "အချိုးအစား ပြောင်းရန်" "မြင်ကွင်းကို ပိုကောင်းအောင်လုပ်ရန်" + "အမှားအယွင်း သင်္ကေတ" "ပိတ်ရန်" "မီနူး ပိတ်ရန်" "%1$s (ဒက်စ်တော့ဝင်းဒိုးမုဒ်)" "စခရင်ကို ချဲ့မည်" "အရွယ်ပြင်ရန်" "အက်ပ်ကို ဤနေရာသို့ ရွှေ့၍မရပါ" + "အက်ပ်ဝင်းဒိုးအသစ် ဖွင့်နေသည်" + "အက်ပ်ဝင်းဒိုး ပိတ်ခြင်း" + "အက်ပ်ဝင်းဒိုးကို ချုံ့နေသည်" + "%1$s (အာရုံပြုထားသည်)" + "%1$s (အာရုံပြုမထားပါ)" "ဘက်ပေါင်းစုံ" "ပြန်ပြောင်းရန်" "ချဲ့ရန်" diff --git a/wmshell/res/values-nb/strings.xml b/wmshell/res/values-nb/strings.xml index 0b6dd8acce..a5db560430 100644 --- a/wmshell/res/values-nb/strings.xml +++ b/wmshell/res/values-nb/strings.xml @@ -36,6 +36,7 @@ "Denne appen kan bare åpnes i ett vindu" "Appen fungerer kanskje ikke på en sekundær skjerm." "Appen kan ikke kjøres på sekundære skjermer." + "Appen støtter ikke bobler" "Skilleelement for delt skjerm" "Skilleelement for delt skjerm" "Utvid den venstre delen av skjermen til hele skjermen" @@ -133,12 +134,18 @@ "Administrer vinduene" "Endre høyde/bredde-forholdet" "Optimaliser visning" + "Feilikon" "Lukk" "Lukk menyen" "%1$s (datamaskin-vindusvisning)" "Maksimer skjermen" "Endre størrelse" "Appen kan ikke flyttes hit" + "Åpner et nytt appvindu" + "Lukker appvinduet" + "Minimerer appvinduet" + "%1$s (fokusert)" + "%1$s (ikke fokusert)" "Oppslukende" "Gjenopprett" "Maksimer" diff --git a/wmshell/res/values-ne/strings.xml b/wmshell/res/values-ne/strings.xml index b370a6f7f1..2b5f36772a 100644 --- a/wmshell/res/values-ne/strings.xml +++ b/wmshell/res/values-ne/strings.xml @@ -36,6 +36,7 @@ "यो एप एउटा विन्डोमा मात्र खोल्न मिल्छ" "यो एपले सहायक प्रदर्शनमा काम नगर्नसक्छ।" "एपले सहायक प्रदर्शनहरूमा लञ्च सुविधालाई समर्थन गर्दैन।" + "एपमा बबल प्रयोग गर्न मिल्दैन" "स्प्लिट स्क्रिन डिभाइडर" "स्प्लिट स्क्रिन डिभाइडर" "बायाँ भाग फुल स्क्रिन" @@ -133,12 +134,18 @@ "विन्डोहरू व्यवस्थापन गर्नुहोस्" "एस्पेक्ट रेसियो परिवर्तन गर्नुहोस्" "भ्यू अप्टिमाइज गर्नुहोस्" + "त्रुटि जनाउने आइकन" "बन्द गर्नुहोस्" "मेनु बन्द गर्नुहोस्" "%1$s (डेस्कटप विन्डोइङ)" "स्क्रिन ठुलो बनाउनुहोस्" "आकार बदल्नुहोस्" "एप सारेर यहाँ ल्याउन सकिएन" + "एपको नयाँ विन्डो खोल्नुहोस्" + "एपको विन्डो बन्द गरिँदै छ" + "एपको विन्डो मिनिमाइज गरिँदै छ" + "%1$s (फोकस गरिएको)" + "%1$s (फोकस नगरिएको)" "इमर्सिभ" "रिस्टोर गर्नुहोस्" "ठुलो बनाउनुहोस्" diff --git a/wmshell/res/values-nl/strings.xml b/wmshell/res/values-nl/strings.xml index 19420bd07c..42d59593ba 100644 --- a/wmshell/res/values-nl/strings.xml +++ b/wmshell/res/values-nl/strings.xml @@ -36,6 +36,7 @@ "Deze app kan maar in 1 venster worden geopend" "App werkt mogelijk niet op een secundair scherm." "App kan niet op secundaire displays worden gestart." + "App ondersteunt geen bubbel" "Scheiding voor gesplitst scherm" "Scheiding voor gesplitst scherm" "Linkerscherm op volledig scherm" @@ -133,12 +134,18 @@ "Vensters beheren" "Beeldverhouding wijzigen" "Weergave optimaliseren" + "Fouticoon" "Sluiten" "Menu sluiten" "%1$s (desktopvensterfunctie)" "Scherm maximaliseren" "Formaat aanpassen" "Kan de app niet hierheen verplaatsen" + "Nieuw app-venster openen" + "App-venster sluiten" + "App-venster minimaliseren" + "%1$s (gefocust)" + "%1$s (niet gefocust)" "Immersief" "Herstellen" "Maximaliseren" diff --git a/wmshell/res/values-or/strings.xml b/wmshell/res/values-or/strings.xml index 9659dc69d9..d0229f4b21 100644 --- a/wmshell/res/values-or/strings.xml +++ b/wmshell/res/values-or/strings.xml @@ -36,6 +36,7 @@ "ଏହି ଆପକୁ କେବଳ 1ଟି ୱିଣ୍ଡୋରେ ଖୋଲାଯାଇପାରିବ" "ସେକେଣ୍ଡାରୀ ଡିସପ୍ଲେରେ ଆପ୍‍ କାମ ନକରିପାରେ।" "ସେକେଣ୍ଡାରୀ ଡିସପ୍ଲେରେ ଆପ୍‍ ଲଞ୍ଚ ସପୋର୍ଟ କରେ ନାହିଁ।" + "ଆପ ବବଲକୁ ସପୋର୍ଟ କରେ ନାହିଁ" "ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ଡିଭାଇଡର" "ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ଡିଭାଇଡର" "ବାମ ପଟକୁ ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍‍ କରନ୍ତୁ" @@ -133,12 +134,18 @@ "ୱିଣ୍ଡୋଗୁଡ଼ିକୁ ପରିଚାଳନା କରନ୍ତୁ" "ଚଉଡ଼ା ଓ ଉଚ୍ଚତାର ଅନୁପାତ ପରିବର୍ତ୍ତନ କରନ୍ତୁ" "ଭ୍ୟୁ ଅପ୍ଟିମାଇଜ କରନ୍ତୁ" + "ତ୍ରୁଟି ଆଇକନ" "ବନ୍ଦ କରନ୍ତୁ" "ମେନୁ ବନ୍ଦ କରନ୍ତୁ" "%1$s (ଡେସ୍କଟପ ୱିଣ୍ଡୋଇଂ)" "ସ୍କ୍ରିନକୁ ବଡ଼ କରନ୍ତୁ" "ରିସାଇଜ କରନ୍ତୁ" "ଆପକୁ ଏଠାକୁ ମୁଭ କରାଯାଇପାରିବ ନାହିଁ" + "ନୂଆ ଆପ ୱିଣ୍ଡୋ ଖୋଲୁଛି" + "ଆପ ୱିଣ୍ଡୋକୁ ବନ୍ଦ କରାଯାଉଛି" + "ଆପ ୱିଣ୍ଡୋକୁ ଛୋଟ କରନ୍ତୁ" + "%1$s (ଫୋକସ କରାଯାଇଛି)" + "%1$s (ଫୋକସ କରାଯାଇନାହିଁ)" "ଇମର୍ସିଭ" "ରିଷ୍ଟୋର କରନ୍ତୁ" "ବଡ଼ କରନ୍ତୁ" diff --git a/wmshell/res/values-pa/strings.xml b/wmshell/res/values-pa/strings.xml index 9e34af5c48..7740560f63 100644 --- a/wmshell/res/values-pa/strings.xml +++ b/wmshell/res/values-pa/strings.xml @@ -36,6 +36,7 @@ "ਇਹ ਐਪ ਸਿਰਫ਼ 1 ਵਿੰਡੋ ਵਿੱਚ ਖੋਲ੍ਹੀ ਜਾ ਸਕਦੀ ਹੈ" "ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਸੈਕੰਡਰੀ ਡਿਸਪਲੇ \'ਤੇ ਕੰਮ ਨਾ ਕਰੇ।" "ਐਪ ਸੈਕੰਡਰੀ ਡਿਸਪਲੇਆਂ \'ਤੇ ਲਾਂਚ ਕਰਨ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ" + "ਐਪ ਬਬਲ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ" "ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਵਿਭਾਜਕ" "ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਵਿਭਾਜਕ" "ਖੱਬੇ ਪੂਰੀ ਸਕ੍ਰੀਨ" @@ -133,12 +134,18 @@ "ਵਿੰਡੋਆਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ" "ਆਕਾਰ ਅਨੁਪਾਤ ਬਦਲੋ" "ਦ੍ਰਿਸ਼ ਨੂੰ ਸੁਯੋਗ ਬਣਾਓ" + "ਗੜਬੜ ਪ੍ਰਤੀਕ" "ਬੰਦ ਕਰੋ" "ਮੀਨੂ ਬੰਦ ਕਰੋ" "%1$s (ਡੈਸਕਟਾਪ ਵਿੰਡੋ)" "ਸਕ੍ਰੀਨ ਦਾ ਆਕਾਰ ਵਧਾਓ" "ਆਕਾਰ ਬਦਲੋ" "ਐਪ ਨੂੰ ਇੱਥੇ ਨਹੀਂ ਲਿਜਾਇਆ ਜਾ ਸਕਦਾ" + "ਨਵੀਂ ਐਪ ਵਿੰਡੋ ਨੂੰ ਖੋਲ੍ਹਿਆ ਜਾ ਰਿਹਾ ਹੈ" + "ਐਪ ਵਿੰਡੋ ਨੂੰ ਬੰਦ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ" + "ਐਪ ਵਿੰਡੋ ਨੂੰ ਛੋਟਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ" + "%1$s (ਫੋਕਸ ਵਿੱਚ ਹੈ)" + "%1$s (ਫੋਕਸ ਵਿੱਚ ਨਹੀਂ ਹੈ)" "ਇਮਰਸਿਵ" "ਮੁੜ-ਬਹਾਲ ਕਰੋ" "ਵੱਡਾ ਕਰੋ" diff --git a/wmshell/res/values-pl/strings.xml b/wmshell/res/values-pl/strings.xml index 4c0613b358..f726b25305 100644 --- a/wmshell/res/values-pl/strings.xml +++ b/wmshell/res/values-pl/strings.xml @@ -36,6 +36,7 @@ "Ta aplikacja może być otwarta tylko w 1 oknie." "Aplikacja może nie działać na dodatkowym ekranie." "Aplikacja nie obsługuje uruchamiania na dodatkowych ekranach." + "Aplikacja nie obsługuje dymków" "Linia dzielenia ekranu" "Linia dzielenia ekranu" "Lewa część ekranu na pełnym ekranie" @@ -133,12 +134,18 @@ "Zarządzaj oknami" "Zmień format obrazu" "Zoptymalizuj widok" + "Ikona błędu" "Zamknij" "Zamknij menu" "%1$s (tryb okien na pulpicie)" "Maksymalizuj ekran" "Zmień rozmiar" "Nie można przenieść aplikacji tutaj" + "Otwarto nowe okno aplikacji" + "Zamykanie okna aplikacji" + "Zminimalizowano okno aplikacji" + "%1$s (aktywne okno)" + "%1$s (nieaktywne okno)" "Tryb immersyjny" "Przywróć" "Maksymalizuj" diff --git a/wmshell/res/values-pt-rBR/strings.xml b/wmshell/res/values-pt-rBR/strings.xml index 1c2a3fa490..ef3b68f9a0 100644 --- a/wmshell/res/values-pt-rBR/strings.xml +++ b/wmshell/res/values-pt-rBR/strings.xml @@ -36,6 +36,7 @@ "Esse app só pode ser aberto em uma única janela" "É possível que o app não funcione em uma tela secundária." "O app não é compatível com a inicialização em telas secundárias." + "O app é incompatível com balões" "Divisor de tela" "Divisor de tela" "Lado esquerdo em tela cheia" @@ -133,12 +134,18 @@ "Gerenciar janelas" "Mudar a proporção" "Visualização otimizada" + "Ícone de erro" "Fechar" "Fechar menu" "%1$s (modo janela para computador)" "Ampliar tela" "Redimensionar" "Não é possível mover o app para cá" + "Abrindo uma nova janela do app" + "Fechando a janela do app" + "Minimizando a janela do app" + "%1$s (em primeiro plano)" + "%1$s (em segundo plano)" "Imersivo" "Restaurar" "Maximizar" diff --git a/wmshell/res/values-pt-rPT/strings.xml b/wmshell/res/values-pt-rPT/strings.xml index ca1005d78d..ccfaa0a86b 100644 --- a/wmshell/res/values-pt-rPT/strings.xml +++ b/wmshell/res/values-pt-rPT/strings.xml @@ -36,6 +36,7 @@ "Esta app só pode ser aberta em 1 janela" "A app pode não funcionar num ecrã secundário." "A app não é compatível com o início em ecrãs secundários." + "A app não é compatível com o balão" "Divisor do ecrã dividido" "Divisor do ecrã dividido" "Ecrã esquerdo inteiro" @@ -133,12 +134,18 @@ "Gerir janelas" "Alterar formato" "Otimizar vista" + "Ícone de erro" "Fechar" "Fechar menu" "%1$s (janelas de computador)" "Maximizar ecrã" "Redimensionar" "Não é possível mover a app para aqui" + "A abrir a nova janela da app" + "A fechar a janela da app" + "A minimizar a janela da app" + "%1$s (com foco)" + "%1$s (sem foco)" "Envolvente" "Restaurar" "Maximizar" diff --git a/wmshell/res/values-pt/strings.xml b/wmshell/res/values-pt/strings.xml index 1c2a3fa490..ef3b68f9a0 100644 --- a/wmshell/res/values-pt/strings.xml +++ b/wmshell/res/values-pt/strings.xml @@ -36,6 +36,7 @@ "Esse app só pode ser aberto em uma única janela" "É possível que o app não funcione em uma tela secundária." "O app não é compatível com a inicialização em telas secundárias." + "O app é incompatível com balões" "Divisor de tela" "Divisor de tela" "Lado esquerdo em tela cheia" @@ -133,12 +134,18 @@ "Gerenciar janelas" "Mudar a proporção" "Visualização otimizada" + "Ícone de erro" "Fechar" "Fechar menu" "%1$s (modo janela para computador)" "Ampliar tela" "Redimensionar" "Não é possível mover o app para cá" + "Abrindo uma nova janela do app" + "Fechando a janela do app" + "Minimizando a janela do app" + "%1$s (em primeiro plano)" + "%1$s (em segundo plano)" "Imersivo" "Restaurar" "Maximizar" diff --git a/wmshell/res/values-ro/strings.xml b/wmshell/res/values-ro/strings.xml index d09da5be59..0fc2f79b4f 100644 --- a/wmshell/res/values-ro/strings.xml +++ b/wmshell/res/values-ro/strings.xml @@ -36,6 +36,7 @@ "Aplicația se poate deschide într-o singură fereastră" "Este posibil ca aplicația să nu funcționeze pe un ecran secundar." "Aplicația nu acceptă lansare pe ecrane secundare." + "Aplicația nu acceptă baloane" "Separator pentru ecranul împărțit" "Separator pentru ecranul împărțit" "Partea stângă pe ecran complet" @@ -133,12 +134,18 @@ "Gestionează ferestrele" "Schimbă raportul de dimensiuni" "Optimizează afișarea" + "Pictogramă de eroare" "Închide" "Închide meniul" "%1$s (ferestre pe desktop)" "Maximizează fereastra" "Redimensionează" "Aplicația nu poate fi mutată aici" + "Se deschide o fereastră nouă a aplicației" + "Se închide fereastra aplicației" + "Se minimizează fereastra aplicației" + "%1$s (Focalizată)" + "%1$s (Nefocalizată)" "Captivant" "Restabilește" "Maximizează" diff --git a/wmshell/res/values-ru/strings.xml b/wmshell/res/values-ru/strings.xml index d9ff3075c4..d24e14093c 100644 --- a/wmshell/res/values-ru/strings.xml +++ b/wmshell/res/values-ru/strings.xml @@ -36,6 +36,7 @@ "Это приложение можно открыть только в одном окне." "Приложение может не работать на дополнительном экране" "Приложение не поддерживает запуск на дополнительных экранах" + "Приложение не поддерживает всплывающие чаты." "Разделитель экрана" "Разделитель экрана" "Левый во весь экран" @@ -100,7 +101,7 @@ "Не помогло?\nНажмите, чтобы отменить изменения." "Нет проблем с камерой? Нажмите, чтобы закрыть." "Здесь вы найдете меню приложения" - "Чтобы открыть сразу несколько приложений, перейдите в режим компьютерных окон" + "Чтобы открыть сразу несколько приложений, перейдите в многооконный режим" "Вернуться в полноэкранный режим можно из меню приложения" "Выполняйте несколько задач одновременно" "Перетащите сюда другое приложение, чтобы использовать разделение экрана." @@ -121,7 +122,7 @@ "Обозначение приложения" "Значок приложения" "Полноэкранный режим" - "Режим компьютерных окон" + "Многооконный режим" "Разделить экран" "Ещё" "Плавающее окно" @@ -133,12 +134,18 @@ "Управление окнами" "Изменить соотношение сторон" "Оптимизировать" + "Значок ошибки" "Закрыть" "Закрыть меню" - "%1$s (режим компьютерных окон)" + "%1$s (многооконный режим)" "Развернуть на весь экран" "Изменить размер" "Приложение нельзя сюда переместить" + "Открывается новое окно приложения" + "Закрытие окна приложения…" + "Сворачивается окно приложения" + "Приложение \"%1$s\" выбрано" + "Приложение \"%1$s\" не выбрано" "Погружение" "Восстановить" "Развернуть" diff --git a/wmshell/res/values-si/strings.xml b/wmshell/res/values-si/strings.xml index 32daf89d5b..804fa30d62 100644 --- a/wmshell/res/values-si/strings.xml +++ b/wmshell/res/values-si/strings.xml @@ -36,6 +36,7 @@ "මෙම යෙදුම විවෘත කළ හැක්කේ 1 කවුළුවක පමණයි" "යෙදුම ද්විතියික සංදර්ශකයක ක්‍රියා නොකළ හැකිය." "යෙදුම ද්විතීයික සංදර්ශක මත දියත් කිරීම සඳහා සහාය නොදක්වයි." + "යෙදුම බුබුලට සහාය නොදක්වයි" "බෙදුම් තිර වෙන්කරණය" "බෙදුම් තිර වෙන්කරණය" "වම් පූර්ණ තිරය" @@ -133,12 +134,18 @@ "කවුළු කළමනාකරණය කරන්න" "දර්ශන අනුපාතය වෙනස් කරන්න" "දසුන ප්‍රශස්ත කරන්න" + "දෝෂ නිරූපකය" "වසන්න" "මෙනුව වසන්න" "%1$s (ඩෙස්ක්ටොප් කවුළුකරණය)" "තිරය උපරිම කරන්න" "ප්‍රතිප්‍රමාණය කරන්න" "යෙදුම මෙතැනට ගෙන යා නොහැක" + "නව යෙදුම් කවුළුව විවෘත කිරීම" + "යෙදුම් කවුළුව වැසීම" + "යෙදුම් කවුළුව අවම කිරීම" + "%1$s (අවධානිත)" + "%1$s (අවධානිත නොවේ)" "ගිලෙන සුළු" "ප්‍රතිසාධනය කරන්න" "විහිදන්න" diff --git a/wmshell/res/values-sk/strings.xml b/wmshell/res/values-sk/strings.xml index fd5c7a7518..2d90b2c0df 100644 --- a/wmshell/res/values-sk/strings.xml +++ b/wmshell/res/values-sk/strings.xml @@ -36,6 +36,7 @@ "Táto aplikácia môže byť otvorená iba v jednom okne" "Aplikácia nemusí fungovať na sekundárnej obrazovke." "Aplikácia nepodporuje spúšťanie na sekundárnych obrazovkách." + "Aplikácia bublinu nepodporuje" "Rozdeľovač obrazovky" "Rozdeľovač obrazovky" "Ľavá – na celú obrazovku" @@ -133,12 +134,18 @@ "Spravovať okná" "Zmeniť pomer strán" "Optimalizovať zobrazenie" + "Ikona chyby" "Zavrieť" "Zavrieť ponuku" "%1$s (windowing na pracovnej ploche)" "Maximalizovať obrazovku" "Zmeniť veľkosť" "Aplikácia sa sem nedá presunúť" + "Otvára sa nové okno aplikácie" + "Zatvára sa okno aplikácie" + "Minimalizuje sa okno aplikácie" + "%1$s (označené)" + "%1$s (neoznačené)" "Pútavé" "Obnoviť" "Maximalizovať" diff --git a/wmshell/res/values-sl/strings.xml b/wmshell/res/values-sl/strings.xml index 15a4589095..a8f6081126 100644 --- a/wmshell/res/values-sl/strings.xml +++ b/wmshell/res/values-sl/strings.xml @@ -36,6 +36,7 @@ "To aplikacijo je mogoče odpreti samo v enem oknu" "Aplikacija morda ne bo delovala na sekundarnem zaslonu." "Aplikacija ne podpira zagona na sekundarnih zaslonih." + "Aplikacija ne podpira oblačka" "Razdelilnik zaslonov" "Razdelilnik zaslonov" "Levi v celozaslonski način" @@ -133,12 +134,18 @@ "Upravljanje oken" "Sprememba razmerja stranic" "Optimizacija pogleda" + "Ikona za napako" "Zapri" "Zapri meni" "%1$s (namizni način prikaza več oken hkrati)" "Maksimiraj zaslon" "Spremeni velikost" "Aplikacije ni mogoče premakniti sem" + "Odpiranje novega okna aplikacije" + "Zapiranje okna aplikacije" + "Minimiranje okna aplikacije" + "%1$s (v fokusu)" + "%1$s (ni v fokusu)" "Poglobljeno" "Obnovi" "Maksimiraj" diff --git a/wmshell/res/values-sq/strings.xml b/wmshell/res/values-sq/strings.xml index 77316aa860..c3d8978a81 100644 --- a/wmshell/res/values-sq/strings.xml +++ b/wmshell/res/values-sq/strings.xml @@ -36,6 +36,7 @@ "Ky aplikacion mund të hapet vetëm në 1 dritare" "Aplikacioni mund të mos funksionojë në një ekran dytësor." "Aplikacioni nuk mbështet nisjen në ekrane dytësore." + "Aplikacioni nuk e mbështet flluskën" "Ndarësi i ekranit të ndarë" "Ndarësi i ekranit të ndarë" "Ekrani i plotë majtas" @@ -133,12 +134,18 @@ "Menaxho dritaret" "Ndrysho raportin e pamjes" "Optimizo pamjen" + "Ikona e gabimit" "Mbyll" "Mbyll menynë" "%1$s (modaliteti me dritare si në desktop)" "Maksimizo ekranin" "Ndrysho përmasat" "Aplikacioni nuk mund të zhvendoset këtu" + "Po hapet një dritare e re e aplikacionit" + "Po mbyllet dritarja e aplikacionit" + "Dritarja e aplikacionit po minimizohet" + "%1$s (në fokus)" + "%1$s (jo në fokus)" "Përfshirës" "Restauro" "Maksimizo" diff --git a/wmshell/res/values-sr/strings.xml b/wmshell/res/values-sr/strings.xml index 66bc2a62ae..d3b5911f90 100644 --- a/wmshell/res/values-sr/strings.xml +++ b/wmshell/res/values-sr/strings.xml @@ -36,6 +36,7 @@ "Ова апликација може да се отвори само у једном прозору" "Апликација можда неће функционисати на секундарном екрану." "Апликација не подржава покретање на секундарним екранима." + "Апликација не подржава облачић" "Разделник подељеног екрана" "Разделник подељеног екрана" "Режим целог екрана за леви екран" @@ -77,14 +78,14 @@ "Одбаци облачић" "Пребаци на цео екран" "Не користи облачиће за конверзацију" - "Ћаскајте у облачићима" + "Четујте у облачићима" "Нове конверзације се приказују као плутајуће иконе или облачићи. Додирните да бисте отворили облачић. Превуците да бисте га преместили." "Контролишите облачиће у било ком тренутку" "Додирните Управљајте да бисте искључили облачиће из ове апликације" "Важи" "Нема недавних облачића" "Овде се приказују недавни и одбачени облачићи" - "Ћаскајте у облачићима" + "Четујте у облачићима" "Нове конверзације се појављују као иконе у доњем углу екрана. Додирните да бисте их проширили или превуците да бисте их одбацили." "Контролишите облачиће у сваком тренутку" "Додирните овде и одредите које апликације и конверзације могу да имају облачић" @@ -133,12 +134,18 @@ "Управљајте прозорима" "Промени размеру" "Оптимизујте приказ" + "Икона грешке" "Затворите" "Затворите мени" "%1$s (приказ рачунарских прозора)" "Повећај екран" "Прилагоди" "Апликација не може да се премести овде" + "Отвара се нови прозор апликације" + "Затвара се прозор апликације" + "Умањује се прозор апликације" + "%1$s (фокусирано)" + "%1$s (није фокусирано)" "Имерзивно" "Врати" "Увећај" diff --git a/wmshell/res/values-sv/strings.xml b/wmshell/res/values-sv/strings.xml index 2e77f642b7..12de73a01a 100644 --- a/wmshell/res/values-sv/strings.xml +++ b/wmshell/res/values-sv/strings.xml @@ -36,6 +36,7 @@ "Denna app kan bara vara öppen i ett fönster" "Appen kanske inte fungerar på en sekundär skärm." "Appen kan inte köras på en sekundär skärm." + "Appen har inte stöd för bubbla" "Avdelare för delad skärm" "Avdelare för delad skärm" "Helskärm på vänster skärm" @@ -104,7 +105,7 @@ "Återgå till helskärm när som helst från appmenyn" "Se och gör mer" "Dra till en annan app för att dela upp skärmen" - "Tryck snabbt två gånger utanför en app för att flytta den" + "Dubbeltryck utanför en app för att flytta den" "OK" "Utöka för mer information." "Vill du starta om för en bättre vy?" @@ -112,7 +113,7 @@ "Avbryt" "Starta om" "Visa inte igen" - "Tryck snabbt två gånger\nför att flytta denna app" + "Dubbeltryck\nför att flytta denna app" "Utöka %1$s" "Återställ %1$s" "Minimera %1$s" @@ -133,12 +134,18 @@ "Hantera fönster" "Ändra bildformat" "Optimera vy" + "Felikon" "Stäng" "Stäng menyn" "%1$s (fönsterstapling)" "Maximera skärmen" "Ändra storlek" "Det går inte att flytta appen hit" + "Öppnar nytt appfönster" + "Stänger appfönstret" + "Minimerar appfönstret" + "%1$s (i fokus)" + "%1$s (inte i fokus)" "Immersiv" "Återställ" "Utöka" diff --git a/wmshell/res/values-sw/strings.xml b/wmshell/res/values-sw/strings.xml index 3b113375e7..f647be60ed 100644 --- a/wmshell/res/values-sw/strings.xml +++ b/wmshell/res/values-sw/strings.xml @@ -36,6 +36,7 @@ "Programu hii inaweza kufunguliwa katika dirisha 1 pekee" "Huenda programu isifanye kazi kwenye dirisha lingine." "Programu hii haiwezi kufunguliwa kwenye madirisha mengine." + "Programu haitumii kiputo" "Kitenganishi cha kugawa skrini" "Kitenganishi cha kugawa skrini" "Skrini nzima ya kushoto" @@ -133,12 +134,18 @@ "Dhibiti Windows" "Badilisha uwiano" "Boresha Mwonekano" + "Aikoni ya Hitilafu" "Funga" "Funga Menyu" "%1$s (Kupanga madirisha ya kompyuta ya mezani)" "Panua Dirisha kwenye Skrini" "Badilisha ukubwa" "Imeshindwa kuhamishia programu hapa" + "Kufungua dirisha jipya la programu" + "Inafunga dirisha la programu" + "Kupunguza dirisha la programu" + "%1$s (Imeangaziwa)" + "%1$s (Haiangaziwi)" "Shirikishi" "Rejesha" "Panua" diff --git a/wmshell/res/values-ta/strings.xml b/wmshell/res/values-ta/strings.xml index 4ed3927900..8dcd767fb6 100644 --- a/wmshell/res/values-ta/strings.xml +++ b/wmshell/res/values-ta/strings.xml @@ -36,6 +36,7 @@ "இந்த ஆப்ஸை 1 சாளரத்தில் மட்டுமே திறக்க முடியும்" "இரண்டாம்நிலைத் திரையில் ஆப்ஸ் வேலை செய்யாமல் போகக்கூடும்." "இரண்டாம்நிலைத் திரைகளில் பயன்பாட்டைத் தொடங்க முடியாது." + "குமிழை ஆப்ஸ் ஆதரிப்பதில்லை" "திரைப் பிரிப்பான்" "திரைப் பிரிப்பான்" "இடது புறம் முழுத் திரை" @@ -97,7 +98,7 @@ "அமைப்புகளில் இந்த ஆப்ஸின் தோற்ற விகிதத்தை மாற்றும்" "தோற்ற விகிதத்தை மாற்றும்" "கேமரா தொடர்பான சிக்கல்களா?\nமீண்டும் பொருத்த தட்டவும்" - "சிக்கல்கள் சரிசெய்யப்படவில்லையா?\nமாற்றியமைக்க தட்டவும்" + "சிக்கல்கள் சரிசெய்யப்படவில்லையா?\nமுன்போல் மாற்ற தட்டவும்" "கேமரா தொடர்பான சிக்கல்கள் எதுவும் இல்லையா? நிராகரிக்க தட்டவும்." "ஆப்ஸ் மெனுவை இங்கே பார்க்கலாம்" "பல ஆப்ஸை ஒன்றாகத் திறக்க டெஸ்க்டாப் சாளரமாக்குதலுக்குச் செல்லலாம்" @@ -133,12 +134,18 @@ "சாளரங்களை நிர்வகிக்கலாம்" "தோற்ற விகிதத்தை மாற்று" "காட்சியை மேம்படுத்தும்" + "பிழை ஐகான்" "மூடும்" "மெனுவை மூடும்" "%1$s (டெஸ்க்டாப் சாளரமாக்குதல்)" "திரையைப் பெரிதாக்கு" "அளவை மாற்று" "ஆப்ஸை இங்கே நகர்த்த முடியாது" + "புதிய ஆப்ஸ் சாளரத்தைத் திறக்கிறது" + "ஆப்ஸ் சாளரம் மூடப்படுகிறது" + "ஆப்ஸ் சாளரத்தைக் குறைக்கிறது" + "%1$s (மையப்படுத்தப்பட்டது)" + "%1$s (மையப்படுத்தப்படவில்லை)" "முழுத்திரையும்" "மீட்டெடுக்கும்" "பெரிதாக்கும்" diff --git a/wmshell/res/values-te/strings.xml b/wmshell/res/values-te/strings.xml index d7f79ca472..d97f979e56 100644 --- a/wmshell/res/values-te/strings.xml +++ b/wmshell/res/values-te/strings.xml @@ -36,6 +36,7 @@ "ఈ యాప్‌ను 1 విండోలో మాత్రమే తెరవవచ్చు" "ప్రత్యామ్నాయ డిస్‌ప్లేలో యాప్ పని చేయకపోవచ్చు." "ప్రత్యామ్నాయ డిస్‌ప్లేల్లో ప్రారంభానికి యాప్ మద్దతు లేదు." + "యాప్ బబుల్‌ను సపోర్ట్ చేయట్లేదు" "స్ప్లిట్ స్క్రీన్ డివైడర్" "స్ప్లిట్ స్క్రీన్ డివైడర్" "ఎడమవైపు ఫుల్-స్క్రీన్‌" @@ -133,12 +134,18 @@ "విండోలను మేనేజ్ చేయండి" "ఆకార నిష్పత్తిని మార్చండి" "వీక్షణను ఆప్టిమైజ్ చేయండి" + "ఎర్రర్ చిహ్నం" "మూసివేయండి" "మెనూను మూసివేయండి" "%1$s (డెస్క్‌టాప్ వీక్షణ)" "స్క్రీన్ సైజ్‌ను పెంచండి" "సైజ్ మార్చండి" "యాప్‌ను ఇక్కడకి తరలించడం సాధ్యం కాదు" + "కొత్త యాప్ విండోను తెరుస్తోంది" + "యాప్ విండోను మూసివేస్తోంది" + "యాప్ విండోను మినిమైజ్ చేస్తోంది" + "%1$s (ఫోకస్డ్)" + "%1$s (ఫోకస్డ్‌గా లేదు)" "లీనమయ్యే" "రీస్టోర్ చేయండి" "మ్యాగ్జిమైజ్ చేయండి" diff --git a/wmshell/res/values-th/strings.xml b/wmshell/res/values-th/strings.xml index cb456cbd6d..c34b76569a 100644 --- a/wmshell/res/values-th/strings.xml +++ b/wmshell/res/values-th/strings.xml @@ -36,6 +36,7 @@ "แอปนี้เปิดได้ใน 1 หน้าต่างเท่านั้น" "แอปอาจไม่ทำงานในจอแสดงผลรอง" "แอปไม่รองรับการเรียกใช้ในจอแสดงผลรอง" + "แอปไม่รองรับบับเบิล" "เส้นแยกหน้าจอ" "เส้นแยกหน้าจอ" "เต็มหน้าจอทางซ้าย" @@ -133,12 +134,18 @@ "จัดการหน้าต่าง" "เปลี่ยนสัดส่วนการแสดงผล" "เพิ่มประสิทธิภาพมุมมอง" + "ไอคอนข้อผิดพลาด" "ปิด" "ปิดเมนู" "%1$s (หน้าต่างเดสก์ท็อป)" "ขยายหน้าจอให้ใหญ่สุด" "ปรับขนาด" "ย้ายแอปมาที่นี่ไม่ได้" + "กำลังเปิดหน้าต่างแอปใหม่" + "กำลังปิดหน้าต่างแอป" + "กำลังย่อหน้าต่างแอป" + "%1$s (โฟกัสอยู่)" + "%1$s (ไม่โฟกัส)" "สมจริง" "คืนค่า" "ขยายใหญ่สุด" diff --git a/wmshell/res/values-tl/strings.xml b/wmshell/res/values-tl/strings.xml index 83a7470251..58db934acd 100644 --- a/wmshell/res/values-tl/strings.xml +++ b/wmshell/res/values-tl/strings.xml @@ -36,6 +36,7 @@ "Sa 1 window lang puwedeng buksan ang app na ito" "Maaaring hindi gumana ang app sa pangalawang display." "Hindi sinusuportahan ng app ang paglulunsad sa mga pangalawang display." + "Hindi sinusuportahan ng app ang bubble" "Divider ng split screen" "Divider ng split screen" "I-full screen ang nasa kaliwa" @@ -133,12 +134,18 @@ "Pamahalaan ang Mga Window" "Baguhin ang aspect ratio" "I-optimize ang View" + "Icon ng Error" "Isara" "Isara ang Menu" "%1$s (Desktop windowing)" "I-maximize ang Screen" "I-resize" "Hindi mailipat dito ang app" + "Nagbubukas ng bagong window ng app" + "Isinasara ang window ng app" + "Mini-minimize ang window ng app" + "%1$s (Naka-focus)" + "%1$s (Hindi Naka-focus)" "Immersive" "I-restore" "I-maximize" diff --git a/wmshell/res/values-tr/strings.xml b/wmshell/res/values-tr/strings.xml index 3d565bc028..540632be7c 100644 --- a/wmshell/res/values-tr/strings.xml +++ b/wmshell/res/values-tr/strings.xml @@ -36,6 +36,7 @@ "Bu uygulama yalnızca 1 pencerede açılabilir" "Uygulama ikincil ekranda çalışmayabilir." "Uygulama ikincil ekranlarda başlatılmayı desteklemiyor." + "Uygulama, balonu desteklemiyor" "Bölünmüş ekran ayırıcı" "Bölünmüş ekran ayırıcı" "Solda tam ekran" @@ -133,12 +134,18 @@ "Pencereleri yönet" "En boy oranını değiştir" "Görünümü Optimize Et" + "Hata Simgesi" "Kapat" "Menüyü kapat" "%1$s (masaüstü pencereleme)" "Ekranı Büyüt" "Yeniden boyutlandır" "Uygulama buraya taşınamıyor" + "Yeni uygulama penceresi açılıyor" + "Uygulama penceresi kapatılıyor" + "Uygulama penceresi simge durumuna küçültülüyor" + "%1$s (Odaklanmış)" + "%1$s (Odaklanmamış)" "Tam ekran" "Geri yükle" "Ekranı kapla" diff --git a/wmshell/res/values-uk/strings.xml b/wmshell/res/values-uk/strings.xml index 6888497324..b42c50f31d 100644 --- a/wmshell/res/values-uk/strings.xml +++ b/wmshell/res/values-uk/strings.xml @@ -36,6 +36,7 @@ "Цей додаток можна відкрити лише в одному вікні" "Додаток може не працювати на додатковому екрані." "Додаток не підтримує запуск на додаткових екранах." + "Додаток не підтримує спливаючі чати" "Розділювач екрана" "Розділювач екрана" "Ліве вікно на весь екран" @@ -133,12 +134,18 @@ "Керувати вікнами" "Змінити формат" "Оптимізувати перегляд" + "Значок помилки" "Закрити" "Закрити меню" "%1$s (режим вікон робочого стола)" "Розгорнути екран" "Змінити розмір" "Сюди не можна перемістити додаток" + "Відкриття нового вікна додатка" + "Закриття вікна додатка" + "Згортання вікна додатка" + "%1$s (виділено)" + "%1$s (не виділено)" "Реалістичність" "Відновити" "Розгорнути" diff --git a/wmshell/res/values-ur/strings.xml b/wmshell/res/values-ur/strings.xml index cf16e77272..53fd8100cb 100644 --- a/wmshell/res/values-ur/strings.xml +++ b/wmshell/res/values-ur/strings.xml @@ -36,6 +36,7 @@ "یہ ایپ صرف 1 ونڈو میں کھولی جا سکتی ہے" "ممکن ہے ایپ ثانوی ڈسپلے پر کام نہ کرے۔" "ایپ ثانوی ڈسپلیز پر شروعات کا تعاون نہیں کرتی۔" + "ایپ ببل کو سپورٹ نہیں کرتی ہے" "اسپلٹ اسکرین ڈیوائیڈر" "اسپلٹ اسکرین ڈیوائیڈر" "بائیں فل اسکرین" @@ -133,12 +134,18 @@ "ونڈوز کا نظم کریں" "تناسبی شرح کو تبدیل کریں" "منظر کو بہتر بنائیں" + "خرابی کا آئیکن" "بند کریں" "مینیو بند کریں" "%1$s (ڈیسک ٹاپ ونڈوئنگ)" "اسکرین کو بڑا کریں" "سائز تبدیل کریں" "ایپ کو یہاں منتقل نہیں کیا جا سکتا" + "نئی ایپ ونڈو کھل رہی ہے" + "ایپ ونڈو بند ہو رہی ہے" + "ایپ ونڈو چھوٹی ہو رہی ہے" + "‫%1$s (فوکس کردہ)" + "‫%1$s (فوکس کردہ نہیں)" "عمیق" "بحال کریں" "بڑا کریں" diff --git a/wmshell/res/values-uz/strings.xml b/wmshell/res/values-uz/strings.xml index 9b1e30ee8f..8e2c245078 100644 --- a/wmshell/res/values-uz/strings.xml +++ b/wmshell/res/values-uz/strings.xml @@ -36,6 +36,7 @@ "Bu ilovani faqat 1 ta oynada ochish mumkin" "Bu ilova qo‘shimcha ekranda ishlamasligi mumkin." "Bu ilova qo‘shimcha ekranlarda ishga tushmaydi." + "Ilovada bulutcha ishlamaydi" "Ekranni ikkiga ajratish chizigʻi" "Ekranni ikkiga ajratish chizigʻi" "Chapda to‘liq ekran" @@ -133,12 +134,18 @@ "Oynalarni boshqarish" "Tomonlar nisbatini oʻzgartirish" "Koʻrinishni optimallashtirish" + "Xatolik belgisi" "Yopish" "Menyuni yopish" "%1$s (Desktop rejimidagi oynalar)" "Ekranni yoyish" "Oʻlchamini oʻzgartirish" "Ilova bu yerga surilmaydi" + "Yangi ilova oynasi ochilmoqda" + "Ilova oynasi yopilmoqda" + "Ilova oynasi kichraytirilmoqda" + "%1$s (fokuslangan)" + "%1$s (fokuslanmagan)" "Immersiv" "Tiklash" "Yoyish" diff --git a/wmshell/res/values-vi/strings.xml b/wmshell/res/values-vi/strings.xml index 4397ccddc4..dd4066dfac 100644 --- a/wmshell/res/values-vi/strings.xml +++ b/wmshell/res/values-vi/strings.xml @@ -36,6 +36,7 @@ "Ứng dụng này chỉ có thể mở trong 1 cửa sổ" "Ứng dụng có thể không hoạt động trên màn hình phụ." "Ứng dụng không hỗ trợ khởi chạy trên màn hình phụ." + "Ứng dụng không hỗ trợ bong bóng" "Trình chia đôi màn hình" "Trình chia đôi màn hình" "Toàn màn hình bên trái" @@ -133,12 +134,18 @@ "Quản lý cửa sổ" "Thay đổi tỷ lệ khung hình" "Tối ưu hoá chế độ xem" + "Biểu tượng lỗi" "Đóng" "Đóng trình đơn" "%1$s (Chế độ cửa sổ trên máy tính)" "Mở rộng màn hình" "Đổi kích thước" "Không di chuyển được ứng dụng đến đây" + "Đang mở cửa sổ ứng dụng mới" + "Đang đóng cửa sổ ứng dụng" + "Đang thu nhỏ cửa sổ ứng dụng" + "%1$s (Đã lấy tiêu điểm)" + "%1$s (Chưa lấy tiêu điểm)" "Hiển thị tối đa" "Khôi phục" "Phóng to tối đa" diff --git a/wmshell/res/values-zh-rCN/strings.xml b/wmshell/res/values-zh-rCN/strings.xml index 6986115d24..14ac1c39b8 100644 --- a/wmshell/res/values-zh-rCN/strings.xml +++ b/wmshell/res/values-zh-rCN/strings.xml @@ -36,6 +36,7 @@ "此应用只能在 1 个窗口中打开" "应用可能无法在辅显示屏上正常运行。" "应用不支持在辅显示屏上启动。" + "该应用不支持气泡框" "分屏分隔线" "分屏分隔线" "左侧全屏" @@ -133,12 +134,18 @@ "管理窗口" "更改宽高比" "优化视图" + "错误图标" "关闭" "关闭菜单" "%1$s(窗口化模式)" "最大化屏幕" "调整大小" "无法将应用移至此处" + "正在打开新的应用窗口" + "正在关闭应用窗口" + "正在最小化应用窗口" + "%1$s(已聚焦)" + "%1$s(未聚焦)" "沉浸式" "恢复" "最大化" diff --git a/wmshell/res/values-zh-rHK/strings.xml b/wmshell/res/values-zh-rHK/strings.xml index 6252efb375..62e46db899 100644 --- a/wmshell/res/values-zh-rHK/strings.xml +++ b/wmshell/res/values-zh-rHK/strings.xml @@ -36,6 +36,7 @@ "此應用程式只可在 1 個視窗中開啟" "應用程式可能無法在次要顯示屏上運作。" "應用程式無法在次要顯示屏上啟動。" + "應用程式不支援小視窗" "分割螢幕分隔線" "分割螢幕分隔線" "左邊全螢幕" @@ -133,12 +134,18 @@ "管理視窗" "變更長寬比" "優化檢視模式" + "錯誤圖示" "關閉" "關閉選單" "%1$s (桌面電腦視窗模式)" "畫面最大化" "調整大小" "應用程式無法移至這裡" + "正在開啟新應用程式視窗" + "閂緊應用程式視窗" + "正在將應用程式視窗縮到最小" + "%1$s (焦點)" + "%1$s (非焦點)" "身歷其境" "還原" "最大化" diff --git a/wmshell/res/values-zh-rTW/strings.xml b/wmshell/res/values-zh-rTW/strings.xml index 3c230349fd..f36f616355 100644 --- a/wmshell/res/values-zh-rTW/strings.xml +++ b/wmshell/res/values-zh-rTW/strings.xml @@ -36,6 +36,7 @@ "這個應用程式只能在 1 個視窗中開啟" "應用程式可能無法在次要顯示器上運作。" "應用程式無法在次要顯示器上啟動。" + "應用程式不支援泡泡" "分割畫面分隔線" "分割畫面分隔線" "以全螢幕顯示左側畫面" @@ -133,12 +134,18 @@ "管理視窗" "變更顯示比例" "最佳化檢視畫面" + "錯誤圖示" "關閉" "關閉選單" "%1$s (電腦分割視窗)" "畫面最大化" "調整大小" "應用程式無法移至此處" + "正在開啟新的應用程式視窗" + "正在關閉應用程式視窗" + "正在最小化應用程式視窗" + "%1$s (前景)" + "%1$s (背景)" "沉浸" "還原" "最大化" diff --git a/wmshell/res/values-zu/strings.xml b/wmshell/res/values-zu/strings.xml index 61dacd4b4a..1d20e40900 100644 --- a/wmshell/res/values-zu/strings.xml +++ b/wmshell/res/values-zu/strings.xml @@ -36,6 +36,7 @@ "Le-app ingavulwa kuphela ewindini eli-1." "Uhlelo lokusebenza kungenzeka lungasebenzi kusibonisi sesibili." "Uhlelo lokusebenza alusekeli ukuqalisa kuzibonisi zesibili." + "I-app ayilisekeli ibhamuza" "Isihlukanisi sokuhlukanisa isikrini" "Isihlukanisi sokuhlukanisa isikrini" "Isikrini esigcwele esingakwesokunxele" @@ -133,12 +134,18 @@ "Phatha Amawindi" "Shintsha ukubukeka kwesilinganiselo" "Lungiselela Ukubuka" + "Isithonjana Sephutha" "Vala" "Vala Imenyu" "%1$s (Ukwenziwa kwamawindi amaningi kwedeskithophu)" "Khulisa Isikrini Sifike Ekugcineni" "Shintsha usayizi" "I-app ayikwazi ukuhanjiswa lapha" + "Ivula iwindi elisha le-app" + "Ivala iwindi le-app" + "Ukunciphisa iwindi le-app" + "%1$s (Igxilile)" + "%1$s (Akugxilile)" "Okugxilile" "Buyisela" "Khulisa" diff --git a/wmshell/res/values/attrs.xml b/wmshell/res/values/attrs.xml index 4ba0468a74..94373906dd 100644 --- a/wmshell/res/values/attrs.xml +++ b/wmshell/res/values/attrs.xml @@ -30,4 +30,18 @@ + + + + + + + + + + + + + + diff --git a/wmshell/res/values/config.xml b/wmshell/res/values/config.xml index 59e6c7786c..9463d9cbc0 100644 --- a/wmshell/res/values/config.xml +++ b/wmshell/res/values/config.xml @@ -23,10 +23,6 @@ TODO(b/238217847): This config is temporary until we refactor the base WMComponent. --> true - - true - 425 @@ -142,6 +138,10 @@ Needs to be less that or equal to 1. --> 0.5625 + + 0.75 + 0x55 diff --git a/wmshell/res/values/dimen.xml b/wmshell/res/values/dimen.xml index ca18c97f91..838c879d40 100644 --- a/wmshell/res/values/dimen.xml +++ b/wmshell/res/values/dimen.xml @@ -291,9 +291,6 @@ 28dp 24dp - 60dp - 24dp - 48dp 84dp 48dp @@ -306,6 +303,8 @@ 140dp 3dp + + 60dp 24dp @@ -662,6 +661,13 @@ 6dp + + 130dp + + 16dp + + 8dp + 8dp diff --git a/wmshell/res/values/strings.xml b/wmshell/res/values/strings.xml index 1fd4704f78..508f9dff30 100644 --- a/wmshell/res/values/strings.xml +++ b/wmshell/res/values/strings.xml @@ -74,6 +74,8 @@ App may not work on a secondary display. App does not support launch on secondary displays. + + App does not support bubble Split screen divider @@ -316,6 +318,8 @@ Change aspect ratio Optimize View + + Error Icon Close @@ -328,6 +332,18 @@ Resize App can\'t be moved here + + + Opening new app window + + Closing app window + + Minimizing app window + + %1$s (Focused) + + %1$s (Not Focused) + Immersive diff --git a/wmshell/res/values/styles.xml b/wmshell/res/values/styles.xml index 678a43e70c..b7030d96c6 100644 --- a/wmshell/res/values/styles.xml +++ b/wmshell/res/values/styles.xml @@ -43,8 +43,8 @@ @@ -113,23 +113,23 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wmshell/shared/src/com/android/wm/shell/shared/split/SplitBounds.java b/wmshell/shared/src/com/android/wm/shell/shared/split/SplitBounds.java index 7c1faa667d..5e17d75206 100644 --- a/wmshell/shared/src/com/android/wm/shell/shared/split/SplitBounds.java +++ b/wmshell/shared/src/com/android/wm/shell/shared/split/SplitBounds.java @@ -15,12 +15,18 @@ */ package com.android.wm.shell.shared.split; +import static android.app.ActivityTaskManager.INVALID_TASK_ID; + +import androidx.annotation.NonNull; import android.graphics.Rect; import android.os.Parcel; import android.os.Parcelable; import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Objects; /** @@ -47,13 +53,42 @@ public class SplitBounds implements Parcelable { * the bounds were originally in */ public final boolean appsStackedVertically; + /** + * If {@code true}, that means at the time of creation of this object, the phone was in + * seascape orientation. This is important on devices with insets, because they do not split + * evenly -- one of the insets must be slightly larger to account for the inset. + * From landscape, it is the leftTop task that expands slightly. + * From seascape, it is the rightBottom task that expands slightly. + */ + public final boolean initiatedFromSeascape; + /** @deprecated Use {@link #leftTopTaskIds} instead. */ + @Deprecated public final int leftTopTaskId; + /** @deprecated Use {@link #rightBottomTaskIds} instead. */ + @Deprecated public final int rightBottomTaskId; + @NonNull + public final List leftTopTaskIds; + @NonNull + public final List rightBottomTaskIds; - public SplitBounds(Rect leftTopBounds, Rect rightBottomBounds, int leftTopTaskId, - int rightBottomTaskId, @PersistentSnapPosition int snapPosition) { + public SplitBounds(Rect leftTopBounds, Rect rightBottomBounds, + int leftTopTaskId, int rightBottomTaskId, + @NonNull List leftTopTaskIds, @NonNull List rightBottomTaskIds, + @PersistentSnapPosition int snapPosition) { + if (leftTopTaskId == INVALID_TASK_ID || rightBottomTaskId == INVALID_TASK_ID + || leftTopTaskId == rightBottomTaskId + || leftTopTaskIds.isEmpty() || rightBottomTaskIds.isEmpty()) { + throw new IllegalArgumentException("The Split task ids are invalid:" + + " leftTopTaskId: " + leftTopTaskId + + " rightBottomTaskId: " + rightBottomTaskId + + " leftTopTaskId size: " + leftTopTaskIds.size() + + " rightBottomTaskId size: " + rightBottomTaskIds.size()); + } this.leftTopBounds = leftTopBounds; this.rightBottomBounds = rightBottomBounds; + this.leftTopTaskIds = List.copyOf(leftTopTaskIds); + this.rightBottomTaskIds = List.copyOf(rightBottomTaskIds); this.leftTopTaskId = leftTopTaskId; this.rightBottomTaskId = rightBottomTaskId; this.snapPosition = snapPosition; @@ -63,11 +98,18 @@ public class SplitBounds implements Parcelable { this.visualDividerBounds = new Rect(leftTopBounds.left, leftTopBounds.bottom, leftTopBounds.right, rightBottomBounds.top); appsStackedVertically = true; + initiatedFromSeascape = false; } else { // horizontal apps, vertical divider this.visualDividerBounds = new Rect(leftTopBounds.right, leftTopBounds.top, rightBottomBounds.left, leftTopBounds.bottom); appsStackedVertically = false; + // The following check is unreliable on devices without insets + // (initiatedFromSeascape will always be set to false.) This happens to be OK for + // all our current uses, but should be refactored. + // TODO: Create a more reliable check, or refactor how splitting works on devices + // with insets. + initiatedFromSeascape = rightBottomBounds.width() > leftTopBounds.width(); } float totalWidth = rightBottomBounds.right - leftTopBounds.left; @@ -78,6 +120,46 @@ public class SplitBounds implements Parcelable { dividerHeightPercent = visualDividerBounds.height() / totalHeight; } + public SplitBounds(Rect leftTopBounds, Rect rightBottomBounds, int leftTopTaskId, + int rightBottomTaskId, @PersistentSnapPosition int snapPosition) { + this(leftTopBounds, rightBottomBounds, leftTopTaskId, rightBottomTaskId, + Collections.singletonList(leftTopTaskId), + Collections.singletonList(rightBottomTaskId), snapPosition); + } + + /** + * Returns the percentage size of the left/top task (compared to the full width/height of + * the split pair). E.g. if the left task is 4 units wide, the divider is 2 units, and the + * right task is 4 units, this method will return 0.4f. + */ + public float getLeftTopTaskPercent() { + // topTaskPercent and leftTaskPercent are defined at creation time, and are not updated + // on device rotate, so we have to check appsStackedVertically to return the right + // creation-time measurements. + return appsStackedVertically ? topTaskPercent : leftTaskPercent; + } + + /** + * Returns the percentage size of the divider's thickness (compared to the full width/height + * of the split pair). E.g. if the left task is 4 units wide, the divider is 2 units, and + * the right task is 4 units, this method will return 0.2f. + */ + public float getDividerPercent() { + // dividerHeightPercent and dividerWidthPercent are defined at creation time, and are + // not updated on device rotate, so we have to check appsStackedVertically to return + // the right creation-time measurements. + return appsStackedVertically ? dividerHeightPercent : dividerWidthPercent; + } + + /** + * Returns the percentage size of the right/bottom task (compared to the full width/height + * of the split pair). E.g. if the left task is 4 units wide, the divider is 2 units, and + * the right task is 4 units, this method will return 0.4f. + */ + public float getRightBottomTaskPercent() { + return 1 - (getLeftTopTaskPercent() + getDividerPercent()); + } + public SplitBounds(Parcel parcel) { leftTopBounds = parcel.readTypedObject(Rect.CREATOR); rightBottomBounds = parcel.readTypedObject(Rect.CREATOR); @@ -85,11 +167,22 @@ public class SplitBounds implements Parcelable { topTaskPercent = parcel.readFloat(); leftTaskPercent = parcel.readFloat(); appsStackedVertically = parcel.readBoolean(); - leftTopTaskId = parcel.readInt(); - rightBottomTaskId = parcel.readInt(); + initiatedFromSeascape = parcel.readBoolean(); dividerWidthPercent = parcel.readFloat(); dividerHeightPercent = parcel.readFloat(); snapPosition = parcel.readInt(); + leftTopTaskId = parcel.readInt(); + rightBottomTaskId = parcel.readInt(); + int size = parcel.readInt(); + leftTopTaskIds = new ArrayList<>(); + for (int i = 0; i < size; i++) { + leftTopTaskIds.add(parcel.readInt()); + } + size = parcel.readInt(); + rightBottomTaskIds = new ArrayList<>(); + for (int i = 0; i < size; i++) { + rightBottomTaskIds.add(parcel.readInt()); + } } @Override @@ -100,11 +193,20 @@ public class SplitBounds implements Parcelable { parcel.writeFloat(topTaskPercent); parcel.writeFloat(leftTaskPercent); parcel.writeBoolean(appsStackedVertically); - parcel.writeInt(leftTopTaskId); - parcel.writeInt(rightBottomTaskId); + parcel.writeBoolean(initiatedFromSeascape); parcel.writeFloat(dividerWidthPercent); parcel.writeFloat(dividerHeightPercent); parcel.writeInt(snapPosition); + parcel.writeInt(leftTopTaskId); + parcel.writeInt(rightBottomTaskId); + parcel.writeInt(leftTopTaskIds.size()); + for (Integer id : leftTopTaskIds) { + parcel.writeInt(id); // Write each Integer in the List + } + parcel.writeInt(rightBottomTaskIds.size()); + for (Integer id : rightBottomTaskIds) { + parcel.writeInt(id); // Write each Integer in the List + } } @Override @@ -121,19 +223,23 @@ public class SplitBounds implements Parcelable { final SplitBounds other = (SplitBounds) obj; return Objects.equals(leftTopBounds, other.leftTopBounds) && Objects.equals(rightBottomBounds, other.rightBottomBounds) - && leftTopTaskId == other.leftTopTaskId - && rightBottomTaskId == other.rightBottomTaskId; + && leftTopTaskIds.equals(other.leftTopTaskIds) + && rightBottomTaskIds.equals(other.rightBottomTaskIds) + && snapPosition == other.snapPosition; } @Override public int hashCode() { - return Objects.hash(leftTopBounds, rightBottomBounds, leftTopTaskId, rightBottomTaskId); + return Objects.hash(leftTopBounds, rightBottomBounds, + leftTopTaskId, rightBottomTaskId, leftTopTaskIds, rightBottomTaskIds); } @Override public String toString() { - return "LeftTop: " + leftTopBounds + ", taskId: " + leftTopTaskId + "\n" - + "RightBottom: " + rightBottomBounds + ", taskId: " + rightBottomTaskId + "\n" + return "LeftTop: " + leftTopBounds + " taskId: " + leftTopTaskId + + ", taskIds: " + leftTopTaskIds + "\n" + + "RightBottom: " + rightBottomBounds + " taskId: " + rightBottomTaskId + + ", taskIds: " + rightBottomTaskIds + "\n" + "Divider: " + visualDividerBounds + "\n" + "AppsVertical? " + appsStackedVertically + "\n" + "snapPosition: " + snapPosition; diff --git a/wmshell/tests/OWNERS b/wmshell/tests/OWNERS index b8a19ad353..0c18bef982 100644 --- a/wmshell/tests/OWNERS +++ b/wmshell/tests/OWNERS @@ -1,4 +1,4 @@ -# Bug component: 1157642 +# Bug component: 928594 # includes OWNERS from parent directories natanieljr@google.com pablogamito@google.com @@ -6,12 +6,18 @@ pablogamito@google.com lbill@google.com madym@google.com hwwang@google.com +gabiyev@google.com chenghsiuchang@google.com atsjenk@google.com jorgegil@google.com -nmusgrave@google.com +vaniadesmonda@google.com pbdr@google.com -tkachenkoi@google.com mpodolian@google.com jeremysim@google.com peanutbutter@google.com +pragyabajoria@google.com +uysalorhan@google.com +gsennton@google.com +mattsziklay@google.com +mdehaini@google.com +toshikikikuchi@google.com diff --git a/wmshell/tests/flicker/Android.bp b/wmshell/tests/flicker/Android.bp index 4abaf5bd4a..98b0bd0b58 100644 --- a/wmshell/tests/flicker/Android.bp +++ b/wmshell/tests/flicker/Android.bp @@ -30,7 +30,6 @@ filegroup { java_library { name: "wm-shell-flicker-utils", - platform_apis: true, optimize: { enabled: false, }, @@ -39,15 +38,15 @@ java_library { ], static_libs: [ "androidx.test.ext.junit", - "flickertestapplib", + "com_android_wm_shell_flags_lib", "flickerlib", "flickerlib-helpers", + "flickertestapplib", + "launcher-aosp-tapl", + "launcher-helper-lib", "platform-test-annotations", "wm-flicker-common-app-helpers", "wm-flicker-common-assertions", - "launcher-helper-lib", - "launcher-aosp-tapl", - "com_android_wm_shell_flags_lib", ], } @@ -59,19 +58,20 @@ java_defaults { enabled: false, }, test_suites: ["device-tests"], - libs: ["android.test.runner"], + libs: ["android.test.runner.stubs.system"], static_libs: [ - "wm-shell-flicker-utils", "androidx.test.ext.junit", - "flickertestapplib", "flickerlib", "flickerlib-helpers", "flickerlib-trace_processor_shell", + "flickertestapplib", + "launcher-aosp-tapl", + "launcher-helper-lib", "platform-test-annotations", + "platform-test-rules", "wm-flicker-common-app-helpers", "wm-flicker-common-assertions", - "launcher-helper-lib", - "launcher-aosp-tapl", + "wm-shell-flicker-utils", ], data: [ ":FlickerTestApp", diff --git a/wmshell/tests/flicker/appcompat/Android.bp b/wmshell/tests/flicker/appcompat/Android.bp index e151ab2c58..b016c9f941 100644 --- a/wmshell/tests/flicker/appcompat/Android.bp +++ b/wmshell/tests/flicker/appcompat/Android.bp @@ -15,6 +15,7 @@ // package { + default_team: "trendy_team_lse_app_compat", // See: http://go/android-license-faq // A large-scale-change added 'default_applicable_licenses' to import // all of the 'license_kinds' from "frameworks_base_license" @@ -23,21 +24,76 @@ package { default_applicable_licenses: ["frameworks_base_license"], } -filegroup { - name: "WMShellFlickerTestsAppCompat-src", - srcs: [ - "src/**/*.kt", - ], -} - android_test { - name: "WMShellFlickerTestsOther", + name: "WMShellFlickerTestsAppCompat", defaults: ["WMShellFlickerTestsDefault"], manifest: "AndroidManifest.xml", package_name: "com.android.wm.shell.flicker", instrumentation_target_package: "com.android.wm.shell.flicker", test_config_template: "AndroidTestTemplate.xml", - srcs: [":WMShellFlickerTestsAppCompat-src"], + srcs: ["src/**/*.kt"], static_libs: ["WMShellFlickerTestsBase"], data: ["trace_config/*"], } + +//////////////////////////////////////////////////////////////////////////////// +// Begin breakdowns for WMShellFlickerTestsAppCompat module + +test_module_config { + name: "WMShellFlickerTestsAppCompat-CatchAll", + base: "WMShellFlickerTestsAppCompat", + exclude_filters: [ + "com.android.wm.shell.flicker.appcompat.OpenAppInSizeCompatModeTest", + "com.android.wm.shell.flicker.appcompat.OpenTransparentActivityTest", + "com.android.wm.shell.flicker.appcompat.QuickSwitchLauncherToLetterboxAppTest", + "com.android.wm.shell.flicker.appcompat.RepositionFixedPortraitAppTest", + "com.android.wm.shell.flicker.appcompat.RestartAppInSizeCompatModeTest", + "com.android.wm.shell.flicker.appcompat.RotateImmersiveAppInFullscreenTest", + ], + test_suites: ["device-tests"], +} + +test_module_config { + name: "WMShellFlickerTestsAppCompat-OpenAppInSizeCompatModeTest", + base: "WMShellFlickerTestsAppCompat", + include_filters: ["com.android.wm.shell.flicker.appcompat.OpenAppInSizeCompatModeTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "WMShellFlickerTestsAppCompat-OpenTransparentActivityTest", + base: "WMShellFlickerTestsAppCompat", + include_filters: ["com.android.wm.shell.flicker.appcompat.OpenTransparentActivityTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "WMShellFlickerTestsAppCompat-QuickSwitchLauncherToLetterboxAppTest", + base: "WMShellFlickerTestsAppCompat", + include_filters: ["com.android.wm.shell.flicker.appcompat.QuickSwitchLauncherToLetterboxAppTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "WMShellFlickerTestsAppCompat-RepositionFixedPortraitAppTest", + base: "WMShellFlickerTestsAppCompat", + include_filters: ["com.android.wm.shell.flicker.appcompat.RepositionFixedPortraitAppTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "WMShellFlickerTestsAppCompat-RestartAppInSizeCompatModeTest", + base: "WMShellFlickerTestsAppCompat", + include_filters: ["com.android.wm.shell.flicker.appcompat.RestartAppInSizeCompatModeTest"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "WMShellFlickerTestsAppCompat-RotateImmersiveAppInFullscreenTest", + base: "WMShellFlickerTestsAppCompat", + include_filters: ["com.android.wm.shell.flicker.appcompat.RotateImmersiveAppInFullscreenTest"], + test_suites: ["device-tests"], +} + +// End breakdowns for FlickerTestsRotation module +//////////////////////////////////////////////////////////////////////////////// diff --git a/wmshell/tests/flicker/appcompat/AndroidTestTemplate.xml b/wmshell/tests/flicker/appcompat/AndroidTestTemplate.xml index f69a90cc79..a4ecac9dfe 100644 --- a/wmshell/tests/flicker/appcompat/AndroidTestTemplate.xml +++ b/wmshell/tests/flicker/appcompat/AndroidTestTemplate.xml @@ -24,6 +24,10 @@