feat: WM-Shell QPR1 (not src or shared)
This commit is contained in:
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+49
-96
@@ -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",
|
||||
],
|
||||
}
|
||||
|
||||
+4
-2
@@ -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
|
||||
|
||||
@@ -4,6 +4,7 @@ aconfig_declarations {
|
||||
container: "system",
|
||||
srcs: [
|
||||
"multitasking.aconfig",
|
||||
"automotive.aconfig",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# Owners for flag changes
|
||||
madym@google.com
|
||||
hwwang@google.com
|
||||
hwwang@google.com
|
||||
sqsun@google.com
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -1,8 +1,23 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.wm.shell.multivalenttests">
|
||||
|
||||
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS"/>
|
||||
<uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT"/>
|
||||
|
||||
<application android:debuggable="true" android:supportsRtl="true" >
|
||||
<uses-library android:name="android.test.runner" />
|
||||
<activity android:name="com.android.wm.shell.bubbles.bar.BubbleBarAnimationHelperTest$TestActivity"
|
||||
android:exported="true"/>
|
||||
|
||||
<activity android:name="com.android.wm.shell.bubbles.bar.BubbleBarMenuViewControllerTest$TestActivity"
|
||||
android:exported="true"/>
|
||||
|
||||
<activity android:name=".bubbles.TestActivity"
|
||||
android:allowEmbedded="true"
|
||||
android:documentLaunchMode="always"
|
||||
android:excludeFromRecents="true"
|
||||
android:exported="false"
|
||||
android:resizeableActivity="true" />
|
||||
</application>
|
||||
|
||||
<instrumentation
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.wm.shell.multivalenttests">
|
||||
<application>
|
||||
<activity android:name="com.android.wm.shell.bubbles.bar.BubbleBarAnimationHelperTest$TestActivity"
|
||||
android:exported="true"/>
|
||||
<activity android:name="com.android.wm.shell.bubbles.bar.BubbleBarMenuViewControllerTest$TestActivity"
|
||||
android:exported="true"/>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
sdk=NEWEST_SDK
|
||||
graphicsMode=NATIVE
|
||||
|
||||
|
||||
+128
-23
@@ -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
|
||||
|
||||
@@ -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<Context>()
|
||||
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<SysuiProxy>()
|
||||
|
||||
@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<BubbleTransitions.BubbleTransition>()
|
||||
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<BubbleTransitions.BubbleTransition>()
|
||||
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<Boolean>) {}
|
||||
|
||||
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<TaskViewTaskController>()
|
||||
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<String, Boolean>()
|
||||
override fun onBubbleExpandChanged(isExpanding: Boolean, key: String) {
|
||||
bubblesExpandedState[key] = isExpanding
|
||||
}
|
||||
}
|
||||
|
||||
override val overflowBubbles: List<Bubble>
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Context>()
|
||||
private lateinit var taskView: TaskView
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
taskView = mock()
|
||||
bubbleTaskView = BubbleTaskView(taskView, directExecutor())
|
||||
}
|
||||
private val componentName = ComponentName(context, "TestClass")
|
||||
private val taskView = mock<TaskView>()
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+33
-13
@@ -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<BubbleBarLocation>()
|
||||
val locationChanges = mutableListOf<BubbleBarLocation>()
|
||||
val locationReleases = mutableListOf<BubbleBarLocation>()
|
||||
|
||||
override fun onStart(location: BubbleBarLocation) {
|
||||
locationStart.add(location)
|
||||
}
|
||||
|
||||
override fun onChange(location: BubbleBarLocation) {
|
||||
locationChanges.add(location)
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.wm.shell.multivalenttests">
|
||||
|
||||
<application android:debuggable="true" android:supportsRtl="true" >
|
||||
<uses-library android:name="android.test.runner" />
|
||||
</application>
|
||||
|
||||
<instrumentation
|
||||
android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||
android:label="Multivalent tests for WindowManager-Shell"
|
||||
android:targetPackage="com.android.wm.shell.multivalenttests">
|
||||
</instrumentation>
|
||||
</manifest>
|
||||
@@ -1,3 +0,0 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.wm.shell.multivalenttests">
|
||||
</manifest>
|
||||
@@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2023 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<configuration description="Runs Tests for WindowManagerShellLib">
|
||||
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
|
||||
<option name="cleanup-apks" value="true" />
|
||||
<option name="install-arg" value="-t" />
|
||||
<option name="test-file-name" value="WMShellMultivalentTestsOnDevice.apk" />
|
||||
</target_preparer>
|
||||
|
||||
<option name="test-suite-tag" value="apct" />
|
||||
<option name="test-suite-tag" value="framework-base-presubmit" />
|
||||
<option name="test-tag" value="WMShellMultivalentTestsOnDevice" />
|
||||
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
|
||||
<option name="package" value="com.android.wm.shell.multivalenttests" />
|
||||
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
|
||||
<option name="hidden-api-checks" value="false"/>
|
||||
</test>
|
||||
</configuration>
|
||||
@@ -1,4 +0,0 @@
|
||||
atsjenk@google.com
|
||||
liranb@google.com
|
||||
madym@google.com
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
sdk=NEWEST_SDK
|
||||
|
||||
-670
@@ -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<Context>()
|
||||
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
|
||||
}
|
||||
}
|
||||
-462
@@ -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<Context>()
|
||||
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<SysuiProxy>()
|
||||
|
||||
@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<Boolean>) {}
|
||||
|
||||
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<TaskViewTaskController>()
|
||||
val taskView = TaskView(context, taskViewTaskController)
|
||||
return BubbleTaskView(taskView, shellExecutor)
|
||||
}
|
||||
}
|
||||
|
||||
private inner class FakeBubbleExpandedViewManager : BubbleExpandedViewManager {
|
||||
|
||||
override val overflowBubbles: List<Bubble>
|
||||
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() {}
|
||||
}
|
||||
}
|
||||
-92
@@ -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<Context>()
|
||||
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()
|
||||
}
|
||||
}
|
||||
-459
@@ -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<Context>()
|
||||
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<BubbleBarLocation>()
|
||||
val locationReleases = mutableListOf<BubbleBarLocation>()
|
||||
override fun onChange(location: BubbleBarLocation) {
|
||||
locationChanges.add(location)
|
||||
}
|
||||
|
||||
override fun onRelease(location: BubbleBarLocation) {
|
||||
locationReleases.add(location)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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",
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.wm.shell.multivalenttests">
|
||||
|
||||
<application android:debuggable="true" android:supportsRtl="true" >
|
||||
<uses-library android:name="android.test.runner" />
|
||||
</application>
|
||||
|
||||
<instrumentation
|
||||
android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||
android:label="Multivalent tests for WindowManager-Shell"
|
||||
android:targetPackage="com.android.wm.shell.multivalenttests">
|
||||
</instrumentation>
|
||||
</manifest>
|
||||
@@ -1,3 +0,0 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.wm.shell.multivalenttests">
|
||||
</manifest>
|
||||
@@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2023 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<configuration description="Runs Tests for WindowManagerShellLib">
|
||||
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
|
||||
<option name="cleanup-apks" value="true" />
|
||||
<option name="install-arg" value="-t" />
|
||||
<option name="test-file-name" value="WMShellMultivalentTestsOnDevice.apk" />
|
||||
</target_preparer>
|
||||
|
||||
<option name="test-suite-tag" value="apct" />
|
||||
<option name="test-suite-tag" value="framework-base-presubmit" />
|
||||
<option name="test-tag" value="WMShellMultivalentTestsOnDevice" />
|
||||
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
|
||||
<option name="package" value="com.android.wm.shell.multivalenttests" />
|
||||
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
|
||||
<option name="hidden-api-checks" value="false"/>
|
||||
</test>
|
||||
</configuration>
|
||||
@@ -1,4 +0,0 @@
|
||||
atsjenk@google.com
|
||||
liranb@google.com
|
||||
madym@google.com
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
sdk=NEWEST_SDK
|
||||
|
||||
-670
@@ -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<Context>()
|
||||
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
|
||||
}
|
||||
}
|
||||
-462
@@ -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<Context>()
|
||||
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<SysuiProxy>()
|
||||
|
||||
@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<Boolean>) {}
|
||||
|
||||
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<TaskViewTaskController>()
|
||||
val taskView = TaskView(context, taskViewTaskController)
|
||||
return BubbleTaskView(taskView, shellExecutor)
|
||||
}
|
||||
}
|
||||
|
||||
private inner class FakeBubbleExpandedViewManager : BubbleExpandedViewManager {
|
||||
|
||||
override val overflowBubbles: List<Bubble>
|
||||
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() {}
|
||||
}
|
||||
}
|
||||
-92
@@ -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<Context>()
|
||||
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()
|
||||
}
|
||||
}
|
||||
-459
@@ -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<Context>()
|
||||
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<BubbleBarLocation>()
|
||||
val locationReleases = mutableListOf<BubbleBarLocation>()
|
||||
override fun onChange(location: BubbleBarLocation) {
|
||||
locationChanges.add(location)
|
||||
}
|
||||
|
||||
override fun onRelease(location: BubbleBarLocation) {
|
||||
locationReleases.add(location)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,11 @@
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M23,5v8h-2V5H3v14h10v2v0H3c-1.1,0 -2,-0.9 -2,-2V5c0,-1.1 0.9,-2 2,-2h18C22.1,3 23,3.9 23,5zM10,8v2.59L5.71,6.29L4.29,7.71L8.59,12H6v2h6V8H10zM19,15c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,15 19,15z"/>
|
||||
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"/>
|
||||
</vector>
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M11.29,14.71L7,10.41V13H5V7h6v2H8.41l4.29,4.29L11.29,14.71zM21,3H3C1.9,3 1,3.9 1,5v14c0,1.1 0.9,2 2,2h10v0v-2H3V5h18v8h2V5C23,3.9 22.1,3 21,3zM19,15c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,15 19,15z"/>
|
||||
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"/>
|
||||
</vector>
|
||||
|
||||
@@ -60,6 +60,20 @@
|
||||
android:focusable="false"
|
||||
tools:text="Gmail"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/expand_menu_error"
|
||||
android:src="@drawable/expand_menu_error"
|
||||
android:layout_width="@dimen/desktop_mode_header_expand_menu_error_image_width"
|
||||
android:layout_height="@dimen/desktop_mode_header_expand_menu_error_image_width"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="@dimen/desktop_mode_header_expand_menu_error_image_margin"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:screenReaderFocusable="false"
|
||||
android:importantForAccessibility="no"
|
||||
android:contentDescription="@null"
|
||||
android:scaleType="centerCrop"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/expand_menu_button"
|
||||
android:layout_width="16dp"
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
style="@style/DesktopModeHandleMenuWindowingButton"/>
|
||||
|
||||
<Space
|
||||
android:id="@+id/split_screen_button_space"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
@@ -164,12 +165,33 @@
|
||||
android:src="@drawable/desktop_mode_ic_handle_menu_change_aspect_ratio"
|
||||
style="@style/DesktopModeHandleMenuActionButton"/>
|
||||
|
||||
<com.android.wm.shell.windowdecor.HandleMenuActionButton
|
||||
android:id="@+id/handle_menu_restart_button"
|
||||
android:contentDescription="@string/handle_menu_restart_text"
|
||||
android:text="@string/handle_menu_restart_text"
|
||||
android:src="@drawable/desktop_mode_ic_handle_menu_restart"
|
||||
style="@style/DesktopModeHandleMenuActionButton"/>
|
||||
<LinearLayout
|
||||
android:id="@+id/handle_menu_restart_pill"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.android.wm.shell.windowdecor.HandleMenuActionButton
|
||||
android:id="@+id/handle_menu_restart_button"
|
||||
android:contentDescription="@string/handle_menu_restart_text"
|
||||
android:text="@string/handle_menu_restart_text"
|
||||
android:src="@drawable/desktop_mode_ic_handle_menu_restart"
|
||||
style="@style/DesktopModeHandleMenuActionButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/restart_menu_error_icon"
|
||||
android:contentDescription="@string/handle_menu_error_icon_text"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:src="@drawable/expand_menu_error"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:scaleType="centerCrop"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<com.android.wm.shell.windowdecor.CaptionMenuLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
|
||||
android:id="@+id/maximize_menu"
|
||||
android:layout_width="wrap_content"
|
||||
@@ -158,12 +159,4 @@
|
||||
android:alpha="0"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Empty view intentionally placed in front of everything else and matching the menu size
|
||||
used to monitor input events over the entire menu. -->
|
||||
<View
|
||||
android:id="@+id/maximize_menu_overlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</FrameLayout>
|
||||
|
||||
</com.android.wm.shell.windowdecor.CaptionMenuLayout>
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/letterbox_restart_dialog_title_icon"
|
||||
android:importantForAccessibility="no"
|
||||
android:layout_width="@dimen/letterbox_restart_dialog_title_icon_width"
|
||||
android:layout_height="@dimen/letterbox_restart_dialog_title_icon_height"
|
||||
|
||||
@@ -24,6 +24,14 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.android.wm.shell.common.split.DividerTooltip
|
||||
android:id="@+id/docked_divider_tooltip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.android.wm.shell.common.split.DividerHandleView
|
||||
android:id="@+id/docked_divider_handle"
|
||||
android:layout_height="match_parent"
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Hierdie app kan net in 1 venster oopgemaak word"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App sal dalk nie op \'n sekondêre skerm werk nie."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App steun nie begin op sekondêre skerms nie."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"App steun nie borrel nie"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Skermverdeler"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Skermverdeler"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Volskerm links"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Bestuur vensters"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Verander aspekverhouding"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimeer aansig"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Fout-ikoon"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Maak toe"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Maak kieslys toe"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (werkskermvensters)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimeer skerm"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Verander grootte"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App kan nie hierheen geskuif word nie"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Maak tans nuwe appvenster oop"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Maak tans appvenster toe"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Minimeer tans appvenster"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (gefokus)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (nie gefokus nie)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Meesleurend"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Stel terug"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimeer"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"ይህ መተግበሪያ መከፈት የሚችለው በ1 መስኮት ብቻ ነው"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"መተግበሪያ በሁለተኛ ማሳያ ላይ ላይሠራ ይችላል።"</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"መተግበሪያ በሁለተኛ ማሳያዎች ላይ ማስጀመርን አይደግፍም።"</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"መተግበሪያ ዓረፋን አይደግፍም"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"የተከፈለ የማያ ገፅ ከፋይ"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"የተከፈለ የማያ ገፅ ከፋይ"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"የግራ ሙሉ ማያ ገፅ"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"መስኮቶችን አስተዳድር"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"ምጥጥነ ገፅታ ለውጥ"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"ዕይታን አትባ"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"የስህተት አዶ"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"ዝጋ"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"ምናሌ ዝጋ"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ዴስክቶፕ መስኮት)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"የማያ ገጹ መጠን አሳድግ"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"መጠን ቀይር"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"መተግበሪያ ወደዚህ መንቀሳቀስ አይችልም"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"አዲስ የመተግበሪያ መስኮት በመክፈት ላይ"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"የመተግበሪያ መስኮትን በመዝጋት ላይ"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"የመተግበሪያ መስኮትን በማሳነስ ላይ"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ትኩረት የተደረገበት)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ትኩረት ያልተደረገበት)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"አስማጭ"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ወደነበረበት መልስ"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"አሳድግ"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"لا يمكن فتح هذا التطبيق إلا في نافذة واحدة."</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"قد لا يعمل التطبيق على شاشة عرض ثانوية."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"لا يمكن تشغيل التطبيق على شاشات عرض ثانوية."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"لا يتيح التطبيق إظهار المهام على شكل فقاعة"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"أداة تقسيم الشاشة"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"أداة تقسيم الشاشة"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"عرض النافذة اليسرى بملء الشاشة"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"إدارة النوافذ"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"تغيير نسبة العرض إلى الارتفاع"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"تحسين طريقة العرض"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"رمز الخطأ"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"إغلاق"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"إغلاق القائمة"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (عرض المحتوى في النافذة الحالية على سطح المكتب)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"تكبير الشاشة إلى أقصى حدّ"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"تغيير الحجم"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"لا يمكن نقل التطبيق إلى هنا"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"جارٍ فتح نافذة تطبيق جديدة"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"جارٍ إغلاق نافذة التطبيق"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"جارٍ تصغير نافذة التطبيق"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" (تم التركيز عليه)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (غير مركّز عليه)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"مجسَّم"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"استعادة"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"تكبير"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"এই এপ্টো কেৱল ১ খন ৱিণ্ড’ত খুলিব পাৰি"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"গৌণ ডিছপ্লেত এপে সঠিকভাৱে কাম নকৰিব পাৰে।"</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"গৌণ ডিছপ্লেত এপ্ লঞ্চ কৰিব নোৱাৰি।"</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"এপে বাবল সমৰ্থন নকৰে"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"স্প্লিট স্ক্ৰীনৰ বিভাজক"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"স্প্লিট স্ক্ৰীনৰ বিভাজক"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"বাওঁফালৰ স্ক্ৰীনখন সম্পূৰ্ণ স্ক্ৰীন কৰক"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"ৱিণ্ড’ পৰিচালনা কৰক"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"আকাৰৰ অনুপাত সলনি কৰক"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"ভিউ অপ্টিমাইজ কৰক"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"আসোঁৱাহৰ চিহ্ন"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"বন্ধ কৰক"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"মেনু বন্ধ কৰক"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ডেস্কটপ ৱিণ্ড’ৱিং)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"স্ক্ৰীন মেক্সিমাইজ কৰক"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"আকাৰ সলনি কৰক"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ইয়ালৈ এপ্টো আনিব নোৱাৰি"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"নতুন এপৰ ৱিণ্ড’ খুলি থকা হৈছে"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"এপৰ ৱিণ্ড’ বন্ধ কৰি থকা হৈছে"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"এপৰ ৱিণ্ড’ মিনিমাইজ কৰা হৈছে"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ফ’কাছ কৰা)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ফ’কাছ কৰা নাই)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ইমাৰ্ছিভ"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"পুনঃস্থাপন কৰক"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"মেক্সিমাইজ কৰক"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Bu tətbiq yalnız 1 pəncərədə açıla bilər"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Tətbiq ikinci ekranda işləməyə bilər."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Tətbiq ikinci ekranda başlamağı dəstəkləmir."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Tətbiq qabarcığı dəstəkləmir"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Bölünmüş ekran ayırıcısı"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Bölünmüş ekran ayırıcısı"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Sol tam ekran"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Pəncərələri idarə edin"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Tərəflər nisbətini dəyişin"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Görünüşü optimallaşdırın"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Xəta ikonası"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Bağlayın"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Menyunu bağlayın"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Masaüstü pəncərə rejimi)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranı maksimum böyüdün"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Ölçüsünü dəyişin"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Tətbiqi bura köçürmək mümkün deyil"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Yeni tətbiq pəncərəsi açılır"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Tətbiq pəncərəsi bağlanır"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Tətbiq pəncərəsi kiçildilir"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Fokuslanmış)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Fokuslanmamış)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"İmmersiv"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Bərpa edin"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Böyüdün"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Ova aplikacija može da se otvori samo u jednom prozoru"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće funkcionisati na sekundarnom ekranu."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacija ne podržava pokretanje na sekundarnim ekranima."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Aplikacija ne podržava oblačić"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Razdelnik podeljenog ekrana"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Razdelnik podeljenog ekrana"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Režim celog ekrana za levi ekran"</string>
|
||||
@@ -77,14 +78,14 @@
|
||||
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Odbaci oblačić"</string>
|
||||
<string name="bubble_fullscreen_text" msgid="1006758103218086231">"Prebaci na ceo ekran"</string>
|
||||
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ne koristi oblačiće za konverzaciju"</string>
|
||||
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Ćaskajte u oblačićima"</string>
|
||||
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Četujte u oblačićima"</string>
|
||||
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Nove konverzacije se prikazuju kao plutajuće ikone ili oblačići. Dodirnite da biste otvorili oblačić. Prevucite da biste ga premestili."</string>
|
||||
<string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Kontrolišite oblačiće u bilo kom trenutku"</string>
|
||||
<string name="bubbles_user_education_manage" msgid="3460756219946517198">"Dodirnite Upravljajte da biste isključili oblačiće iz ove aplikacije"</string>
|
||||
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Važi"</string>
|
||||
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nema nedavnih oblačića"</string>
|
||||
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Ovde se prikazuju nedavni i odbačeni oblačići"</string>
|
||||
<string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Ćaskajte u oblačićima"</string>
|
||||
<string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Četujte u oblačićima"</string>
|
||||
<string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Nove konverzacije se pojavljuju kao ikone u donjem uglu ekrana. Dodirnite da biste ih proširili ili prevucite da biste ih odbacili."</string>
|
||||
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Kontrolišite oblačiće u svakom trenutku"</string>
|
||||
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Dodirnite ovde i odredite koje aplikacije i konverzacije mogu da imaju oblačić"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Upravljajte prozorima"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Promeni razmeru"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimizujte prikaz"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Ikona greške"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Zatvorite"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite meni"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (prikaz računarskih prozora)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Povećaj ekran"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Prilagodi"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacija ne može da se premesti ovde"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Otvara se novi prozor aplikacije"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Zatvara se prozor aplikacije"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Umanjuje se prozor aplikacije"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (fokusirano)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (nije fokusirano)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Imerzivno"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Vrati"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Uvećaj"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Гэту праграму можна адкрыць толькі ў адным акне"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Праграма можа не працаваць на дадатковых экранах."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Праграма не падтрымлівае запуск на дадатковых экранах."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"У праграме не падтрымліваецца ўсплывальны чат"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Раздзяляльнік падзеленага экрана"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Раздзяляльнік падзеленага экрана"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Левы экран – поўнаэкранны рэжым"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Кіраваць вокнамі"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Змяніць суадносіны бакоў"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Аптымізаваць прагляд"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Значок памылкі"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Закрыць"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Закрыць меню"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (рэжым вокнаў працоўнага стала)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Разгарнуць на ўвесь экран"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Змяніць памер"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Нельга перамясціць сюды праграму"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Адкрываецца новае акно праграмы"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Закрываецца акно праграмы"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Згортваецца акно праграмы"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (у фокусе)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (не ў фокусе)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"З эфектам прысутнасці"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Аднавіць"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Разгарнуць"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Това приложение може да се отвори само в 1 прозорец"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Възможно е приложението да не работи на алтернативни дисплеи."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Приложението не поддържа използването на алтернативни дисплеи."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Приложението не поддържа балончета"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Разделител в режима за разделен екран"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Разделител в режима за разделен екран"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ляв екран: Показване на цял екран"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Управление на прозорците"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Промяна на съотношението"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Оптимизиране на изгледа"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Икона за грешка"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Затваряне"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Затваряне на менюто"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (режим за настолни компютри)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Увеличаване на екрана"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Нов размер"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Приложението не може да бъде преместено тук"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Отваря се нов прозорец на приложението"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Прозорецът на приложението се затваря"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Прозорецът на приложението се намалява"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (притежава фокуса)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (не притежава фокуса)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Реалистично"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Възстановяване"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Увеличаване"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"এই অ্যাপটি শুধুমাত্র ১টি উইন্ডোতে খোলা যেতে পারে"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"সেকেন্ডারি ডিসপ্লেতে অ্যাপটি কাজ নাও করতে পারে।"</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"সেকেন্ডারি ডিসপ্লেতে অ্যাপ লঞ্চ করা যাবে না।"</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"অ্যাপে বাবল কাজ করে না"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"স্প্লিট স্ক্রিন বিভাজক"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"স্প্লিট স্ক্রিন বিভাজক"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"বাঁ দিকের অংশ নিয়ে পূর্ণ স্ক্রিন"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"উইন্ডো ম্যানেজ করুন"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"অ্যাস্পেক্ট রেশিও পরিবর্তন করুন"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"ভিউ অপ্টিমাইজ করুন"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"সমস্যার আইকন"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"বন্ধ করুন"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"\'মেনু\' বন্ধ করুন"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ডেস্কটপ উইন্ডোইং)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"স্ক্রিন বড় করুন"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ছোট বড় করুন"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"অ্যাপটি এখানে সরানো যাবে না"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"নতুন অ্যাপ উইন্ডো খোলা হচ্ছে"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"অ্যাপের উইন্ডো বন্ধ করা হচ্ছে"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"অ্যাপ উইন্ডো ছোট করা হয়েছে"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ফোকাস করা হয়েছে)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ফোকাস করা নেই)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ইমারসিভ"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ফিরিয়ে আনুন"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"বড় করুন"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Ova aplikacija se može otvoriti samo u 1 prozoru"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće raditi na sekundarnom ekranu."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacija ne podržava pokretanje na sekundarnim ekranima."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Aplikacija ne podržava oblačić"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Razdjelnik podijeljenog ekrana"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Razdjelnik podijeljenog ekrana"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Lijevo cijeli ekran"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Upravljanje prozorima"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Promjena formata slike"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimiziranje prikaza"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Ikona greške"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Zatvaranje"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Zatvaranje menija"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (računarski prikaz prozora)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimiziraj ekran"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Promijeni veličinu"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ne možete premjestiti aplikaciju ovdje"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Otvaranje novog prozora aplikacije"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Zatvaranje prozora aplikacije"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Minimiziranje prozora aplikacije"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (fokusirano)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (nije fokusirano)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Uvjerljivo"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Vraćanje"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimiziraj"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Aquesta aplicació només pot obrir-se en 1 finestra"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"És possible que l\'aplicació no funcioni en una pantalla secundària."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'aplicació no es pot obrir en pantalles secundàries."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"L\'aplicació no admet la bombolla"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Separador de pantalla dividida"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Separador de pantalla dividida"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Pantalla esquerra completa"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Gestiona les finestres"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Canvia la relació d\'aspecte"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Visualització d\'Optimize"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Icona d\'error"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Tanca"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Tanca el menú"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (sistema de finestres de tipus escriptori)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximitza la pantalla"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Canvia la mida"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"L\'aplicació no es pot moure aquí"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"S\'està obrint una finestra nova de l\'aplicació"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"S\'està tancant la finestra de l\'aplicació"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"S\'està minimitzant la finestra de l\'aplicació"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (té el focus)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (no té el focus)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersiu"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restaura"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximitza"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Tuto aplikaci lze otevřít jen v jednom okně"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikace na sekundárním displeji nemusí fungovat."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikace nepodporuje spuštění na sekundárních displejích."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Aplikace bublinu nepodporuje"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Čára rozdělující obrazovku"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Čára rozdělující obrazovku"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Levá část na celou obrazovku"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Spravovat okna"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Změnit poměr stran"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimalizovat zobrazení"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Ikona chyby"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Zavřít"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Zavřít nabídku"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (okna na ploše)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximalizovat obrazovku"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Změnit velikost"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikaci sem nelze přesunout"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Otevírání nového okna aplikace"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Zavírání okna aplikace"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Minimalizace okna aplikace"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (označeno)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (neoznačeno)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Pohlcující"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Obnovit"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximalizovat"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Denne app kan kun åbnes i 1 vindue"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen fungerer muligvis ikke på sekundære skærme."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Appen kan ikke åbnes på sekundære skærme."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Appen understøtter ikke bobler"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Adskiller til opdelt skærm"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Adskiller til opdelt skærm"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vis venstre del i fuld skærm"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Administrer vinduer"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Skift billedformat"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimer visning"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Fejlikon"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Luk"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Luk menu"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (vinduer på skrivebordet)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimér skærm"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Tilpas størrelse"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Apps kan ikke flyttes hertil"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Et nyt appvindue er åbnet"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Lukker appvindue"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Appvinduet er minimeret"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (fremhævet)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ikke fremhævet)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Opslugende"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Gendan"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimér"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Diese App kann nur in einem einzigen Fenster geöffnet werden"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Die App funktioniert auf einem sekundären Display möglicherweise nicht."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Die App unterstützt den Start auf sekundären Displays nicht."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"App unterstützt keine Bubbles"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Bildschirmteiler"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Bildschirmteiler"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vollbild links"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Fenster verwalten"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Seitenverhältnis ändern"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Ansicht optimieren"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Fehlersymbol"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Schließen"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Menü schließen"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Desktop-Freiform-Fenster)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Bildschirm maximieren"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Größe ändern"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Die App kann nicht hierher verschoben werden"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Neues App-Fenster wird geöffnet"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"App-Fenster wird geschlossen"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"App-Fenster wird minimiert"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Fokussiert)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Nicht fokussiert)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersiv"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Wiederherstellen"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximieren"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Αυτή η εφαρμογή μπορεί να ανοίξει μόνο σε ένα παράθυρο"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Η εφαρμογή ίσως να μην λειτουργήσει σε δευτερεύουσα οθόνη."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Η εφαρμογή δεν υποστηρίζει την εκκίνηση σε δευτερεύουσες οθόνες."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Η εφαρμογή δεν υποστηρίζει συννεφάκια"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Διαχωριστικό οθόνης"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Διαχωριστικό οθόνης"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Αριστερή πλήρης οθόνη"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Διαχείριση παραθύρων"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Αλλαγή λόγου διαστάσεων"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Βελτιστοποίηση προβολής"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Εικονίδιο σφάλματος"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Κλείσιμο"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Κλείσιμο μενού"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Προσαρμογή σε παράθυρο στην επιφάνεια εργασίας)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Μεγιστοποίηση οθόνης"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Αλλαγή μεγέθους"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Δεν είναι δυνατή η μετακίνηση της εφαρμογής εδώ"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Άνοιγμα νέου παραθύρου εφαρμογής"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Κλείσιμο παραθύρου εφαρμογής"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Ελαχιστοποίηση παραθύρου εφαρμογής"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Με εστίαση)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Χωρίς εστίαση)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Καθηλωτικό"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Επαναφορά"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Μεγιστοποίηση"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"This app can only be opened in one window"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"App does not support bubble"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Split screen divider"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Split screen divider"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Left full screen"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Manage windows"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimise view"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Error icon"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Close"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Desktop windowing)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Resize"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Opening new app window"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Closing app window"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Minimising app window"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (focused)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (not focused)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersive"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restore"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximise"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"This app can only be opened in 1 window"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"App does not support bubble"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Split screen divider"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Split screen divider"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Left full screen"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Manage Windows"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimize View"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Error Icon"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Close"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Close Menu"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Desktop windowing)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximize Screen"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Resize"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Opening new app window"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Closing app window"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Minimizing app window"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Focused)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Not Focused)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersive"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restore"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximize"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"This app can only be opened in one window"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"App does not support bubble"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Split screen divider"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Split screen divider"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Left full screen"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Manage windows"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimise view"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Error icon"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Close"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Desktop windowing)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Resize"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Opening new app window"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Closing app window"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Minimising app window"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (focused)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (not focused)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersive"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restore"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximise"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"This app can only be opened in one window"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"App does not support bubble"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Split screen divider"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Split screen divider"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Left full screen"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Manage windows"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimise view"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Error icon"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Close"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Desktop windowing)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Resize"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Opening new app window"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Closing app window"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Minimising app window"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (focused)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (not focused)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersive"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restore"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximise"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Esta app solo puede estar abierta en 1 ventana"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Es posible que la app no funcione en una pantalla secundaria."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"La app no puede iniciarse en pantallas secundarias."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"La app no admite la burbuja"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Divisor de pantalla dividida"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Divisor de pantalla dividida"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Pantalla izquierda completa"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Administrar ventanas"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambiar relación de aspecto"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimizar vista"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Ícono de error"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Cerrar"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (renderización en ventanas de escritorio)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Dividir pantalla"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"No se puede mover la app aquí"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Abriendo una nueva ventana de la app"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Cerrando la ventana de la app"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Minimizando la ventana de la app"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (enfocada)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (sin enfocar)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Inmersivo"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restablecer"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximizar"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Esta aplicación solo puede abrirse en una ventana"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Es posible que la aplicación no funcione en una pantalla secundaria."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"La aplicación no se puede abrir en pantallas secundarias."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"La aplicación no es compatible con burbujas"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Divisor de pantalla dividida"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Divisor de pantalla dividida"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Pantalla izquierda completa"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Gestionar ventanas"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambiar relación de aspecto"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimizar vista"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Icono de error"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Cerrar"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (modo Ventanas)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Dividir pantalla"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"La aplicación no se puede mover aquí"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Abriendo nueva ventana de la aplicación"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Cerrando ventana de la aplicación"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Minimizando ventana de la aplicación"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (enfocada)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (no enfocada)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Inmersivo"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restaurar"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximizar"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Selle rakenduse saab avada ainult ühes aknas"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Rakendus ei pruugi teisesel ekraanil töötada."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Rakendus ei toeta teisestel ekraanidel käivitamist."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Rakendus ei toeta mulle"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Jagatud ekraanikuva jaotur"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Jagatud ekraanikuva jaotur"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vasak täisekraan"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Akende haldamine"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Kuvasuhte muutmine"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Vaate optimeerimine"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Veaikoon"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Sule"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Sule menüü"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (töölaua aknad)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Kuva täisekraanil"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Suuruse muutmine"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Rakendust ei saa siia teisaldada"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Rakenduse avamine uues aknas"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Rakenduse akna sulgemine"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Rakenduse akna minimeerimine"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (fookuses)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (mitte fookuses)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Mahuta"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Taasta"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimeeri"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Leiho bakar batean ireki daiteke aplikazioa"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Baliteke aplikazioak ez funtzionatzea bigarren mailako pantailetan."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikazioa ezin da exekutatu bigarren mailako pantailatan."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Aplikazioak ez ditu onartzen burbuilak"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Pantaila-zatitzailea"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Pantaila-zatitzailea"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ezarri ezkerraldea pantaila osoan"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Kudeatu leihoak"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Aldatu aspektu-erlazioa"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimizatu ikuspegia"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Errore-ikonoa"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Itxi"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Itxi menua"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ordenagailuan leihoak erabiltzeko modua)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Handitu pantaila"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Aldatu tamaina"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikazioa ezin da hona ekarri"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Ireki da aplikazioaren leiho berri bat"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Aplikazioaren leihoa ixten"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Minimizatu da aplikazioaren leihoa"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (fokuratuta)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (fokuratu gabe)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Murgiltzailea"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Leheneratu"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximizatu"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"این برنامه فقط در ۱ پنجره میتواند باز شود"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ممکن است برنامه در نمایشگر ثانویه کار نکند."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"برنامه از راهاندازی در نمایشگرهای ثانویه پشتیبانی نمیکند."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"این برنامه از حبابک پشتیبانی نمیکند"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"تقسیمکننده صفحهٔ دونیمه"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"تقسیمکننده صفحهٔ دونیمه"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"تمامصفحه چپ"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"مدیریت کردن پنجرهها"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"تغییر نسبت ابعادی"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"بهینهسازی نما"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"نماد خطا"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"بستن"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"بستن منو"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (پردازش پنجرهای رایانه)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"بزرگ کردن صفحه"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"تغییر اندازه"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"برنامه را نمیتوان به اینجا منتقل کرد"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"باز کردن پنجره برنامه جدید"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"بستن پنجره برنامه"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"کوچک کردن پنجره برنامه"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (کانونیشده)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (کانونینشده)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"فراگیر"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"بازیابی"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"بزرگ کردن"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Tämän sovelluksen voi avata vain yhdessä ikkunassa"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Sovellus ei ehkä toimi toissijaisella näytöllä."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Sovellus ei tue käynnistämistä toissijaisilla näytöillä."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Sovellus ei tue kuplia"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Näytönjakaja"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Näytönjakaja"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vasen koko näytölle"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Hallinnoi ikkunoita"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Vaihda kuvasuhdetta"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimoi näkymä"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Virhekuvake"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Sulje"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Sulje valikko"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (työpöydän ikkunointi)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Suurenna näyttö"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Muuta kokoa"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Sovellusta ei voi siirtää tänne"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Avataan uutta sovellusikkunaa"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Suljetaan sovellusikkunaa"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Pienennetään sovellusikkunaa"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Keskitetty)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Ei keskitetty)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersiivinen"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Palauta"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Suurenna"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Cette appli ne peut être ouverte que dans une seule fenêtre."</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Il est possible que l\'appli ne fonctionne pas sur un écran secondaire."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'appli ne peut pas être lancée sur des écrans secondaires."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"L\'appli ne prend pas en charge la bulle"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Séparateur d\'écran partagé"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Séparateur d\'écran partagé"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Plein écran à la gauche"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Gérer les fenêtres"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Modifier les proportions"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimiser l\'affichage"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Icône d\'erreur"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Fermer"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Fermer le menu"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (fenêtrage du bureau)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Agrandir l\'écran"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Redimensionner"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Impossible de déplacer l\'appli ici"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Ouverture d\'une nouvelle fenêtre d\'appli en cours…"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Fermeture de la fenêtre de l\'appli en cours…"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Réduction de la fenêtre d\'appli en cours…"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (mise en évidence)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (non mise en évidence)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersif"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restaurer"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Agrandir"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Cette appli ne peut être ouverte que dans 1 fenêtre"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Il est possible que l\'application ne fonctionne pas sur un écran secondaire."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'application ne peut pas être lancée sur des écrans secondaires."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"L\'appli n\'est pas compatible avec les bulles"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Séparateur d\'écran partagé"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Séparateur d\'écran partagé"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Écran de gauche en plein écran"</string>
|
||||
@@ -55,7 +56,7 @@
|
||||
<string name="accessibility_split_top" msgid="2789329702027147146">"Affichée en haut"</string>
|
||||
<string name="accessibility_split_bottom" msgid="8694551025220868191">"Affichée en haut"</string>
|
||||
<string name="one_handed_tutorial_title" msgid="4583241688067426350">"Utilisation du mode une main"</string>
|
||||
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Pour quitter, balayez l\'écran de bas en haut ou appuyez n\'importe où au-dessus de l\'application"</string>
|
||||
<string name="one_handed_tutorial_description" msgid="3486582858591353067">"Pour quitter, balayez vers le haut depuis le bas de l\'écran ou appuyez n\'importe où au-dessus de l\'application"</string>
|
||||
<string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Démarrer le mode une main"</string>
|
||||
<string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Quitter le mode une main"</string>
|
||||
<string name="bubbles_settings_button_description" msgid="1301286017420516912">"Paramètres des bulles de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Gérer les fenêtres"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Modifier le format"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimiser l\'affichage"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Icône Erreur"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Fermer"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Fermer le menu"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (fenêtrage de bureau)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Mettre en plein écran"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Redimensionner"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Impossible de déplacer l\'appli ici"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Ouverture d\'une nouvelle fenêtre de l\'application"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Fermeture de la fenêtre de l\'application"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Réduction de la fenêtre de l\'application"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (sélectionné)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (non sélectionné)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersif"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restaurer"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Agrandir"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Esta aplicación só se pode abrir en 1 ventá"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"É posible que a aplicación non funcione nunha pantalla secundaria."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"A aplicación non se pode iniciar en pantallas secundarias."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"A aplicación non admite as burbullas"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Divisor de pantalla dividida"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Divisor de pantalla dividida"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Pantalla completa á esquerda"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Xestionar as ventás"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambiar a proporción"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimizar a vista"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Icona de erro"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Pechar"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Pechar o menú"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (modo con ventás tipo ordenador)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Cambiar tamaño"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Non se pode mover aquí a aplicación"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Abrindo nova ventá da aplicación"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Pechando ventá da aplicación"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Minimizando ventá da aplicación"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (enfocada)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (non enfocada)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Envolvente"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restaurar"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximizar"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"આ ઍપ માત્ર 1 વિન્ડોમાં ખોલી શકાય છે"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ઍપ્લિકેશન ગૌણ ડિસ્પ્લે પર કદાચ કામ ન કરે."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ઍપ્લિકેશન ગૌણ ડિસ્પ્લે પર લૉન્ચનું સમર્થન કરતી નથી."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"ઍપ બબલને સપોર્ટ કરતી નથી"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"સ્ક્રીનને વિભાજિત કરતું વિભાજક"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"સ્ક્રીનને વિભાજિત કરતું વિભાજક"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ડાબી પૂર્ણ સ્ક્રીન"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"વિન્ડો મેનેજ કરો"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"સાપેક્ષ ગુણોત્તર બદલો"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"વ્યૂ ઑપ્ટિમાઇઝ કરો"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"ભૂલનું આઇકન"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"બંધ કરો"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"મેનૂ બંધ કરો"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ડેસ્કટૉપ વિન્ડોઇંગ)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"સ્ક્રીન કરો મોટી કરો"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"કદ બદલો"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ઍપ અહીં ખસેડી શકાતી નથી"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"નવી વિન્ડો ખોલવી"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"ઍપની વિન્ડો બંધ કરી રહ્યાં છીએ"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"ઍપ વિન્ડો ન્યૂનતમ કરવી"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ફોકસ કરેલ)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ફોકસ ન કરેલી)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ઇમર્સિવ"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"રિસ્ટોર કરો"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"મોટું કરો"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"इस ऐप्लिकेशन को सिर्फ़ एक विंडो में खोला जा सकता है"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"हो सकता है कि ऐप प्राइमरी (मुख्य) डिस्प्ले के अलावा बाकी दूसरे डिस्प्ले पर काम न करे."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"प्राइमरी (मुख्य) डिस्प्ले के अलावा बाकी दूसरे डिस्प्ले पर ऐप लॉन्च नहीं किया जा सकता."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"इस ऐप्लिकेशन पर बबल की सुविधा काम नहीं करती"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"स्प्लिट स्क्रीन डिवाइडर मोड"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"स्प्लिट स्क्रीन डिवाइडर मोड"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"बाईं स्क्रीन को फ़ुल स्क्रीन बनाएं"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"विंडो मैनेज करें"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) बदलें"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"व्यू को ऑप्टिमाइज़ करें"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"गड़बड़ी का आइकॉन"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"बंद करें"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"मेन्यू बंद करें"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (डेस्कटॉप विंडोविंग)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रीन को बड़ा करें"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"साइज़ बदलें"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ऐप्लिकेशन को यहां मूव नहीं किया जा सकता"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"ऐप्लिकेशन की नई विंडो खोली जा रही है"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"ऐप्लिकेशन की विंडो बंद की जा रही है"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"ऐप्लिकेशन की विंडो को छोटा किया जा रहा है"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (फ़ोकस किया गया)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (फ़ोकस नहीं किया गया)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"इमर्सिव"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"वापस लाएं"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"बड़ा करें"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Ova se aplikacija može otvoriti samo u jednom prozoru"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće funkcionirati na sekundarnom zaslonu."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacija ne podržava pokretanje na sekundarnim zaslonima."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Aplikacija ne podržava oblačić"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Razdjelnik podijeljenog zaslona"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Razdjelnik podijeljenog zaslona"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Lijevi zaslon u cijeli zaslon"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Upravljanje prozorima"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Promijeni omjer slike"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimiziraj prikaz"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Ikona pogreške"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Zatvorite"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite izbornik"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (prikaz u prozorima na računalu)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimalno povećaj zaslon"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Promijeni veličinu"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacija se ne može premjestiti ovdje"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Otvaranje novog prozora aplikacije"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Zatvaranje prozora aplikacije"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Minimiziranje prozora aplikacije"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (fokusirano)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (nije fokusirano)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Interaktivno"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Vrati"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimiziraj"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Ez az alkalmazás csak egy ablakban nyitható meg"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Előfordulhat, hogy az alkalmazás nem működik másodlagos kijelzőn."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Az alkalmazást nem lehet másodlagos kijelzőn elindítani."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Az alkalmazás nem támogatja a buborékot"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Elválasztó az osztott képernyős nézetben"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Elválasztó az osztott képernyős nézetben"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Bal oldali teljes képernyőre"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Ablakok kezelése"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Méretarány módosítása"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Nézet optimalizálása"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Hiba ikon"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Bezárás"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Menü bezárása"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Asztali ablakkezelési mód)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Képernyő méretének maximalizálása"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Átméretezés"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Az alkalmazás nem helyezhető át ide"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Új alkalmazásablak megnyitása…"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Alkalmazásablak bezárása"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Alkalmazásablak kis méretre állítása…"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Fókuszált)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Nincs fókuszban)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Magával ragadó"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Visszaállítás"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Teljes méret"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Այս հավելվածը հնարավոր է բացել միայն մեկ պատուհանում"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Հավելվածը կարող է չաշխատել լրացուցիչ էկրանի վրա"</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Հավելվածը չի աջակցում գործարկումը լրացուցիչ էկրանների վրա"</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Հավելվածը չի աջակցում ամպիկ"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Տրոհված էկրանի բաժանիչ"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Տրոհված էկրանի բաժանիչ"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ձախ էկրանը՝ լիաէկրան"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Կառավարել պատուհանները"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Փոխել կողմերի հարաբերակցությունը"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Օպտիմալացնել"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Սխալի պատկերակ"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Փակել"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Փակել ընտրացանկը"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (համակարգչային պատուհաններ)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ծավալել էկրանը"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Փոխել չափը"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Հավելվածը հնարավոր չէ տեղափոխել այստեղ"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Հավելվածի նոր պատուհանը բացվում է"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Հավելվածի պատուհանը փակվում է"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Հավելվածի պատուհանը ծալվում է"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"Ընտրված է <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածն ընտրված չէ"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Ներկայության էֆեկտով"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Վերականգնել"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Ծավալել"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Aplikasi ini hanya dapat dibuka di 1 jendela"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikasi mungkin tidak berfungsi pada layar sekunder."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikasi tidak mendukung peluncuran pada layar sekunder."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Aplikasi tidak mendukung balon"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Pembagi layar terpisah"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Pembagi layar terpisah"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Layar penuh di kiri"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Kelola Jendela"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Ubah rasio aspek"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimalkan Tampilan"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Ikon Error"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Tutup"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Tutup Menu"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Mode jendela desktop)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Perbesar Layar"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Ubah ukuran"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikasi tidak dapat dipindahkan ke sini"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Membuka jendela aplikasi baru"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Menutup jendela aplikasi"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Meminimalkan jendela aplikasi"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Difokuskan)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Tidak Difokuskan)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Imersif"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Pulihkan"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimalkan"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Aðeins er hægt að opna þetta forrit í 1 glugga"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Hugsanlegt er að forritið virki ekki á öðrum skjá."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Forrit styður ekki opnun á öðrum skjá."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Forrit styður ekki blöðru"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Skilrúm skjáskiptingar"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Skilrúm skjáskiptingar"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vinstri á öllum skjánum"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Stjórna gluggum"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Breyta myndhlutfalli"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Fínstilla yfirlit"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Villutákn"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Loka"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Loka valmynd"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (gluggastilling í tölvu)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Stækka skjá"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Breyta stærð"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ekki er hægt að færa forritið hingað"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Opnar nýjan forritsglugga"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Lokar forritsglugga"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Minnkar forritsglugga"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (í fókus)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ekki í fókus)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Umlykjandi"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Endurheimta"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Stækka"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Questa app può essere aperta soltanto in 1 finestra"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"L\'app potrebbe non funzionare su un display secondario."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'app non supporta l\'avvio su display secondari."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"L\'app non supporta la riduzione a icona"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Strumento per schermo diviso"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Strumento per schermo diviso"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Schermata sinistra a schermo intero"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Gestisci finestre"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambia proporzioni"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Ottimizza visualizzazione"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Icona di errore"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Chiudi"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Chiudi il menu"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (app in finestre)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Massimizza schermo"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Ridimensiona"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Impossibile spostare l\'app qui"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Apertura di una nuova finestra dell\'app"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Chiusura della finestra app in corso…"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Riduzione a icona della finestra dell\'app"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (selezionata)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (non selezionata)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersivo"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Ripristina"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Ingrandisci"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"ניתן לפתוח את האפליקציה הזו רק בחלון אחד"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ייתכן שהאפליקציה לא תפעל במסך משני."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"האפליקציה אינה תומכת בהפעלה במסכים משניים."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"האפליקציה לא תומכת בבועה"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"מחלק מסך מפוצל"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"מחלק מסך מפוצל"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"מסך שמאלי מלא"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"ניהול החלונות"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"שינוי יחס הגובה-רוחב"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"אופטימיזציה של התצוגה"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"סמל שגיאה"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"סגירה"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"סגירת התפריט"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (שינוי דינמי של חלונות במחשב)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"הגדלת המסך"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"שינוי הגודל"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"לא ניתן להעביר את האפליקציה לכאן"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"נפתח חלון חדש באפליקציה"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"החלון של האפליקציה עומד להיסגר"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"חלון האפליקציה התמזער"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (במיקוד)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (לא במיקוד)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"הטמעה"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"שחזור"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"הגדלה"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"このアプリはウィンドウが 1 つの場合のみ開くことができます"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"アプリはセカンダリ ディスプレイでは動作しないことがあります。"</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"アプリはセカンダリ ディスプレイでの起動に対応していません。"</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"アプリがふきだしに対応していません"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"分割画面の分割線"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"分割画面の分割線"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"左全画面"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"ウィンドウを管理する"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"アスペクト比を変更"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"ビューを最適化"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"エラーアイコン"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"閉じる"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"メニューを閉じる"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g>(デスクトップ ウィンドウ)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"画面の最大化"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"サイズ変更"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"アプリはここに移動できません"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"新しいアプリ ウィンドウを開いています"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"アプリのウィンドウを閉じています"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"アプリ ウィンドウを最小化しています"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g>(フォーカス)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g>(非フォーカス)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"没入モード"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"復元"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"最大化"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"ამ აპის გახსნა შესაძლებელია მხოლოდ 1 ფანჯარაში"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"აპმა შეიძლება არ იმუშაოს მეორეულ ეკრანზე."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"აპს არ გააჩნია მეორეული ეკრანის მხარდაჭერა."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"ბუშტი არ არის მხარდაჭერილი აპის მიერ"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"ეკრანის გაყოფის გამყოფი"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"ეკრანის გაყოფის გამყოფი"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"მარცხენა ნაწილის სრულ ეკრანზე გაშლა"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"ფანჯრების მართვა"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"თანაფარდობის შეცვლა"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"ხედის ოპტიმიზება"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"შეცდომის ხატულა"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"დახურვა"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"მენიუს დახურვა"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (დესკტოპის ფანჯრის რეჟიმი)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"აპლიკაციის გაშლა სრულ ეკრანზე"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ზომის შეცვლა"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"აპის აქ გადატანა შეუძლებელია"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"აპის ახალი ფანჯარა იხსნება"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"მიმდინარეობს აპის ფანჯრის დახურვა"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"აპის ფანჯარა იკეცება"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ფოკუსირებული)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ფოკუსის გარეთ)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"იმერსიული"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"აღდგენა"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"მაქსიმალურად გაშლა"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Бұл қолданбаны тек 1 терезеден ашуға болады."</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Қолданба қосымша дисплейде жұмыс істемеуі мүмкін."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Қолданба қосымша дисплейлерде іске қосуды қолдамайды."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Қолданба қалқыма терезеге қолдау көрсетпейді."</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Экранды бөлу режимінің бөлгіші"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Экранды бөлу режимінің бөлгіші"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Сол жағын толық экранға шығару"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Терезелерді басқару"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Арақатынасты өзгерту"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Көріністі оңтайландыру"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Қате белгішесі"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Жабу"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Мәзірді жабу"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (компьютерлік терезелер режимі)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Экранды ұлғайту"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Өлшемін өзгерту"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Қолданба бұл жерге қойылмайды."</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Жаңа қолданба терезесін ашу"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Қолданба терезесі жабылып жатыр"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Қолданба терезесін кішірейту"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ерекшеленген)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ерекшеленбеген)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Иммерсивтік әсер"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Қалпына келтіру"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Жаю"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"អាចបើកកម្មវិធីនេះបានតែក្នុងវិនដូ 1 ប៉ុណ្ណោះ"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"កម្មវិធីនេះប្រហែលជាមិនដំណើរការនៅលើអេក្រង់បន្ទាប់បន្សំទេ។"</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"កម្មវិធីនេះមិនអាចចាប់ផ្តើមនៅលើអេក្រង់បន្ទាប់បន្សំបានទេ។"</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"កម្មវិធីមិនអាចប្រើផ្ទាំងសារបានទេ"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"បន្ទាត់ខណ្ឌចែកក្នុងមុខងារបំបែកអេក្រង់"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"បន្ទាត់ខណ្ឌចែកក្នុងមុខងារបំបែកអេក្រង់"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"អេក្រង់ពេញខាងឆ្វេង"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"គ្រប់គ្រងវិនដូ"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"ប្ដូរសមាមាត្រ"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"បង្កើនប្រសិទ្ធភាពការមើល"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"រូបបញ្ហា"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"បិទ"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"បិទម៉ឺនុយ"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (មុខងារវិនដូកុំព្យូទ័រ)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ពង្រីកអេក្រង់"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ប្ដូរទំហំ"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"មិនអាចផ្លាស់ទីកម្មវិធីមកទីនេះបានទេ"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"ការបើកវិនដូកម្មវិធីថ្មី"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"កំពុងបិទវិនដូកម្មវិធី"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"ការបង្រួមវិនដូកម្មវិធី"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (បានផ្ដោត)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (មិនបានផ្ដោត)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ជក់ចិត្ត"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ស្ដារ"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"ពង្រីក"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"ಈ ಆ್ಯಪ್ ಅನ್ನು 1 ವಿಂಡೋದಲ್ಲಿ ಮಾತ್ರ ತೆರೆಯಬಹುದು"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ಸೆಕೆಂಡರಿ ಡಿಸ್ಪ್ಲೇಗಳಲ್ಲಿ ಆ್ಯಪ್ ಕಾರ್ಯ ನಿರ್ವಹಿಸದೇ ಇರಬಹುದು."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ಸೆಕೆಂಡರಿ ಡಿಸ್ಪ್ಲೇಗಳಲ್ಲಿ ಪ್ರಾರಂಭಿಸುವಿಕೆಯನ್ನು ಆ್ಯಪ್ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"ಬಬಲ್ ಅನ್ನು ಆ್ಯಪ್ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಡಿವೈಡರ್"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಡಿವೈಡರ್"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ಎಡ ಫುಲ್ ಸ್ಕ್ರೀನ್"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"ವಿಂಡೋಗಳನ್ನು ನಿರ್ವಹಿಸಿ"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"ದೃಶ್ಯಾನುಪಾತವನ್ನು ಬದಲಾಯಿಸಿ"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"ವೀಕ್ಷಣೆಯನ್ನು ಆಪ್ಟಿಮೈಸ್ ಮಾಡಿ"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"ದೋಷದ ಐಕಾನ್"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"ಮುಚ್ಚಿ"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"ಮೆನು ಮುಚ್ಚಿ"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ಡೆಸ್ಕ್ಟಾಪ್ ವಿಂಡೋಯಿಂಗ್)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ಸ್ಕ್ರೀನ್ ಅನ್ನು ಮ್ಯಾಕ್ಸಿಮೈಸ್ ಮಾಡಿ"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ಮರುಗಾತ್ರಗೊಳಿಸಿ"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ಆ್ಯಪ್ ಅನ್ನು ಇಲ್ಲಿಗೆ ಸರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"ಹೊಸ ಆ್ಯಪ್ ವಿಂಡೋವನ್ನು ತೆರೆಯಲಾಗುತ್ತಿದೆ"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"ಆ್ಯಪ್ ವಿಂಡೋವನ್ನು ಮುಚ್ಚಲಾಗುತ್ತಿದೆ"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"ಆ್ಯಪ್ ವಿಂಡೋವನ್ನು ಮಿನಿಮೈಸ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ಫೋಕಸ್ ಮಾಡಲಾಗಿದೆ)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ಫೋಕಸ್ ಮಾಡಲಾಗಿಲ್ಲ)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ಇಮ್ಮರ್ಸಿವ್"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ಮರುಸ್ಥಾಪಿಸಿ"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"ಮ್ಯಾಕ್ಸಿಮೈಸ್ ಮಾಡಿ"</string>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ಶೀರ್ಷಿಕೆ ರಹಿತ ಕಾರ್ಯಕ್ರಮ)"</string>
|
||||
<string name="pip_close" msgid="2955969519031223530">"ಮುಚ್ಚಿರಿ"</string>
|
||||
<string name="pip_fullscreen" msgid="7278047353591302554">"ಫುಲ್ ಸ್ಕ್ರೀನ್"</string>
|
||||
<string name="pip_move" msgid="158770205886688553">"ಸರಿಸಿ"</string>
|
||||
<string name="pip_move" msgid="158770205886688553">"ಮೂವ್"</string>
|
||||
<string name="pip_expand" msgid="1051966011679297308">"ವಿಸ್ತೃತಗೊಳಿಸಿ"</string>
|
||||
<string name="pip_collapse" msgid="3903295106641385962">"ಕುಗ್ಗಿಸಿ"</string>
|
||||
<string name="pip_edu_text" msgid="7930546669915337998">"ಕಂಟ್ರೋಲ್ಗಳಿಗಾಗಿ "<annotation icon="home_icon">"ಹೋಮ್"</annotation>" ಅನ್ನು ಎರಡು ಬಾರಿ ಒತ್ತಿರಿ"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"이 앱은 창 1개에서만 열 수 있습니다."</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"앱이 보조 디스플레이에서 작동하지 않을 수도 있습니다."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"앱이 보조 디스플레이에서의 실행을 지원하지 않습니다."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"앱이 풍선을 지원하지 않습니다."</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"화면 분할기"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"화면 분할기"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"왼쪽 화면 전체화면"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"창 관리"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"가로세로 비율 변경"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"뷰 최적화"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"오류 아이콘"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"닫기"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"메뉴 닫기"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g>(데스크톱 윈도윙)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"화면 최대화"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"크기 조절"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"앱을 여기로 이동할 수 없음"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"새 앱 창 열기"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"앱 창 닫기"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"앱 창 최소화"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g>(포커스)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g>(포커스되지 않음)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"몰입형"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"복원"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"최대화하기"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Бул колдонмону 1 терезеде гана ачууга болот"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Колдонмо кошумча экранда иштебей коюшу мүмкүн."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Колдонмону кошумча экрандарда иштетүүгө болбойт."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Колдонмо көбүкчөнү колдоого албайт"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Экранды бөлгүч"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Экранды бөлгүч"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Сол жактагы экранды толук экран режимине өткөрүү"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Терезелерди тескөө"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Тараптардын катнашын өзгөртүү"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Көрүнүштү оптималдаштыруу"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Ката сүрөтчөсү"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Жабуу"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Менюну жабуу"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Иш тактанын терезелери)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Экранды чоңойтуу"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Өлчөмүн өзгөртүү"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Колдонмону бул жерге жылдырууга болбойт"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Колдонмонун жаңы терезесин ачуу"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Колдонмо терезеси жабылууда"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Колдонмонун терезесин кичирейтүү"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Иштеп жатат)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Иштебей турат)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Сүңгүтүүчү"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Калыбына келтирүү"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Чоңойтуу"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"ແອັບນີ້ສາມາດເປີດໄດ້ໃນ 1 ໜ້າຈໍເທົ່ານັ້ນ"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ແອັບອາດບໍ່ສາມາດໃຊ້ໄດ້ໃນໜ້າຈໍທີສອງ."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ແອັບບໍ່ຮອງຮັບການເປີດໃນໜ້າຈໍທີສອງ."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"ແອັບບໍ່ຮອງຮັບຟອງ"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"ເສັ້ນແບ່ງໜ້າຈໍ"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"ເສັ້ນແບ່ງໜ້າຈໍ"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ເຕັມໜ້າຈໍຊ້າຍ"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"ຈັດການໜ້າຈໍ"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"ປ່ຽນອັດຕາສ່ວນຮູບ"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"ມຸມມອງເພີ່ມປະສິດທິພາບ"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"ໄອຄອນຂໍ້ຜິດພາດ"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"ປິດ"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"ປິດເມນູ"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ໜ້າຈໍເດັສທັອບ)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ປັບຈໍໃຫຍ່ສຸດ"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ປັບຂະໜາດ"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ບໍ່ສາມາດຍ້າຍແອັບມາບ່ອນນີ້ໄດ້"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"ກຳລັງເປີດໜ້າຈໍແອັບໃໝ່"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"ກຳລັງປິດໜ້າຈໍແອັບ"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"ກຳລັງຫຍໍ້ໜ້າຈໍແອັບ"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ໂຟກັສ)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ບໍ່ໂຟກັສ)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ສົມຈິງ"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ກູ້ຄືນ"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"ຂະຫຍາຍໃຫຍ່ສຸດ"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Šią programą galima atidaryti tik viename lange"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Programa gali neveikti antriniame ekrane."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Programa nepalaiko paleisties antriniuose ekranuose."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Programa nepalaiko pokalbio debesėlio"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Išskaidyto ekrano režimo daliklis"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Išskaidyto ekrano režimo daliklis"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Kairysis ekranas viso ekrano režimu"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Tvarkyti langus"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Keisti kraštinių santykį"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimizuoti rodinį"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Klaidos piktograma"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Uždaryti"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Uždaryti meniu"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ (versijos staliniams kompiuteriams rodinys)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Išskleisti ekraną"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Pakeisti dydį"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Programos negalima perkelti čia"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Atidaromas naujas programos langas"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Uždaromas programos langas"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Sumažinamas programos langas"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ (paryškinta)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ (neparyškinta)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Įtraukiantis"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Atkurti"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Padidinti"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Šo lietotni var atvērt tikai vienā logā"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Lietotne, iespējams, nedarbosies sekundārajā displejā."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Lietotnē netiek atbalstīta palaišana sekundārajos displejos."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Lietotnē netiek atbalstīts burbulis"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Ekrāna sadalītājs"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Ekrāna sadalītājs"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Kreisā daļa pa visu ekrānu"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Pārvaldīt logus"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Mainīt malu attiecību"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimizēt skatu"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Kļūdas ikona"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Aizvērt"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Aizvērt izvēlni"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (darbvirsmas logošana)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimizēt ekrānu"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Mainīt lielumu"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Lietotni nevar pārvietot šeit."</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Tiek atvērts jauns lietotnes logs"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Tiek aizvērts lietotnes logs"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Tiek minimizēts lietotnes logs"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (fokusā)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (nav fokusā)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Iekļaujoši"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Atjaunot"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimizēt"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Апликацијава може да се отвори само во еден прозорец"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апликацијата може да не функционира на друг екран."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Апликацијата не поддржува стартување на други екрани."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Апликацијата не поддржува балонче"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Разделник на поделен екран"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Разделник на поделен екран"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Левиот на цел екран"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Управувајте со прозорците"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Промени го соодносот"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Оптимизирај го приказот"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Икона за грешка"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Затворете"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Затворете го менито"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (режим со прозорци на работната површина)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Максимизирај го екранот"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Смени големина"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Апликацијата не може да се премести овде"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Отворање нов прозорец на апликацијата"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Се затвора прозорецот на апликацијата"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Минимизирање на прозорецот на апликацијата"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (фокусирано)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (не е фокусирано)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Реалистично"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Врати"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Максимизирај"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"ഈ ആപ്പ് ഒരു വിൻഡോയിൽ മാത്രമേ തുറക്കാനാകൂ"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"രണ്ടാം ഡിസ്പ്ലേയിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"രണ്ടാം ഡിസ്പ്ലേകളിൽ സമാരംഭിക്കുന്നതിനെ ആപ്പ് അനുവദിക്കുന്നില്ല."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"ബബിളിനെ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"സ്ക്രീൻ വിഭജന മോഡ് ഡിവൈഡർ"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"സ്ക്രീൻ വിഭജന മോഡ് ഡിവൈഡർ"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ഇടത് പൂർണ്ണ സ്ക്രീൻ"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"വിൻഡോകൾ മാനേജ് ചെയ്യുക"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"വീക്ഷണ അനുപാതം മാറ്റുക"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"കാഴ്ച ഒപ്റ്റിമൈസ് ചെയ്യുക"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"പിശക് ഐക്കൺ"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"അടയ്ക്കുക"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"മെനു അടയ്ക്കുക"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ഡെസ്ക്ടോപ്പ് വിൻഡോയിംഗ്)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"സ്ക്രീൻ വലുതാക്കുക"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"വലുപ്പം മാറ്റുക"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ആപ്പ് ഇവിടേക്ക് നീക്കാനാകില്ല"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"പുതിയ ആപ്പ് വിൻഡോ തുറക്കുന്നു"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"ആപ്പ് വിൻഡോ അടയ്ക്കുന്നു"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"ആപ്പ് വിൻഡോ മിനിമൈസ് ചെയ്യുന്നു"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ഫോക്കസ് ചെയ്തവ)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ഫോക്കസ് ചെയ്യാത്തവ)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ഇമേഴ്സീവ്"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"പുനഃസ്ഥാപിക്കുക"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"വലുതാക്കുക"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Энэ аппыг зөвхөн 1 цонхонд нээх боломжтой"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апп хоёрдогч дэлгэцэд ажиллахгүй."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Аппыг хоёрдогч дэлгэцэд эхлүүлэх боломжгүй."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Апп бөмбөлгийг дэмждэггүй"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Дэлгэцийг хуваах хуваагч"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Дэлгэцийг хуваах хуваагч"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Зүүн талын бүтэн дэлгэц"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Цонхнуудыг удирдах"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Аспектын харьцааг өөрчлөх"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Харагдах байдлыг оновчлох"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Алдааны дүрс тэмдэг"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Хаах"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Цэсийг хаах"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Дэлгэцийн цонх үүсгэх онцлог)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Дэлгэцийг томруулах"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Хэмжээг өөрчлөх"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Аппыг ийш зөөх боломжгүй"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Аппын шинэ цонхыг нээж байна"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Аппын цонхыг хааж байна"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Аппын цонхыг жижгэрүүлж байна"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (сонгосон)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (сонгоогүй)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Бодит мэт"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Сэргээх"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Томруулах"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"हे अॅप फक्त एका विंडोमध्ये उघडले जाऊ शकते"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"दुसऱ्या डिस्प्लेवर अॅप कदाचित चालणार नाही."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"दुसऱ्या डिस्प्लेवर अॅप लाँच होणार नाही."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"अॅप बबलला सपोर्ट करत नाही"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"स्प्लिट स्क्रीन विभाजक"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"स्प्लिट स्क्रीन विभाजक"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"डावी फुल स्क्रीन"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"विंडो व्यवस्थापित करा"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"आस्पेक्ट रेशो बदला"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"दृश्य ऑप्टिमाइझ करा"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"एरर आयकन"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"बंद करा"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"मेनू बंद करा"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (डेस्कटॉप विंडोइंग)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रीन मोठी करा"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"आकार बदला"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"अॅप इथे हलवू शकत नाही"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"नवीन अॅप विंडो उघडत आहे"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"अॅपची विंडो बंद करत आहे"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"अॅप विंडो लहान करत आहे"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (फोकस केलेले)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (फोकस न केलेले)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"इमर्सिव्ह"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"रिस्टोअर करा"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"मोठे करा"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Apl ini hanya boleh dibuka dalam 1 tetingkap"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Apl mungkin tidak berfungsi pada paparan kedua."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Apl tidak menyokong pelancaran pada paparan kedua."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Apl tidak menyokong gelembung"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Pembahagi skrin pisah"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Pembahagi skrin pisah"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Skrin penuh kiri"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Urus Tetingkap"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Tukar nisbah bidang"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimumkan Paparan"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Ikon Ralat"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Tutup"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Tutup Menu"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Tetingkap desktop)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimumkan Skrin"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Ubah saiz"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Apl tidak boleh dialihkan ke sini"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Membuka tetingkap apl baharu"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Menutup tetingkap apl"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Meminimumkan tetingkap apl"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Terfokus)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Tidak terfokus)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Mengasyikkan"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Pulihkan"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimumkan"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"ဤအက်ပ်ကို ဝင်းဒိုး ၁ ခုတွင်သာ ဖွင့်နိုင်သည်"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ဤအက်ပ်အနေဖြင့် ဒုတိယဖန်သားပြင်ပေါ်တွင် အလုပ်လုပ်မည် မဟုတ်ပါ။"</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ဤအက်ပ်အနေဖြင့် ဖွင့်ရန်စနစ်ကို ဒုတိယဖန်သားပြင်မှ အသုံးပြုရန် ပံ့ပိုးမထားပါ။"</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"အက်ပ်သည် ပူဖောင်းကွက်ကို မပံ့ပိုးပါ"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"မျက်နှာပြင် ခွဲ၍ပြသခြင်း ပိုင်းခြားစနစ်"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"မျက်နှာပြင် ခွဲ၍ပြသခြင်း ပိုင်းခြားစနစ်"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ဘယ်ဘက် မျက်နှာပြင်အပြည့်"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"ဝင်းဒိုးများ စီမံရန်"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"အချိုးအစား ပြောင်းရန်"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"မြင်ကွင်းကို ပိုကောင်းအောင်လုပ်ရန်"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"အမှားအယွင်း သင်္ကေတ"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"ပိတ်ရန်"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"မီနူး ပိတ်ရန်"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ဒက်စ်တော့ဝင်းဒိုးမုဒ်)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"စခရင်ကို ချဲ့မည်"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"အရွယ်ပြင်ရန်"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"အက်ပ်ကို ဤနေရာသို့ ရွှေ့၍မရပါ"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"အက်ပ်ဝင်းဒိုးအသစ် ဖွင့်နေသည်"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"အက်ပ်ဝင်းဒိုး ပိတ်ခြင်း"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"အက်ပ်ဝင်းဒိုးကို ချုံ့နေသည်"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (အာရုံပြုထားသည်)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (အာရုံပြုမထားပါ)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ဘက်ပေါင်းစုံ"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ပြန်ပြောင်းရန်"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"ချဲ့ရန်"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Denne appen kan bare åpnes i ett vindu"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen fungerer kanskje ikke på en sekundær skjerm."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Appen kan ikke kjøres på sekundære skjermer."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"Appen støtter ikke bobler"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Skilleelement for delt skjerm"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Skilleelement for delt skjerm"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Utvid den venstre delen av skjermen til hele skjermen"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Administrer vinduene"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Endre høyde/bredde-forholdet"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Optimaliser visning"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Feilikon"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Lukk"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Lukk menyen"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (datamaskin-vindusvisning)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimer skjermen"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Endre størrelse"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Appen kan ikke flyttes hit"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Åpner et nytt appvindu"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"Lukker appvinduet"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"Minimerer appvinduet"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (fokusert)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ikke fokusert)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Oppslukende"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Gjenopprett"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimer"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"यो एप एउटा विन्डोमा मात्र खोल्न मिल्छ"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"यो एपले सहायक प्रदर्शनमा काम नगर्नसक्छ।"</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"एपले सहायक प्रदर्शनहरूमा लञ्च सुविधालाई समर्थन गर्दैन।"</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"एपमा बबल प्रयोग गर्न मिल्दैन"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"स्प्लिट स्क्रिन डिभाइडर"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"स्प्लिट स्क्रिन डिभाइडर"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"बायाँ भाग फुल स्क्रिन"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"विन्डोहरू व्यवस्थापन गर्नुहोस्"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"एस्पेक्ट रेसियो परिवर्तन गर्नुहोस्"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"भ्यू अप्टिमाइज गर्नुहोस्"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"त्रुटि जनाउने आइकन"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"बन्द गर्नुहोस्"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"मेनु बन्द गर्नुहोस्"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (डेस्कटप विन्डोइङ)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रिन ठुलो बनाउनुहोस्"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"आकार बदल्नुहोस्"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"एप सारेर यहाँ ल्याउन सकिएन"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"एपको नयाँ विन्डो खोल्नुहोस्"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"एपको विन्डो बन्द गरिँदै छ"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"एपको विन्डो मिनिमाइज गरिँदै छ"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (फोकस गरिएको)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (फोकस नगरिएको)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"इमर्सिभ"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"रिस्टोर गर्नुहोस्"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"ठुलो बनाउनुहोस्"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"Deze app kan maar in 1 venster worden geopend"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App werkt mogelijk niet op een secundair scherm."</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App kan niet op secundaire displays worden gestart."</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"App ondersteunt geen bubbel"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"Scheiding voor gesplitst scherm"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"Scheiding voor gesplitst scherm"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Linkerscherm op volledig scherm"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"Vensters beheren"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"Beeldverhouding wijzigen"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"Weergave optimaliseren"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"Fouticoon"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"Sluiten"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"Menu sluiten"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (desktopvensterfunctie)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Scherm maximaliseren"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Formaat aanpassen"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Kan de app niet hierheen verplaatsen"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"Nieuw app-venster openen"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"App-venster sluiten"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"App-venster minimaliseren"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (gefocust)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (niet gefocust)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Immersief"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Herstellen"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maximaliseren"</string>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="dock_multi_instances_not_supported_text" msgid="5011042177901502928">"ଏହି ଆପକୁ କେବଳ 1ଟି ୱିଣ୍ଡୋରେ ଖୋଲାଯାଇପାରିବ"</string>
|
||||
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ସେକେଣ୍ଡାରୀ ଡିସପ୍ଲେରେ ଆପ୍ କାମ ନକରିପାରେ।"</string>
|
||||
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ସେକେଣ୍ଡାରୀ ଡିସପ୍ଲେରେ ଆପ୍ ଲଞ୍ଚ ସପୋର୍ଟ କରେ ନାହିଁ।"</string>
|
||||
<string name="bubble_not_supported_text" msgid="8843806122229754809">"ଆପ ବବଲକୁ ସପୋର୍ଟ କରେ ନାହିଁ"</string>
|
||||
<string name="accessibility_divider" msgid="6407584574218956849">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ଡିଭାଇଡର"</string>
|
||||
<string name="divider_title" msgid="1963391955593749442">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ଡିଭାଇଡର"</string>
|
||||
<string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ବାମ ପଟକୁ ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍ କରନ୍ତୁ"</string>
|
||||
@@ -133,12 +134,18 @@
|
||||
<string name="manage_windows_text" msgid="5567366688493093920">"ୱିଣ୍ଡୋଗୁଡ଼ିକୁ ପରିଚାଳନା କରନ୍ତୁ"</string>
|
||||
<string name="change_aspect_ratio_text" msgid="9104456064548212806">"ଚଉଡ଼ା ଓ ଉଚ୍ଚତାର ଅନୁପାତ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
|
||||
<string name="handle_menu_restart_text" msgid="3907767216238298098">"ଭ୍ୟୁ ଅପ୍ଟିମାଇଜ କରନ୍ତୁ"</string>
|
||||
<string name="handle_menu_error_icon_text" msgid="7200375184879808684">"ତ୍ରୁଟି ଆଇକନ"</string>
|
||||
<string name="close_text" msgid="4986518933445178928">"ବନ୍ଦ କରନ୍ତୁ"</string>
|
||||
<string name="collapse_menu_text" msgid="7515008122450342029">"ମେନୁ ବନ୍ଦ କରନ୍ତୁ"</string>
|
||||
<string name="desktop_mode_app_header_chip_text" msgid="7617377295944971651">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ଡେସ୍କଟପ ୱିଣ୍ଡୋଇଂ)"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ସ୍କ୍ରିନକୁ ବଡ଼ କରନ୍ତୁ"</string>
|
||||
<string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ରିସାଇଜ କରନ୍ତୁ"</string>
|
||||
<string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ଆପକୁ ଏଠାକୁ ମୁଭ କରାଯାଇପାରିବ ନାହିଁ"</string>
|
||||
<string name="desktop_mode_talkback_state_opening" msgid="8505494249513712682">"ନୂଆ ଆପ ୱିଣ୍ଡୋ ଖୋଲୁଛି"</string>
|
||||
<string name="desktop_mode_talkback_state_closing" msgid="6791583518636526904">"ଆପ ୱିଣ୍ଡୋକୁ ବନ୍ଦ କରାଯାଉଛି"</string>
|
||||
<string name="desktop_mode_talkback_state_minimizing" msgid="7406911785134757827">"ଆପ ୱିଣ୍ଡୋକୁ ଛୋଟ କରନ୍ତୁ"</string>
|
||||
<string name="desktop_mode_talkback_state_focused" msgid="6287982923335568236">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ଫୋକସ କରାଯାଇଛି)"</string>
|
||||
<string name="desktop_mode_talkback_state_not_focused" msgid="4640618691603218929">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ଫୋକସ କରାଯାଇନାହିଁ)"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"ଇମର୍ସିଭ"</string>
|
||||
<string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"ରିଷ୍ଟୋର କରନ୍ତୁ"</string>
|
||||
<string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"ବଡ଼ କରନ୍ତୁ"</string>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user