diff options
637 files changed, 18382 insertions, 1844 deletions
diff --git a/Android.bp b/Android.bp index 598beb6dd..f10c0b400 100644 --- a/Android.bp +++ b/Android.bp @@ -27,6 +27,28 @@ license { license_text: [], } +aconfig_declarations { + name: "docsui-flags-aconfig", + package: "com.android.documentsui.flags", + container: "system", + srcs: ["flags.aconfig"], +} + +java_aconfig_library { + name: "docsui-flags-aconfig-java-lib", + aconfig_declarations: "docsui-flags-aconfig", + min_sdk_version: "29", + sdk_version: "system_current", +} + +java_library { + name: "docsui-change-ids", + srcs: ["src/com/android/documentsui/ChangeIds.java"], + libs: ["app-compat-annotations"], + min_sdk_version: "29", + sdk_version: "system_current", +} + java_defaults { name: "documentsui_defaults", @@ -40,14 +62,11 @@ java_defaults { "androidx.transition_transition", "apache-commons-compress", "com.google.android.material_material", + "docsui-change-ids", "guava", "modules-utils-build_system", ], - libs: [ - "app-compat-annotations", - ], - privileged: true, certificate: "platform", @@ -59,21 +78,11 @@ java_defaults { sdk_version: "system_current", min_sdk_version: "29", - - lint: { strict_updatability_linting: true } } platform_compat_config { name: "documents-ui-compat-config", - src: ":DocumentsUI", -} - -filegroup { - name: "DocumentsUI-srcs", - srcs: [ - "src/**/*.java", - ":statslog-docsui-java-gen", - ], + src: ":docsui-change-ids", } java_library { @@ -81,26 +90,29 @@ java_library { srcs: [ ":statslog-docsui-java-gen", ], - lint: { strict_updatability_linting: true } + libs: [ + "androidx.annotation_annotation", + ], + lint: { + strict_updatability_linting: true, + }, } genrule { name: "statslog-docsui-java-gen", tools: ["stats-log-api-gen"], cmd: "$(location stats-log-api-gen) --java $(out) --module docsui" + - " --javaPackage com.android.documentsui --javaClass DocumentsStatsLog --minApiLevel 29", + " --javaPackage com.android.documentsui --javaClass DocumentsStatsLog --minApiLevel 29", out: ["com/android/documentsui/DocumentsStatsLog.java"], } android_library { - name: "DocumentsUI-res-lib", - - manifest: "AndroidManifest.xml", + name: "DocumentsUI-lib", + defaults: ["documentsui_defaults"], + static_libs: ["docsui-flags-aconfig-java-lib"], + flags_packages: ["docsui-flags-aconfig"], - static_libs: [ - "androidx.appcompat_appcompat", - "com.google.android.material_material", - ], + manifest: "AndroidManifestLib.xml", resource_dirs: [ "res", @@ -110,40 +122,36 @@ android_library { "--auto-add-overlay", ], + // This is included in `documentsui_defaults`. + exclude_srcs: ["src/com/android/documentsui/ChangeIds.java"], + + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ":statslog-docsui-java-gen", + ], + sdk_version: "system_current", target_sdk_version: "33", min_sdk_version: "29", - lint: { strict_updatability_linting: true } + lint: { + baseline_filename: "lint-baseline.xml", + }, } android_library { - name: "DocumentsUIUnitTests-res-lib", - - manifest: "AndroidManifestForUnitTests.xml", - - static_libs: [ - "androidx.appcompat_appcompat", - "com.google.android.material_material", - "modules-utils-build_system", - ], - - resource_dirs: [ - "res", - ], + name: "DocumentsUIManifestLib", + defaults: ["documentsui_defaults"], - licenses: [ - "Android-Apache-2.0", - "packages_apps_DocumentsUI_res_drawable_pd_license", - ], + manifest: "AndroidManifest.xml", + flags_packages: ["docsui-flags-aconfig"], - aaptflags: [ - "--auto-add-overlay", - ], + resource_dirs: [], + libs: ["DocumentsUI-lib"], sdk_version: "system_current", target_sdk_version: "33", min_sdk_version: "29", - lint: { strict_updatability_linting: true } } android_app { @@ -153,13 +161,10 @@ android_app { manifest: "AndroidManifest.xml", - srcs: [ - ":DocumentsUI-srcs", - ], + static_libs: ["DocumentsUI-lib"], + resource_dirs: [], - resource_dirs: [ - "res", - ], + flags_packages: ["docsui-flags-aconfig"], licenses: [ "Android-Apache-2.0", @@ -170,6 +175,4 @@ android_app { min_sdk_version: "29", updatable: true, - lint: { strict_updatability_linting: true } } - diff --git a/AndroidManifest.xml b/AndroidManifest.xml index f536d8184..1fa1ac3b6 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -19,7 +19,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.documentsui"> - <uses-sdk android:minSdkVersion="29"/> + <uses-sdk android:minSdkVersion="30"/> <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" /> <uses-permission android:name="android.permission.REMOVE_TASKS" /> @@ -41,6 +41,9 @@ <uses-permission android:name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"/> + <!-- Permissions required for reading device configs --> + <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/> + <application android:name=".DocumentsApplication" android:label="@string/app_label" @@ -49,6 +52,7 @@ android:allowBackup="true" android:backupAgent=".prefs.BackupAgent" android:fullBackupOnly="false" + android:enableOnBackInvokedCallback="false" android:crossProfile="true"> <meta-data @@ -56,29 +60,67 @@ android:value="AEdPqrEAAAAInBA8ued0O_ZyYUsVhwinUF-x50NIe9K0GzBW4A" /> <activity + android:name=".picker.TrampolineActivity" + android:exported="true" + android:theme="@android:style/Theme.NoDisplay" + android:featureFlag="com.android.documentsui.flags.redirect_get_content" + android:visibleToInstantApps="true"> + <intent-filter android:priority="120"> + <action android:name="android.intent.action.OPEN_DOCUMENT" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.OPENABLE" /> + <data android:mimeType="*/*" /> + </intent-filter> + <intent-filter android:priority="120"> + <action android:name="android.intent.action.CREATE_DOCUMENT" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.OPENABLE" /> + <data android:mimeType="*/*" /> + </intent-filter> + <intent-filter android:priority="120"> + <action android:name="android.intent.action.GET_CONTENT" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.OPENABLE" /> + <data android:mimeType="*/*" /> + </intent-filter> + <intent-filter android:priority="120"> + <action android:name="android.intent.action.OPEN_DOCUMENT_TREE" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + + <activity android:name=".picker.PickActivity" android:exported="true" android:theme="@style/LauncherTheme" android:visibleToInstantApps="true"> - <intent-filter android:priority="100"> + <intent-filter + android:featureFlag="!com.android.documentsui.flags.redirect_get_content" + android:priority="100"> <action android:name="android.intent.action.OPEN_DOCUMENT" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.OPENABLE" /> <data android:mimeType="*/*" /> </intent-filter> - <intent-filter android:priority="100"> + <intent-filter + android:featureFlag="!com.android.documentsui.flags.redirect_get_content" + android:priority="100"> <action android:name="android.intent.action.CREATE_DOCUMENT" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.OPENABLE" /> <data android:mimeType="*/*" /> </intent-filter> - <intent-filter android:priority="100"> + <intent-filter + android:featureFlag="!com.android.documentsui.flags.redirect_get_content" + android:priority="100"> <action android:name="android.intent.action.GET_CONTENT" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.OPENABLE" /> <data android:mimeType="*/*" /> </intent-filter> - <intent-filter android:priority="100"> + <intent-filter + android:featureFlag="!com.android.documentsui.flags.redirect_get_content" + android:priority="100"> <action android:name="android.intent.action.OPEN_DOCUMENT_TREE" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> @@ -207,15 +249,5 @@ android:process=":com.android.documentsui.services"> </service> - <activity - android:name=".selection.demo.SelectionDemoActivity" - android:label="Selection Demo" - android:exported="true" - android:theme="@style/DocumentsTheme"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - </intent-filter> - </activity> - </application> </manifest> diff --git a/AndroidManifestForUnitTests.xml b/AndroidManifestLib.xml index 993d4409a..b7e54192b 100644 --- a/AndroidManifestForUnitTests.xml +++ b/AndroidManifestLib.xml @@ -18,7 +18,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.documentsui"> - <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" /> + <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" /> <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" /> <uses-permission android:name="android.permission.REMOVE_TASKS" /> @@ -1,3 +1,6 @@ # Bug component: 46626 -include platform/frameworks/base:/core/java/android/os/storage/OWNERS
\ No newline at end of file +include platform/frameworks/base:/core/java/android/os/storage/OWNERS + +benreich@google.com +alexbn@google.com diff --git a/TEST_MAPPING b/TEST_MAPPING index 8036110a0..6de67146a 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -7,5 +7,13 @@ { "name": "DocumentsUIUnitTests" } + ], + "desktop-postsubmit": [ { + "name": "DocumentsUIGoogleTests", + "keywords": ["primary-device"] + }, + { + "name": "DocumentsUIUnitTests" + } ] } diff --git a/app-perf-tests/Android.bp b/app-perf-tests/Android.bp index f753ac5b5..2d4bc0611 100644 --- a/app-perf-tests/Android.bp +++ b/app-perf-tests/Android.bp @@ -12,15 +12,15 @@ android_test { ], libs: [ - "android.test.base", - "android.test.runner", + "android.test.base.stubs.system", + "android.test.runner.stubs.system", ], static_libs: [ "androidx.legacy_legacy-support-v4", "collector-device-lib", "mockito-target", - "ub-uiautomator", + "androidx.test.uiautomator_uiautomator", ], platform_apis: true, diff --git a/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java b/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java index 8366c89f5..821198dbd 100644 --- a/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java +++ b/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java @@ -32,9 +32,10 @@ import android.content.pm.ResolveInfo; import android.os.Bundle; import android.os.SystemClock; import android.provider.DocumentsContract; -import android.support.test.uiautomator.UiDevice; import android.util.Log; +import androidx.test.uiautomator.UiDevice; + import org.junit.After; import org.junit.Before; import org.junit.Test; diff --git a/compose/Android.bp b/compose/Android.bp new file mode 100644 index 000000000..f00bf4c20 --- /dev/null +++ b/compose/Android.bp @@ -0,0 +1,62 @@ +// 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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_library { + name: "DocumentsUIComposelib", + manifest: "AndroidManifest.xml", + + resource_dirs: [ + "res", + ], + srcs: [ + "src/**/*.kt", + ], + + static_libs: [ + "androidx.activity_activity-compose", + "androidx.appcompat_appcompat", + "androidx.compose.foundation_foundation", + "androidx.compose.material3_material3", + "androidx.compose.material3_material3-window-size-class", + "androidx.compose.material_material-icons-extended", + "androidx.compose.runtime_runtime", + "androidx.compose.ui_ui", + "androidx.core_core-ktx", + "androidx.hilt_hilt-navigation-compose", + "androidx.lifecycle_lifecycle-runtime-compose", + "androidx.lifecycle_lifecycle-runtime-ktx", + "hilt_android", + "modules-utils-build_system", + ], + + sdk_version: "system_current", + target_sdk_version: "33", + min_sdk_version: "29", +} + +android_app { + name: "DocumentsUICompose", + manifest: "AndroidManifest.xml", + static_libs: ["DocumentsUIComposelib"], + + privileged: true, + certificate: "platform", + + sdk_version: "system_current", + min_sdk_version: "29", +} diff --git a/compose/AndroidManifest.xml b/compose/AndroidManifest.xml new file mode 100644 index 000000000..9b943e086 --- /dev/null +++ b/compose/AndroidManifest.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* + * 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. + */ +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.documentsui.compose"> + + <uses-sdk android:minSdkVersion="30"/> + + <!-- Permissions copied from com.android.documentsui AndroidManifest.xml --> + <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" /> + <uses-permission android:name="android.permission.REMOVE_TASKS" /> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/> + <uses-permission android:name="android.permission.WAKE_LOCK" /> + <uses-permission android:name="android.permission.CACHE_CONTENT" /> + <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> + <uses-permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES" /> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> + <uses-permission android:name="android.permission.MODIFY_QUIET_MODE" /> + <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> + <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> + <uses-permission android:name="android.permission.HIDE_OVERLAY_WINDOWS"/> + <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/> + <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/> + <uses-permission android:name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"/> + <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/> + + <application + android:name=".DocumentsUIApplication" + android:label="@string/app_label" + android:supportsRtl="true" + android:allowBackup="true" + android:theme="@style/Theme.DocumentsUINoTitleBar"> + + <activity + android:name=".MainActivity" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + </application> +</manifest> diff --git a/compose/OWNERS b/compose/OWNERS new file mode 100644 index 000000000..ee4568b02 --- /dev/null +++ b/compose/OWNERS @@ -0,0 +1,6 @@ +# Bug component: 374224390 + +wenbojie@google.com +benreich@google.com +lucmult@google.com +tylersaunders@google.com diff --git a/compose/README b/compose/README new file mode 100644 index 000000000..5ccfbeda3 --- /dev/null +++ b/compose/README @@ -0,0 +1,12 @@ +This folder is intended for Sydney Files team to experiment constructing Jetpack Compose components +for DocumentsUI. + +## Build and Install + +Use `brya` target as an example. + +```bash +lunch brya-trunk_staging-eng +m DocumentsUICompose +adb install out/target/product/brya/system/priv-app/DocumentsUICompose/DocumentsUICompose.apk +```
\ No newline at end of file diff --git a/res/menu/selection_demo_actions.xml b/compose/res/values/strings.xml index e07c06b12..a7acb0e66 100644 --- a/res/menu/selection_demo_actions.xml +++ b/compose/res/values/strings.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2017 The Android Open Source Project +<!-- 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. @@ -14,13 +14,6 @@ limitations under the License. --> -<menu xmlns:android="http://schemas.android.com/apk/res/android"> - <item - android:id="@+id/option_menu_add_column" - android:title="Add column" - android:showAsAction="always" /> - <item - android:id="@+id/option_menu_remove_column" - android:title="Remove column" - android:showAsAction="always" /> -</menu> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_label">DocsUI Compose</string> +</resources>
\ No newline at end of file diff --git a/compose/res/values/themes.xml b/compose/res/values/themes.xml new file mode 100644 index 000000000..95442b050 --- /dev/null +++ b/compose/res/values/themes.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <style name="Theme.DocumentsUINoTitleBar" parent="android:Theme.Material.Light.NoActionBar" /> +</resources>
\ No newline at end of file diff --git a/compose/src/com/android/documentsui/compose/DocumentsUIApplication.kt b/compose/src/com/android/documentsui/compose/DocumentsUIApplication.kt new file mode 100644 index 000000000..f6e0e811e --- /dev/null +++ b/compose/src/com/android/documentsui/compose/DocumentsUIApplication.kt @@ -0,0 +1,23 @@ +/* + * Copyright 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.documentsui.compose + +import android.app.Application +import dagger.hilt.android.HiltAndroidApp + +@HiltAndroidApp(Application::class) +class DocumentsUIApplication : Hilt_DocumentsUIApplication() diff --git a/compose/src/com/android/documentsui/compose/MainActivity.kt b/compose/src/com/android/documentsui/compose/MainActivity.kt new file mode 100644 index 000000000..8db5140f2 --- /dev/null +++ b/compose/src/com/android/documentsui/compose/MainActivity.kt @@ -0,0 +1,47 @@ +/* + * Copyright 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.documentsui.compose + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.ui.Modifier +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint(ComponentActivity::class) +class MainActivity : Hilt_MainActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + enableEdgeToEdge() + super.onCreate(savedInstanceState) + + setContent { + DocumentsUITheme { + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + Text(text = "DocumentsUI Compose") + } + } + } + } +} diff --git a/compose/src/com/android/documentsui/compose/Theme.kt b/compose/src/com/android/documentsui/compose/Theme.kt new file mode 100644 index 000000000..de6f7f34f --- /dev/null +++ b/compose/src/com/android/documentsui/compose/Theme.kt @@ -0,0 +1,48 @@ +/* + * Copyright 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.documentsui.compose + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import com.android.modules.utils.build.SdkLevel + +@Composable +fun DocumentsUITheme( + darkTheme: Boolean = isSystemInDarkTheme(), + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && SdkLevel.isAtLeastS() -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + darkTheme -> darkColorScheme() + else -> lightColorScheme() + } + + MaterialTheme( + colorScheme = colorScheme, + content = content + ) +} diff --git a/flags.aconfig b/flags.aconfig new file mode 100644 index 000000000..1c4369603 --- /dev/null +++ b/flags.aconfig @@ -0,0 +1,60 @@ +package: "com.android.documentsui.flags" +container: "system" + +flag { + name: "use_material3" + namespace: "documentsui" + description: "Use Material 3 theme and styles." + bug: "373720657" + is_fixed_read_only: true +} + +flag { + name: "use_search_v2" + namespace: "documentsui" + description: "Enables the next generation search functionality." + bug: "378590312" + is_fixed_read_only: true +} + +flag { + name: "zip_ng" + namespace: "documentsui" + description: "Enables the next generation ZIP functionality." + bug: "382550591" +} + +flag { + name: "desktop_file_handling" + namespace: "documentsui" + description: "Enables desktop file handling." + bug: "381778967" +} + +flag { + name: "visual_signals" + namespace: "documentsui" + description: "Enables in-app progress display of file operations" + bug: "378011512" +} + +flag { + name: "hide_roots_on_desktop" + namespace: "documentsui" + description: "Enables the hiding of the Images/Videos/Audio/Documents roots on desktop." + bug: "381959330" +} + +flag { + name: "redirect_get_content" + namespace: "documentsui" + description: "Redirects GET_CONTENT requests to Photopicker when appropriate" + bug: "377771195" +} + +flag { + name: "use_peek_preview" + namespace: "documentsui" + description: "Enables the Peek previewing capability as a substitute for the Inspector." + bug: "373242058" +} diff --git a/lint-baseline.xml b/lint-baseline.xml index c7db33135..a89103e53 100644 --- a/lint-baseline.xml +++ b/lint-baseline.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev"> +<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01"> <issue id="NewApi" diff --git a/perf-tests/Android.bp b/perf-tests/Android.bp index 955b1c031..1559227b6 100644 --- a/perf-tests/Android.bp +++ b/perf-tests/Android.bp @@ -8,7 +8,6 @@ android_test { manifest: "AndroidManifest.xml", srcs: [ - ":DocumentsUIPerfTests-files", "src/**/*.java", ], @@ -17,18 +16,19 @@ android_test { ], libs: [ - "android.test.base", - "android.test.mock", - "android.test.runner", + "android.test.base.stubs.system", + "android.test.mock.stubs.system", + "android.test.runner.stubs.system", ], static_libs: [ + "DocumentsUIPerfTests-lib", "androidx.legacy_legacy-support-v4", "androidx.test.rules", "androidx.test.espresso.core", "mockito-target", "ub-janktesthelper", - "ub-uiautomator", + "androidx.test.uiautomator_uiautomator", ], platform_apis: true, diff --git a/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java b/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java index 33ef73e5e..f7c295dc9 100644 --- a/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java +++ b/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java @@ -24,12 +24,12 @@ import android.app.Activity; import android.net.Uri; import android.os.Bundle; import android.os.RemoteException; -import android.test.suitebuilder.annotation.LargeTest; + +import androidx.test.filters.LargeTest; import com.android.documentsui.BaseActivity.EventListener; import com.android.documentsui.base.RootInfo; import com.android.documentsui.files.FilesActivity; -import com.android.documentsui.ActivityTest; import java.util.ArrayList; import java.util.Arrays; diff --git a/perf-tests/src/com/android/documentsui/FilesJankPerfTest.java b/perf-tests/src/com/android/documentsui/FilesJankPerfTest.java index 04dfc7882..8054c3814 100644 --- a/perf-tests/src/com/android/documentsui/FilesJankPerfTest.java +++ b/perf-tests/src/com/android/documentsui/FilesJankPerfTest.java @@ -16,27 +16,24 @@ package com.android.documentsui; -import static com.android.documentsui.StressProvider.DEFAULT_AUTHORITY; -import static com.android.documentsui.StressProvider.STRESS_ROOT_0_ID; import static com.android.documentsui.StressProvider.STRESS_ROOT_2_ID; import android.app.Activity; -import android.os.RemoteException; -import android.test.suitebuilder.annotation.LargeTest; - import android.app.UiAutomation; -import android.content.Intent; import android.content.Context; +import android.content.Intent; +import android.os.RemoteException; +import android.support.test.jank.GfxMonitor; import android.support.test.jank.JankTest; import android.support.test.jank.JankTestBase; -import android.support.test.uiautomator.UiDevice; -import android.support.test.jank.GfxMonitor; -import android.support.test.uiautomator.UiScrollable; -import android.util.Log; +import androidx.test.filters.LargeTest; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiScrollable; + +import com.android.documentsui.bots.DirectoryListBot; import com.android.documentsui.bots.SidebarBot; import com.android.documentsui.files.FilesActivity; -import com.android.documentsui.bots.DirectoryListBot; @LargeTest public class FilesJankPerfTest extends JankTestBase { diff --git a/perfetto_config.pbtx b/perfetto_config.pbtx new file mode 100644 index 000000000..7c5bfa128 --- /dev/null +++ b/perfetto_config.pbtx @@ -0,0 +1,222 @@ +buffers: { + size_kb: 63488 + fill_policy: DISCARD +} +buffers: { + size_kb: 2048 + fill_policy: DISCARD +} +# Max duration: 1 min +duration_ms: 60000 + +data_sources: { + config { + name: "linux.ftrace" + + # See: https://perfetto.dev/docs/data-sources/atrace#traceconfig + ftrace_config { + ftrace_events: "ftrace/print" + + # Trace all ContentProvider commands and SQLite queries. + # See: https://source.corp.google.com/android-internal/frameworks/base/core/java/android/os/Trace.java?q=TRACE_TAG_DATABASE + # See: https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/database/sqlite/SQLiteConnection.java + # Uncomment to enable. + # Note: on a userdebug build it will add a trace for every SQLite command for every + # application, which makes traces very-very "noisy". + # atrace_categories: "database" + + # Trace Binder IPC transactions. + # Uncomment to enable. + # Note: on a userdebug build it will add a trace for every Binder transaction for every + # application, which makes traces very-very "noisy". + # atrace_categories: "binder_driver" + + # ActivityManager, WindowManager, Graphics, View System. + # Uncomment to enable. + # Note: on a userdebug build it will traces from corresponding category for every + # application, which makes traces very-very "noisy". + # atrace_categories: "wm" + # atrace_categories: "am" + atrace_categories: "gfx" + atrace_categories: "view" + + # Trace DocumentUI "custom" events. + atrace_apps: "com.android.documentsui" + atrace_apps: "com.google.android.documentsui" + + # Trace other Providers. + + # authorities="com.android.documentsui.archives" - DocsUI + atrace_apps: "com.android.documentsui" + atrace_apps: "com.google.android.documentsui" + + # authorities="com.android.externalstorage.documents" - ExternalStorageProvider + atrace_apps: "com.android.externalstorage" + + # authorities="com.android.mtp.documents" - Mtp + atrace_apps: "com.android.mtp" + + # authorities="com.android.pixellogger.documents" - PixelLogger + atrace_apps: "com.android.pixellogger" + + # authorities="com.android.providers.downloads" - DownloadSProvider + atrace_apps: "com.android.providers.downloads.documents" + + # authorities="com.android.providers.media.documents" - MediaProvider + atrace_apps: "com.android.providers.media.module" + atrace_apps: "com.google.android.providers.media.module" + + # authorities="com.android.shell.documents" - Shell (BugreportStorageProvider) + # atrace_apps: "android.uid.shell" + + # authorities="com.google.android.apps.docs.storage" - Google Docs + atrace_apps: "com.google.android.apps.docs" + + # Google Photos. + # atrace_apps: "com.google.android.apps.photos" + + # Trace all apps' events. + # Uncomment to enable. + # atrace_apps: "*" + } + } +} + +# This is for getting Thread-to-Process associations and full process names. +data_sources: { + config { + name: "linux.process_stats" + } +} + +# "Expected Timeline" and "Actual Timeline" jor each process +# See https://perfetto.dev/docs/data-sources/frametimeline#traceconfig +data_sources { + config { + name: "android.surfaceflinger.frametimeline" + } +} + +# Memory Profiling +# See https://perfetto.dev/docs/data-sources/memory-counters + +# Android Logcat +data_sources: { + config { + name: "android.log" + android_log_config { + min_prio: PRIO_VERBOSE # Default: PRIO_DEBUG + + log_ids: LID_EVENTS + log_ids: LID_CRASH + log_ids: LID_KERNEL + log_ids: LID_DEFAULT + log_ids: LID_RADIO + log_ids: LID_SECURITY + log_ids: LID_STATS + log_ids: LID_SYSTEM + + # If filter_tags non-empty ignores all log messages whose tag doesn't match one of the + # specified values. + # filter_tags: "AbstractActionHandler" + # filter_tags: "ActionModeController" + # filter_tags: "Archive" + # filter_tags: "ArchiveFileTestRule" + # filter_tags: "ArchiveHandle" + # filter_tags: "ArchivesProvider" + # filter_tags: "CancelFromNotificationUiTest" + # filter_tags: "ClipStorage" + # filter_tags: "CommandInterceptor" + # filter_tags: "CompressJob" + # filter_tags: "ConfirmFragment" + # filter_tags: "ContentLock" + # filter_tags: "CopyJob" + # filter_tags: "DebugHelper" + # filter_tags: "DeleteJob" + # filter_tags: "DirectoryFragment" + # filter_tags: "DirectoryLoader" + # filter_tags: "DirectoryResult" + # filter_tags: "DocumentAccess" + # filter_tags: "DocumentClipper" + # filter_tags: "DocumentInfo" + # filter_tags: "DocumentStack" + # filter_tags: "Documents" + # filter_tags: "DocumentsApplication" + # filter_tags: "DocumentsSwipeRefreshLayout" + # filter_tags: "DragStartListener" + # filter_tags: "DrawerController" + # filter_tags: "EjectRootTask" + # filter_tags: "FileCopyUiTest" + # filter_tags: "FileDeleteUiTest" + # filter_tags: "FileOperationService" + # filter_tags: "FileOperations" + # filter_tags: "FilesActivity" + # filter_tags: "FilesAppPerfTest" + # filter_tags: "FocusManager" + # filter_tags: "GetRootDocumentTask" + # filter_tags: "HeaderItem" + # filter_tags: "HeaderMessage" + # filter_tags: "IconHelper" + # filter_tags: "ItemDragListener" + # filter_tags: "Job" + # filter_tags: "JumboUrisSupplier" + # filter_tags: "LastAccessedProvider" + # filter_tags: "LastAccessedStorage" + # filter_tags: "LauncherActivity" + # filter_tags: "ListDocumentHolder" + # filter_tags: "LoadDocStackTask" + # filter_tags: "LoadRootTask" + # filter_tags: "Loader" + # filter_tags: "ManagerActionHandler" + # filter_tags: "MenuManager" + # filter_tags: "MetadataLoader" + # filter_tags: "Metrics" + # filter_tags: "Model" + # filter_tags: "ModelBackedDocuments" + # filter_tags: "MoveJob" + # filter_tags: "MultiRootDocsLoader" + # filter_tags: "NavigationViewManager" + # filter_tags: "OperationDialogFragment" + # filter_tags: "PermissionsTest" + # filter_tags: "PickActivity" + # filter_tags: "PickCountRecordProvider" + # filter_tags: "PickCountRecordStorage" + # filter_tags: "PickFragment" + # filter_tags: "PickerActionHandler" + # filter_tags: "PreBootReceiver" + # filter_tags: "ProfileTabsController" + # filter_tags: "ProvidersCache" + # filter_tags: "QuickViewIntentBuilder" + # filter_tags: "ReadableArchive" + # filter_tags: "RefreshTask" + # filter_tags: "ResolvedResourcesJob" + # filter_tags: "RootCursorWrapper" + # filter_tags: "RootInfo" + # filter_tags: "RootItem" + # filter_tags: "RootUiTest" + # filter_tags: "RootsDragHost" + # filter_tags: "RootsFragment" + # filter_tags: "RootsListBot" + # filter_tags: "SaveFragment" + # filter_tags: "ScaleHelper" + # filter_tags: "ScopedAccessMetrics" + # filter_tags: "SearchFragment" + # filter_tags: "SearchHistoryManager" + # filter_tags: "SearchManager" + # filter_tags: "SectioningDocumentsAdapterWrapper" + # filter_tags: "SelectionMetadata" + # filter_tags: "SharedInputHandler" + # filter_tags: "SortModel" + # filter_tags: "SpacerItem" + # filter_tags: "State" + # filter_tags: "StubProvider" + # filter_tags: "TestContextResolver" + # filter_tags: "TestNotificationService" + # filter_tags: "ThemeOverlayManager" + # filter_tags: "ThumbnailLoader" + # filter_tags: "UserIdManager" + # filter_tags: "WriteableArchive" + # filter_tags: "dirlist.DragHost" + } + } +} diff --git a/proguard.flags b/proguard.flags index a9483308c..e71b073c8 100644 --- a/proguard.flags +++ b/proguard.flags @@ -23,5 +23,184 @@ } # To prevent class not found exception in org.brotli.dec.Dictionary --keep final class org.brotli.dec.DictionaryData +# TODO(b/373579455): Evaluate if <init> needs to be kept. +-keep final class org.brotli.dec.DictionaryData { + void <init>(); +} + +# keep rule generated after running trace references on the test app against DocumentsUIGoogle.jar +# TODO(b/339312616): Remove after a more permanent fix is available +# On modifying or adding new test run the following command to generate new keep rules and replace +# the once listed below with the newly generated keep rules: +# java -cp prebuilts/r8/r8.jar com.android.tools.r8.tracereferences.TraceReferences \ +# --lib out/soong/.intermediates/frameworks/base/framework/android_common/<some_hash>/combined/framework.jar \ +# --source out/target/product/panther/testcases/DocumentsUIGoogleTests/arm64/DocumentsUIGoogleTests.apk \ +# --target out/soong/.intermediates/vendor/unbundled_google/packages/DocumentsUIGoogle/DocumentsUIGoogle/android_common/<some_hash>/javac/DocumentsUIGoogle.jar \ +# --keep-rules \ +# --output /tmp/keep.txt + +-keep class androidx.appcompat.R$id { + int search_src_text; +} +-keep class com.android.documentsui.R$bool { + int feature_notification_channel; + int full_bar_search_view; + int is_launcher_enabled; + int show_search_bar; +} +-keep class com.android.documentsui.R$color { + int app_background_color; + int primary; +} +-keep class com.android.documentsui.R$dimen { + int grid_item_radius; +} +-keep class com.android.documentsui.R$drawable { + int ic_briefcase; + int ic_cab_cancel; + int ic_eject; + int ic_menu_copy; + int ic_root_download; + int ic_sd_storage; + int root_list_selector; + int work_off; +} +-keep class com.android.documentsui.R$id { + int action_menu_compress; + int action_menu_copy_to; + int action_menu_delete; + int action_menu_deselect_all; + int action_menu_extract_to; + int action_menu_inspect; + int action_menu_move_to; + int action_menu_open_with; + int action_menu_rename; + int action_menu_select; + int action_menu_select_all; + int action_menu_share; + int action_menu_sort; + int action_menu_view_in_owner; + int apps_group; + int apps_row; + int button; + int content; + int cross_profile; + int cross_profile_content; + int cross_profile_progress; + int dir_menu_copy_to_clipboard; + int dir_menu_create_dir; + int dir_menu_cut_to_clipboard; + int dir_menu_delete; + int dir_menu_deselect_all; + int dir_menu_inspect; + int dir_menu_open; + int dir_menu_open_in_new_window; + int dir_menu_open_with; + int dir_menu_paste_from_clipboard; + int dir_menu_paste_into_folder; + int dir_menu_rename; + int dir_menu_select_all; + int dir_menu_share; + int dir_menu_view_in_owner; + int drawer_layout; + int inspector_details_view; + int option_menu_create_dir; + int option_menu_debug; + int option_menu_extract_all; + int option_menu_inspect; + int option_menu_launcher; + int option_menu_new_window; + int option_menu_search; + int option_menu_select_all; + int option_menu_settings; + int option_menu_show_hidden_files; + int option_menu_sort; + int root_menu_eject_root; + int root_menu_open_in_new_window; + int root_menu_paste_into_folder; + int root_menu_settings; + int sub_menu_grid; + int sub_menu_list; + int table_header; + int tabs; + int tabs_container; + int toolbar; +} +-keep class com.android.documentsui.R$layout { + int apps_row; + int directory_header; + int files_activity; + int fixed_layout; + int item_doc_list; +} +-keep class com.android.documentsui.R$menu { + int dir_context_menu; + int file_context_menu; + int mixed_context_menu; +} +-keep class com.android.documentsui.R$plurals { + int copy_error_notification_title; + int elements_dragged; +} +-keep class com.android.documentsui.R$string { + int cant_select_work_files_error_message; + int cant_select_work_files_error_title; + int copy_notification_title; + int copy_preparing; + int copy_remaining; + int debug_content_uri; + int default_root_uri; + int directory_items; + int empty; + int menu_copy; + int menu_move; + int menu_rename; + int menu_select; + int menu_select_all; + int menu_sort; + int menu_view_in_owner; + int metadata_address; + int metadata_album; + int metadata_altitude; + int metadata_aperture; + int metadata_aperture_format; + int metadata_artist; + int metadata_camera; + int metadata_camera_format; + int metadata_composer; + int metadata_coordinates; + int metadata_coordinates_format; + int metadata_date_time; + int metadata_dimensions; + int metadata_dimensions_format; + int metadata_duration; + int metadata_focal_format; + int metadata_focal_length; + int metadata_iso_format; + int metadata_iso_speed_ratings; + int metadata_shutter_speed; + int name_conflict; + int no_results; + int personal_tab; + int preferred_root_package; + int quiet_mode_button; + int quiet_mode_error_title; + int rename_error; + int search_bar_hint; + int share_via; + int sort_dimension_date; + int sort_dimension_file_type; + int sort_dimension_name; + int sort_dimension_size; + int sort_direction_ascending; + int sort_direction_descending; + int trusted_quick_viewer_package; + int work_tab; +} +-keep class com.android.documentsui.R$style { + int DocumentsDefaultTheme; + int DocumentsTheme; +} +# Keep Apache Commons Compress classes +-keep class org.apache.commons.compress.** { *; } diff --git a/res/color/doc_list_item_subtitle_color.xml b/res/flag(!com.android.documentsui.flags.use_material3)/color/doc_list_item_subtitle_color.xml index 5f5896e7a..5f5896e7a 100644 --- a/res/color/doc_list_item_subtitle_color.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/color/doc_list_item_subtitle_color.xml diff --git a/res/color/fragment_pick_button_background_color.xml b/res/flag(!com.android.documentsui.flags.use_material3)/color/fragment_pick_button_background_color.xml index cf6d480ea..cf6d480ea 100644 --- a/res/color/fragment_pick_button_background_color.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/color/fragment_pick_button_background_color.xml diff --git a/res/color/fragment_pick_button_text_color.xml b/res/flag(!com.android.documentsui.flags.use_material3)/color/fragment_pick_button_text_color.xml index e4e1edc48..e4e1edc48 100644 --- a/res/color/fragment_pick_button_text_color.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/color/fragment_pick_button_text_color.xml diff --git a/res/color/horizontal_breadcrumb_color.xml b/res/flag(!com.android.documentsui.flags.use_material3)/color/horizontal_breadcrumb_color.xml index d5a852c0a..d5a852c0a 100644 --- a/res/color/horizontal_breadcrumb_color.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/color/horizontal_breadcrumb_color.xml diff --git a/res/color/item_action_icon.xml b/res/flag(!com.android.documentsui.flags.use_material3)/color/item_action_icon.xml index 5de0cb678..5de0cb678 100644 --- a/res/color/item_action_icon.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/color/item_action_icon.xml diff --git a/res/color/item_details.xml b/res/flag(!com.android.documentsui.flags.use_material3)/color/item_details.xml index 970e55d76..970e55d76 100644 --- a/res/color/item_details.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/color/item_details.xml diff --git a/res/color/item_doc_grid_border.xml b/res/flag(!com.android.documentsui.flags.use_material3)/color/item_doc_grid_border.xml index 592d07634..592d07634 100644 --- a/res/color/item_doc_grid_border.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/color/item_doc_grid_border.xml diff --git a/res/color/item_doc_grid_tint.xml b/res/flag(!com.android.documentsui.flags.use_material3)/color/item_doc_grid_tint.xml index 878afb175..878afb175 100644 --- a/res/color/item_doc_grid_tint.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/color/item_doc_grid_tint.xml diff --git a/res/color/item_root_icon.xml b/res/flag(!com.android.documentsui.flags.use_material3)/color/item_root_icon.xml index 456d1b4a2..456d1b4a2 100644 --- a/res/color/item_root_icon.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/color/item_root_icon.xml diff --git a/res/color/item_root_primary_text.xml b/res/flag(!com.android.documentsui.flags.use_material3)/color/item_root_primary_text.xml index 62a620c85..62a620c85 100644 --- a/res/color/item_root_primary_text.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/color/item_root_primary_text.xml diff --git a/res/color/item_root_secondary_text.xml b/res/flag(!com.android.documentsui.flags.use_material3)/color/item_root_secondary_text.xml index 632135ce8..632135ce8 100644 --- a/res/color/item_root_secondary_text.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/color/item_root_secondary_text.xml diff --git a/res/color/profile_tab_selector.xml b/res/flag(!com.android.documentsui.flags.use_material3)/color/profile_tab_selector.xml index 53aef1f6a..53aef1f6a 100644 --- a/res/color/profile_tab_selector.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/color/profile_tab_selector.xml diff --git a/res/color/search_chip_background_color.xml b/res/flag(!com.android.documentsui.flags.use_material3)/color/search_chip_background_color.xml index c94d155a5..c94d155a5 100644 --- a/res/color/search_chip_background_color.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/color/search_chip_background_color.xml diff --git a/res/color/search_chip_ripple_color.xml b/res/flag(!com.android.documentsui.flags.use_material3)/color/search_chip_ripple_color.xml index 0f78a0722..0f78a0722 100644 --- a/res/color/search_chip_ripple_color.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/color/search_chip_ripple_color.xml diff --git a/res/color/search_chip_stroke_color.xml b/res/flag(!com.android.documentsui.flags.use_material3)/color/search_chip_stroke_color.xml index be169354e..be169354e 100644 --- a/res/color/search_chip_stroke_color.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/color/search_chip_stroke_color.xml diff --git a/res/color/search_chip_text_color.xml b/res/flag(!com.android.documentsui.flags.use_material3)/color/search_chip_text_color.xml index 262bede41..4e6e3a9d7 100644 --- a/res/color/search_chip_text_color.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/color/search_chip_text_color.xml @@ -16,7 +16,7 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_selected="true" android:color="?android:colorControlActivated"/> + <item android:state_selected="true" android:color="@color/search_chip_text_selected_color"/> <item android:state_enabled="true" android:color="?android:textColorSecondary"/> <item android:state_enabled="false" android:color="?android:textColorSecondary" android:alpha="0.3"/> </selector>
\ No newline at end of file diff --git a/res/color/sort_list_text.xml b/res/flag(!com.android.documentsui.flags.use_material3)/color/sort_list_text.xml index cbe8da6fe..cbe8da6fe 100644 --- a/res/color/sort_list_text.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/color/sort_list_text.xml diff --git a/res/drawable-ldrtl/roots_list_border.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable-ldrtl/roots_list_border.xml index 7f3387a9d..7f3387a9d 100644 --- a/res/drawable-ldrtl/roots_list_border.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable-ldrtl/roots_list_border.xml diff --git a/res/drawable/band_select_overlay.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/band_select_overlay.xml index ba4d5261e..ba4d5261e 100644 --- a/res/drawable/band_select_overlay.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/band_select_overlay.xml diff --git a/res/drawable/bottom_sheet_dialog_background.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/bottom_sheet_dialog_background.xml index 703667a52..703667a52 100644 --- a/res/drawable/bottom_sheet_dialog_background.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/bottom_sheet_dialog_background.xml diff --git a/res/drawable/breadcrumb_item_background.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/breadcrumb_item_background.xml index 410e8edb9..410e8edb9 100644 --- a/res/drawable/breadcrumb_item_background.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/breadcrumb_item_background.xml diff --git a/res/drawable/circle_button_background.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/circle_button_background.xml index d5b3c50d1..d5b3c50d1 100644 --- a/res/drawable/circle_button_background.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/circle_button_background.xml diff --git a/res/drawable/debug_msg_1.png b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/debug_msg_1.png Binary files differindex 862769a39..862769a39 100644 --- a/res/drawable/debug_msg_1.png +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/debug_msg_1.png diff --git a/res/drawable/debug_msg_2.png b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/debug_msg_2.png Binary files differindex e4c62591c..e4c62591c 100644 --- a/res/drawable/debug_msg_2.png +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/debug_msg_2.png diff --git a/res/drawable/drag_shadow_background.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/drag_shadow_background.xml index 58c0e1afd..58c0e1afd 100644 --- a/res/drawable/drag_shadow_background.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/drag_shadow_background.xml diff --git a/res/drawable/drop_badge_states.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/drop_badge_states.xml index 57d43d3fc..57d43d3fc 100644 --- a/res/drawable/drop_badge_states.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/drop_badge_states.xml diff --git a/res/drawable/dropdown_sort_widget_background.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/dropdown_sort_widget_background.xml index a1a74e787..a1a74e787 100644 --- a/res/drawable/dropdown_sort_widget_background.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/dropdown_sort_widget_background.xml diff --git a/res/drawable/empty.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/empty.xml index 73d4ffd2a..73d4ffd2a 100644 --- a/res/drawable/empty.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/empty.xml diff --git a/res/drawable/fast_scroll_thumb_drawable.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/fast_scroll_thumb_drawable.xml index e2beaec36..e2beaec36 100644 --- a/res/drawable/fast_scroll_thumb_drawable.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/fast_scroll_thumb_drawable.xml diff --git a/res/drawable/fast_scroll_track_drawable.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/fast_scroll_track_drawable.xml index d363f1a65..d363f1a65 100644 --- a/res/drawable/fast_scroll_track_drawable.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/fast_scroll_track_drawable.xml diff --git a/res/drawable/generic_ripple_background.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/generic_ripple_background.xml index edf52c404..edf52c404 100644 --- a/res/drawable/generic_ripple_background.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/generic_ripple_background.xml diff --git a/res/drawable/gradient_actionbar_background.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/gradient_actionbar_background.xml index da29c4588..da29c4588 100644 --- a/res/drawable/gradient_actionbar_background.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/gradient_actionbar_background.xml diff --git a/res/drawable/grid_item_background.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/grid_item_background.xml index 9c4e644a8..9c4e644a8 100644 --- a/res/drawable/grid_item_background.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/grid_item_background.xml diff --git a/res/drawable/hourglass.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/hourglass.xml index 9b8d0e294..9b8d0e294 100644 --- a/res/drawable/hourglass.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/hourglass.xml diff --git a/res/drawable/ic_action_clear.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_action_clear.xml index 38588b9bc..38588b9bc 100644 --- a/res/drawable/ic_action_clear.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_action_clear.xml diff --git a/res/drawable/ic_action_open.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_action_open.xml index 15890c948..15890c948 100644 --- a/res/drawable/ic_action_open.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_action_open.xml diff --git a/res/drawable/ic_advanced_shortcut.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_advanced_shortcut.xml index 677e5f962..677e5f962 100644 --- a/res/drawable/ic_advanced_shortcut.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_advanced_shortcut.xml diff --git a/res/drawable/ic_arrow_back.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_arrow_back.xml index 1a9993033..1a9993033 100644 --- a/res/drawable/ic_arrow_back.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_arrow_back.xml diff --git a/res/drawable/ic_arrow_upward.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_arrow_upward.xml index dab39f9a3..dab39f9a3 100644 --- a/res/drawable/ic_arrow_upward.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_arrow_upward.xml diff --git a/res/drawable/ic_breadcrumb_arrow.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_breadcrumb_arrow.xml index e08d0d781..e08d0d781 100644 --- a/res/drawable/ic_breadcrumb_arrow.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_breadcrumb_arrow.xml diff --git a/res/drawable/ic_briefcase.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_briefcase.xml index 64efd18d9..64efd18d9 100644 --- a/res/drawable/ic_briefcase.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_briefcase.xml diff --git a/res/drawable/ic_briefcase_white.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_briefcase_white.xml index da3b6befa..da3b6befa 100644 --- a/res/drawable/ic_briefcase_white.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_briefcase_white.xml diff --git a/res/drawable/ic_cab_cancel.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_cab_cancel.xml index 1eae40e5f..1eae40e5f 100644 --- a/res/drawable/ic_cab_cancel.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_cab_cancel.xml diff --git a/res/drawable/ic_check.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_check.xml index 2f02c9a6c..1d7aed0cb 100644 --- a/res/drawable/ic_check.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_check.xml @@ -18,7 +18,7 @@ Copyright (C) 2018 The Android Open Source Project android:height="24dp" android:viewportWidth="24.0" android:viewportHeight="24.0" - android:tint="?android:colorControlActivated"> + android:tint="@color/search_chip_text_selected_color"> <path android:fillColor="@android:color/white" android:pathData="vM9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/> diff --git a/res/drawable/ic_check_circle.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_check_circle.xml index 62a4e34b4..62a4e34b4 100644 --- a/res/drawable/ic_check_circle.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_check_circle.xml diff --git a/res/drawable/ic_chip_from_this_week.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_chip_from_this_week.xml index 8d799df60..8d799df60 100644 --- a/res/drawable/ic_chip_from_this_week.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_chip_from_this_week.xml diff --git a/res/drawable/ic_chip_large_files.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_chip_large_files.xml index 1accc73ce..1accc73ce 100644 --- a/res/drawable/ic_chip_large_files.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_chip_large_files.xml diff --git a/res/drawable/ic_create_new_folder.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_create_new_folder.xml index 9bde40598..9bde40598 100644 --- a/res/drawable/ic_create_new_folder.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_create_new_folder.xml diff --git a/res/drawable/ic_debug_menu.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_debug_menu.xml index f0ada107b..f0ada107b 100644 --- a/res/drawable/ic_debug_menu.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_debug_menu.xml diff --git a/res/drawable/ic_dialog_alert.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_dialog_alert.xml index 8066483e5..8066483e5 100644 --- a/res/drawable/ic_dialog_alert.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_dialog_alert.xml diff --git a/res/drawable/ic_dialog_info.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_dialog_info.xml index 968bb67dd..968bb67dd 100644 --- a/res/drawable/ic_dialog_info.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_dialog_info.xml diff --git a/res/drawable/ic_done.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_done.xml index 299bd177f..299bd177f 100644 --- a/res/drawable/ic_done.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_done.xml diff --git a/res/drawable/ic_drop_copy_badge.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_drop_copy_badge.xml index 7f1be3151..7f1be3151 100644 --- a/res/drawable/ic_drop_copy_badge.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_drop_copy_badge.xml diff --git a/res/drawable/ic_eject.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_eject.xml index 0e1b36f33..0e1b36f33 100644 --- a/res/drawable/ic_eject.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_eject.xml diff --git a/res/drawable/ic_exit_to_app.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_exit_to_app.xml index b597def5b..b597def5b 100644 --- a/res/drawable/ic_exit_to_app.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_exit_to_app.xml diff --git a/res/drawable/ic_folder_shortcut.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_folder_shortcut.xml index 993a56ad3..993a56ad3 100644 --- a/res/drawable/ic_folder_shortcut.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_folder_shortcut.xml diff --git a/res/drawable/ic_hamburger.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_hamburger.xml index bc273524b..bc273524b 100644 --- a/res/drawable/ic_hamburger.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_hamburger.xml diff --git a/res/drawable/ic_history.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_history.xml index df0636dee..df0636dee 100644 --- a/res/drawable/ic_history.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_history.xml diff --git a/res/drawable/ic_images_shortcut.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_images_shortcut.xml index 5e84369ea..5e84369ea 100644 --- a/res/drawable/ic_images_shortcut.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_images_shortcut.xml diff --git a/res/drawable/ic_menu_compress.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_menu_compress.xml index cdb328e82..cdb328e82 100644 --- a/res/drawable/ic_menu_compress.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_menu_compress.xml diff --git a/res/drawable/ic_menu_copy.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_menu_copy.xml index 9c391dae2..9c391dae2 100644 --- a/res/drawable/ic_menu_copy.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_menu_copy.xml diff --git a/res/drawable/ic_menu_delete.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_menu_delete.xml index bfe3ed64f..bfe3ed64f 100644 --- a/res/drawable/ic_menu_delete.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_menu_delete.xml diff --git a/res/drawable/ic_menu_extract.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_menu_extract.xml index 7770148c5..7770148c5 100644 --- a/res/drawable/ic_menu_extract.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_menu_extract.xml diff --git a/res/drawable/ic_menu_search.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_menu_search.xml index 4d92eeea4..4d92eeea4 100644 --- a/res/drawable/ic_menu_search.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_menu_search.xml diff --git a/res/drawable/ic_menu_share.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_menu_share.xml index 5ff5c8635..5ff5c8635 100644 --- a/res/drawable/ic_menu_share.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_menu_share.xml diff --git a/res/drawable/ic_menu_view_grid.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_menu_view_grid.xml index 82af2c351..82af2c351 100644 --- a/res/drawable/ic_menu_view_grid.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_menu_view_grid.xml diff --git a/res/drawable/ic_menu_view_list.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_menu_view_list.xml index 3b0c4fc8d..3b0c4fc8d 100644 --- a/res/drawable/ic_menu_view_list.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_menu_view_list.xml diff --git a/res/drawable/ic_reject_drop_badge.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_reject_drop_badge.xml index 402aff8f8..402aff8f8 100644 --- a/res/drawable/ic_reject_drop_badge.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_reject_drop_badge.xml diff --git a/res/drawable/ic_root_bugreport.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_root_bugreport.xml index bc6fc3a18..bc6fc3a18 100644 --- a/res/drawable/ic_root_bugreport.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_root_bugreport.xml diff --git a/res/drawable/ic_root_download.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_root_download.xml index 56c7ea7f0..56c7ea7f0 100644 --- a/res/drawable/ic_root_download.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_root_download.xml diff --git a/res/drawable/ic_root_recent.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_root_recent.xml index cbc33407e..cbc33407e 100644 --- a/res/drawable/ic_root_recent.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_root_recent.xml diff --git a/res/drawable/ic_root_smartphone.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_root_smartphone.xml index ad647ffd1..ad647ffd1 100644 --- a/res/drawable/ic_root_smartphone.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_root_smartphone.xml diff --git a/res/drawable/ic_sd_storage.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_sd_storage.xml index 8d9e4a671..8d9e4a671 100644 --- a/res/drawable/ic_sd_storage.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_sd_storage.xml diff --git a/res/drawable/ic_sort.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_sort.xml index 12ad81742..12ad81742 100644 --- a/res/drawable/ic_sort.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_sort.xml diff --git a/res/drawable/ic_sort_arrow.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_sort_arrow.xml index b4b92a50f..b4b92a50f 100644 --- a/res/drawable/ic_sort_arrow.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_sort_arrow.xml diff --git a/res/drawable/ic_subdirectory_arrow.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_subdirectory_arrow.xml index 35f5ca59e..35f5ca59e 100644 --- a/res/drawable/ic_subdirectory_arrow.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_subdirectory_arrow.xml diff --git a/res/drawable/ic_usb_shortcut.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_usb_shortcut.xml index cf954454c..cf954454c 100644 --- a/res/drawable/ic_usb_shortcut.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_usb_shortcut.xml diff --git a/res/drawable/ic_usb_storage.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_usb_storage.xml index 60cb6c27f..60cb6c27f 100644 --- a/res/drawable/ic_usb_storage.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_usb_storage.xml diff --git a/res/drawable/ic_user_profile.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_user_profile.xml index 42e06a59e..42e06a59e 100644 --- a/res/drawable/ic_user_profile.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_user_profile.xml diff --git a/res/drawable/ic_zoom_out.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_zoom_out.xml index 295054a35..295054a35 100644 --- a/res/drawable/ic_zoom_out.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/ic_zoom_out.xml diff --git a/res/drawable/inspector_separator.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/inspector_separator.xml index cbb494a1d..cbb494a1d 100644 --- a/res/drawable/inspector_separator.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/inspector_separator.xml diff --git a/res/drawable/item_doc_grid_border.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/item_doc_grid_border.xml index db66094fc..db66094fc 100644 --- a/res/drawable/item_doc_grid_border.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/item_doc_grid_border.xml diff --git a/res/drawable/item_doc_grid_border_rounded.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/item_doc_grid_border_rounded.xml index e6ffbcad6..e6ffbcad6 100644 --- a/res/drawable/item_doc_grid_border_rounded.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/item_doc_grid_border_rounded.xml diff --git a/res/drawable/launcher_screen.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/launcher_screen.xml index c0d814632..c0d814632 100644 --- a/res/drawable/launcher_screen.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/launcher_screen.xml diff --git a/res/drawable/launcher_screen_night.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/launcher_screen_night.xml index 983c4977d..983c4977d 100644 --- a/res/drawable/launcher_screen_night.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/launcher_screen_night.xml diff --git a/res/drawable/list_checker.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/list_checker.xml index d0d3a1d9b..d0d3a1d9b 100644 --- a/res/drawable/list_checker.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/list_checker.xml diff --git a/res/drawable/list_divider.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/list_divider.xml index 5067af08e..5067af08e 100644 --- a/res/drawable/list_divider.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/list_divider.xml diff --git a/res/drawable/list_item_background.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/list_item_background.xml index a73ae2e2a..a73ae2e2a 100644 --- a/res/drawable/list_item_background.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/list_item_background.xml diff --git a/res/drawable/menu_dropdown_panel.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/menu_dropdown_panel.xml index f750f0d5a..f750f0d5a 100644 --- a/res/drawable/menu_dropdown_panel.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/menu_dropdown_panel.xml diff --git a/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/progress_indeterminate_horizontal_material_trimmed.xml index a6668bcdf..a6668bcdf 100644 --- a/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/progress_indeterminate_horizontal_material_trimmed.xml diff --git a/res/drawable/root_item_background.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/root_item_background.xml index 6eca486eb..6eca486eb 100644 --- a/res/drawable/root_item_background.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/root_item_background.xml diff --git a/res/drawable/root_list_selector.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/root_list_selector.xml index 911c2edc5..911c2edc5 100644 --- a/res/drawable/root_list_selector.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/root_list_selector.xml diff --git a/res/drawable/search_bar_background.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/search_bar_background.xml index ab657c385..ab657c385 100644 --- a/res/drawable/search_bar_background.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/search_bar_background.xml diff --git a/res/drawable/share_off.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/share_off.xml index 23e5c564f..23e5c564f 100644 --- a/res/drawable/share_off.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/share_off.xml diff --git a/res/drawable/sort_widget_background.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/sort_widget_background.xml index b7f6ae523..b7f6ae523 100644 --- a/res/drawable/sort_widget_background.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/sort_widget_background.xml diff --git a/res/drawable/splash_screen.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/splash_screen.xml index 3f0c48b6b..3f0c48b6b 100644 --- a/res/drawable/splash_screen.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/splash_screen.xml diff --git a/res/drawable/tab_border_rounded.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/tab_border_rounded.xml index dfff1d49c..dfff1d49c 100644 --- a/res/drawable/tab_border_rounded.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/tab_border_rounded.xml diff --git a/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml index 39e3a3738..39e3a3738 100644 --- a/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml diff --git a/res/drawable/work_off.xml b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/work_off.xml index 323f5e884..323f5e884 100644 --- a/res/drawable/work_off.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/drawable/work_off.xml diff --git a/res/layout-sw720dp/column_headers.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout-sw720dp/column_headers.xml index 60be5dc10..60be5dc10 100644 --- a/res/layout-sw720dp/column_headers.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout-sw720dp/column_headers.xml diff --git a/res/layout-sw720dp/directory_app_bar.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout-sw720dp/directory_app_bar.xml index 928659793..928659793 100644 --- a/res/layout-sw720dp/directory_app_bar.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout-sw720dp/directory_app_bar.xml diff --git a/res/layout-sw720dp/item_doc_list.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout-sw720dp/item_doc_list.xml index da9179606..01cdd8c66 100644 --- a/res/layout-sw720dp/item_doc_list.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout-sw720dp/item_doc_list.xml @@ -34,7 +34,7 @@ android:orientation="horizontal" > <FrameLayout - android:id="@android:id/icon" + android:id="@+id/icon" android:pointerIcon="hand" android:layout_width="@dimen/list_item_width" android:layout_height="@dimen/list_item_height" @@ -95,12 +95,13 @@ android:orientation="horizontal"> <ImageView - android:id="@+id/icon_briefcase" + android:id="@+id/icon_profile_badge" android:layout_height="@dimen/briefcase_icon_size" android:layout_width="@dimen/briefcase_icon_size" android:layout_marginEnd="@dimen/briefcase_icon_margin" android:layout_gravity="center_vertical" android:src="@drawable/ic_briefcase" + android:tint="?android:attr/colorAccent" android:contentDescription="@string/a11y_work"/> <TextView diff --git a/res/layout-sw720dp/shared_cell_content.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout-sw720dp/shared_cell_content.xml index 9346933fd..9346933fd 100644 --- a/res/layout-sw720dp/shared_cell_content.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout-sw720dp/shared_cell_content.xml diff --git a/res/layout/apps_item.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/apps_item.xml index 61241f761..61241f761 100644 --- a/res/layout/apps_item.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/apps_item.xml diff --git a/res/layout/apps_row.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/apps_row.xml index 0b8504a9a..0b8504a9a 100644 --- a/res/layout/apps_row.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/apps_row.xml diff --git a/res/layout/column_headers.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/column_headers.xml index bee221203..bee221203 100644 --- a/res/layout/column_headers.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/column_headers.xml diff --git a/res/layout/dialog_delete_confirmation.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/dialog_delete_confirmation.xml index 80879ad00..80879ad00 100644 --- a/res/layout/dialog_delete_confirmation.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/dialog_delete_confirmation.xml diff --git a/res/layout/dialog_file_name.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/dialog_file_name.xml index 7f2a9592b..7f2a9592b 100644 --- a/res/layout/dialog_file_name.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/dialog_file_name.xml diff --git a/res/layout/dialog_sorting.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/dialog_sorting.xml index d8cb7364c..d8cb7364c 100644 --- a/res/layout/dialog_sorting.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/dialog_sorting.xml diff --git a/res/layout/directory_app_bar.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/directory_app_bar.xml index ad80ec201..ad80ec201 100644 --- a/res/layout/directory_app_bar.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/directory_app_bar.xml diff --git a/res/layout/directory_header.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/directory_header.xml index 4d602ac33..af730829f 100644 --- a/res/layout/directory_header.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/directory_header.xml @@ -69,7 +69,8 @@ android:layout_height="wrap_content" android:layout_marginStart="@dimen/root_info_header_horizontal_padding" android:layout_marginEnd="@dimen/root_info_header_horizontal_padding" - android:minHeight="@dimen/root_info_header_height"> + android:minHeight="@dimen/root_info_header_height" + android:accessibilityHeading="true"> <TextView android:id="@+id/header_title" diff --git a/res/layout/drag_shadow_layout.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/drag_shadow_layout.xml index 591e81375..591e81375 100644 --- a/res/layout/drag_shadow_layout.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/drag_shadow_layout.xml diff --git a/res/layout/drawer_layout.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/drawer_layout.xml index d08c17d9f..d08c17d9f 100644 --- a/res/layout/drawer_layout.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/drawer_layout.xml diff --git a/res/layout/drop_badge.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/drop_badge.xml index e17fa1ce0..e17fa1ce0 100644 --- a/res/layout/drop_badge.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/drop_badge.xml diff --git a/res/layout/fixed_layout.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/fixed_layout.xml index fb2cb2452..fb2cb2452 100644 --- a/res/layout/fixed_layout.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/fixed_layout.xml diff --git a/res/layout/fragment_directory.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/fragment_directory.xml index 015039a6a..015039a6a 100644 --- a/res/layout/fragment_directory.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/fragment_directory.xml diff --git a/res/layout/fragment_pick.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/fragment_pick.xml index cba4ecb9a..cba4ecb9a 100644 --- a/res/layout/fragment_pick.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/fragment_pick.xml diff --git a/res/layout/fragment_roots.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/fragment_roots.xml index af7861992..af7861992 100644 --- a/res/layout/fragment_roots.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/fragment_roots.xml diff --git a/res/layout/fragment_save.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/fragment_save.xml index 0f46b2a9c..0f46b2a9c 100644 --- a/res/layout/fragment_save.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/fragment_save.xml diff --git a/res/layout/fragment_search.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/fragment_search.xml index 02baffdd3..02baffdd3 100644 --- a/res/layout/fragment_search.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/fragment_search.xml diff --git a/res/layout/inspector_action_view.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/inspector_action_view.xml index 422638348..422638348 100644 --- a/res/layout/inspector_action_view.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/inspector_action_view.xml diff --git a/res/layout/inspector_activity.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/inspector_activity.xml index 8763351c9..8763351c9 100644 --- a/res/layout/inspector_activity.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/inspector_activity.xml diff --git a/res/layout/inspector_header.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/inspector_header.xml index 94a092790..94a092790 100644 --- a/res/layout/inspector_header.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/inspector_header.xml diff --git a/res/layout/inspector_section_title.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/inspector_section_title.xml index 358b9613c..358b9613c 100644 --- a/res/layout/inspector_section_title.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/inspector_section_title.xml diff --git a/res/layout/item_dir_grid.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_dir_grid.xml index 8720c37cf..bd690d4d3 100644 --- a/res/layout/item_dir_grid.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_dir_grid.xml @@ -81,11 +81,12 @@ </FrameLayout> <ImageView - android:id="@+id/icon_briefcase" + android:id="@+id/icon_profile_badge" android:layout_height="@dimen/briefcase_icon_size" android:layout_width="@dimen/briefcase_icon_size" android:layout_marginEnd="@dimen/briefcase_icon_margin" android:src="@drawable/ic_briefcase" + android:tint="?android:attr/colorAccent" android:contentDescription="@string/a11y_work"/> <TextView diff --git a/res/layout/item_doc_grid.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_doc_grid.xml index 5e2e93842..d654571eb 100644 --- a/res/layout/item_doc_grid.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_doc_grid.xml @@ -146,7 +146,7 @@ android:paddingEnd="12dp"> <ImageView - android:id="@+id/icon_briefcase" + android:id="@+id/icon_profile_badge" android:layout_height="@dimen/briefcase_icon_size" android:layout_width="@dimen/briefcase_icon_size" android:layout_marginEnd="@dimen/briefcase_icon_margin" @@ -154,6 +154,7 @@ android:layout_alignBottom="@android:id/title" android:gravity="center_vertical" android:src="@drawable/ic_briefcase" + android:tint="?android:attr/colorAccent" android:contentDescription="@string/a11y_work"/> <TextView @@ -161,7 +162,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" - android:layout_toEndOf="@+id/icon_briefcase" + android:layout_toEndOf="@+id/icon_profile_badge" android:singleLine="true" android:ellipsize="end" android:textAlignment="viewStart" diff --git a/res/layout/item_doc_header_message.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_doc_header_message.xml index 4b2cf355f..4b2cf355f 100644 --- a/res/layout/item_doc_header_message.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_doc_header_message.xml diff --git a/res/layout/item_doc_inflated_message.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_doc_inflated_message.xml index abfdbfd10..abfdbfd10 100644 --- a/res/layout/item_doc_inflated_message.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_doc_inflated_message.xml diff --git a/res/layout/item_doc_inflated_message_content.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_doc_inflated_message_content.xml index 0635e1654..0635e1654 100644 --- a/res/layout/item_doc_inflated_message_content.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_doc_inflated_message_content.xml diff --git a/res/layout/item_doc_inflated_message_cross_profile.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_doc_inflated_message_cross_profile.xml index 3cc0d7ce2..3cc0d7ce2 100644 --- a/res/layout/item_doc_inflated_message_cross_profile.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_doc_inflated_message_cross_profile.xml diff --git a/res/layout/item_doc_list.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_doc_list.xml index 0942c4b5f..77494a29c 100644 --- a/res/layout/item_doc_list.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_doc_list.xml @@ -92,12 +92,13 @@ android:layout_weight="1"> <ImageView - android:id="@+id/icon_briefcase" + android:id="@+id/icon_profile_badge" android:layout_height="@dimen/briefcase_icon_size" android:layout_width="@dimen/briefcase_icon_size" android:layout_marginEnd="@dimen/briefcase_icon_margin" android:layout_gravity="center_vertical" android:src="@drawable/ic_briefcase" + android:tint="?android:attr/colorAccent" android:contentDescription="@string/a11y_work" /> <TextView diff --git a/res/layout/item_history.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_history.xml index 7bb76b35b..7bb76b35b 100644 --- a/res/layout/item_history.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_history.xml diff --git a/res/layout/item_photo_grid.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_photo_grid.xml index 5cf685004..4581d3d25 100644 --- a/res/layout/item_photo_grid.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_photo_grid.xml @@ -104,7 +104,7 @@ </FrameLayout> <FrameLayout - android:id="@+id/icon_briefcase" + android:id="@+id/icon_profile_badge" android:layout_width="@dimen/button_touch_size" android:layout_height="@dimen/button_touch_size" android:layout_alignParentBottom="true" @@ -116,6 +116,7 @@ android:layout_height="@dimen/briefcase_icon_size_photo" android:layout_width="@dimen/briefcase_icon_size_photo" android:src="@drawable/ic_briefcase_white" + android:tint="?android:attr/colorAccent" android:padding="5dp" android:background="@drawable/circle_button_background" android:layout_gravity="center" diff --git a/res/layout/item_root.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_root.xml index 8d0f86bad..8d0f86bad 100644 --- a/res/layout/item_root.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_root.xml diff --git a/res/layout/item_root_header.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_root_header.xml index f82b1577d..f82b1577d 100644 --- a/res/layout/item_root_header.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_root_header.xml diff --git a/res/layout/item_root_spacer.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_root_spacer.xml index 16ecee7fd..16ecee7fd 100644 --- a/res/layout/item_root_spacer.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/item_root_spacer.xml diff --git a/res/layout/navigation_breadcrumb_item.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/navigation_breadcrumb_item.xml index 93d3feb3f..93d3feb3f 100644 --- a/res/layout/navigation_breadcrumb_item.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/navigation_breadcrumb_item.xml diff --git a/res/layout/root_vertical_divider.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/root_vertical_divider.xml index 6b9c72341..6b9c72341 100644 --- a/res/layout/root_vertical_divider.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/root_vertical_divider.xml diff --git a/res/layout/search_chip_item.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/search_chip_item.xml index 3ee00c290..3ee00c290 100644 --- a/res/layout/search_chip_item.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/search_chip_item.xml diff --git a/res/layout/search_chip_row.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/search_chip_row.xml index ad0ac43c8..ad0ac43c8 100644 --- a/res/layout/search_chip_row.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/search_chip_row.xml diff --git a/res/layout/sort_list_item.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/sort_list_item.xml index c2f50c8b8..c2f50c8b8 100644 --- a/res/layout/sort_list_item.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/sort_list_item.xml diff --git a/res/layout/table_key_value_row.xml b/res/flag(!com.android.documentsui.flags.use_material3)/layout/table_key_value_row.xml index 6a0b4be13..6a0b4be13 100644 --- a/res/layout/table_key_value_row.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/layout/table_key_value_row.xml diff --git a/res/menu/action_mode_menu.xml b/res/flag(!com.android.documentsui.flags.use_material3)/menu/action_mode_menu.xml index 49a9ade70..49a9ade70 100644 --- a/res/menu/action_mode_menu.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/menu/action_mode_menu.xml diff --git a/res/menu/activity.xml b/res/flag(!com.android.documentsui.flags.use_material3)/menu/activity.xml index 39be106ca..9c3516aeb 100644 --- a/res/menu/activity.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/menu/activity.xml @@ -67,6 +67,13 @@ android:visible="false" app:showAsAction="never"/> <item + android:id="@+id/option_menu_extract_all" + android:title="@string/menu_extract_all" + android:icon="@drawable/ic_menu_extract" + android:enabled="false" + android:visible="false" + app:showAsAction="always"/> + <item android:id="@+id/option_menu_settings" android:title="@string/menu_settings" android:visible="false" diff --git a/res/menu/container_context_menu.xml b/res/flag(!com.android.documentsui.flags.use_material3)/menu/container_context_menu.xml index bd8b6c35e..bd8b6c35e 100644 --- a/res/menu/container_context_menu.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/menu/container_context_menu.xml diff --git a/res/menu/dir_context_menu.xml b/res/flag(!com.android.documentsui.flags.use_material3)/menu/dir_context_menu.xml index 383841ae3..232753b9d 100644 --- a/res/menu/dir_context_menu.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/menu/dir_context_menu.xml @@ -34,6 +34,9 @@ android:id="@+id/dir_menu_copy_to_clipboard" android:title="@string/menu_copy_to_clipboard" /> <item + android:id="@+id/dir_menu_compress" + android:title="@string/menu_compress" /> + <item android:id="@+id/dir_menu_paste_into_folder" android:title="@string/menu_paste_into_folder" /> </group> @@ -47,6 +50,7 @@ android:id="@+id/dir_menu_delete" android:title="@string/menu_delete" /> </group> + <group android:id="@+id/menu_extras_group"> <item diff --git a/res/menu/file_context_menu.xml b/res/flag(!com.android.documentsui.flags.use_material3)/menu/file_context_menu.xml index 9e786f173..02b0e87e1 100644 --- a/res/menu/file_context_menu.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/menu/file_context_menu.xml @@ -38,6 +38,9 @@ <item android:id="@+id/dir_menu_copy_to_clipboard" android:title="@string/menu_copy_to_clipboard" /> + <item + android:id="@+id/dir_menu_compress" + android:title="@string/menu_compress" /> </group> <group @@ -49,6 +52,7 @@ android:id="@+id/dir_menu_delete" android:title="@string/menu_delete" /> </group> + <group android:id="@+id/menu_extras_group"> <item diff --git a/res/menu/mixed_context_menu.xml b/res/flag(!com.android.documentsui.flags.use_material3)/menu/mixed_context_menu.xml index cb6b4fdaf..128b130d5 100644 --- a/res/menu/mixed_context_menu.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/menu/mixed_context_menu.xml @@ -26,6 +26,9 @@ <item android:id="@+id/dir_menu_copy_to_clipboard" android:title="@string/menu_copy_to_clipboard" /> + <item + android:id="@+id/dir_menu_compress" + android:title="@string/menu_compress" /> </group> <group @@ -34,6 +37,7 @@ android:id="@+id/dir_menu_delete" android:title="@string/menu_delete" /> </group> + <group android:id="@+id/menu_extras_group"> <item diff --git a/res/menu/root_context_menu.xml b/res/flag(!com.android.documentsui.flags.use_material3)/menu/root_context_menu.xml index 1ff818b3c..1ff818b3c 100644 --- a/res/menu/root_context_menu.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/menu/root_context_menu.xml diff --git a/res/menu/sub_menu.xml b/res/flag(!com.android.documentsui.flags.use_material3)/menu/sub_menu.xml index 73a97dc97..73a97dc97 100644 --- a/res/menu/sub_menu.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/menu/sub_menu.xml diff --git a/res/values-h600dp-v31/dimens.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values-h600dp-v31/dimens.xml index 6da529151..6da529151 100644 --- a/res/values-h600dp-v31/dimens.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values-h600dp-v31/dimens.xml diff --git a/res/values-h600dp/dimens.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values-h600dp/dimens.xml index d21465289..d21465289 100644 --- a/res/values-h600dp/dimens.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values-h600dp/dimens.xml diff --git a/res/values-night-v31/colors.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values-night-v31/colors.xml index c5e4f6d90..c5e4f6d90 100644 --- a/res/values-night-v31/colors.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values-night-v31/colors.xml diff --git a/res/values-night-v31/styles.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values-night-v31/styles.xml index 0bbda8997..0bbda8997 100644 --- a/res/values-night-v31/styles.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values-night-v31/styles.xml diff --git a/res/values-night/colors.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values-night/colors.xml index 143b3e693..9874d8a4c 100644 --- a/res/values-night/colors.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values-night/colors.xml @@ -35,4 +35,6 @@ <color name="list_item_selected_background_color">?android:colorSecondary</color> <color name="fragment_pick_active_text_color">#202124</color> <!-- Grey 900 --> + + <color name="search_chip_text_selected_color">@android:color/black</color> </resources> diff --git a/res/values-night/themes.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values-night/themes.xml index 8ade73172..8ade73172 100644 --- a/res/values-night/themes.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values-night/themes.xml diff --git a/res/values-sw600dp/dimens.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values-sw600dp/dimens.xml index 642ff7e9a..642ff7e9a 100644 --- a/res/values-sw600dp/dimens.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values-sw600dp/dimens.xml diff --git a/res/values-sw720dp-land/dimens.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values-sw720dp-land/dimens.xml index 07a188701..07a188701 100644 --- a/res/values-sw720dp-land/dimens.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values-sw720dp-land/dimens.xml diff --git a/res/values-sw720dp-land/layouts.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values-sw720dp-land/layouts.xml index 0e1807ce1..0e1807ce1 100644 --- a/res/values-sw720dp-land/layouts.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values-sw720dp-land/layouts.xml diff --git a/res/values-sw720dp/colors.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values-sw720dp/colors.xml index b39b89409..b39b89409 100644 --- a/res/values-sw720dp/colors.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values-sw720dp/colors.xml diff --git a/res/values-sw720dp/config.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values-sw720dp/config.xml index b6444d8b6..b6444d8b6 100644 --- a/res/values-sw720dp/config.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values-sw720dp/config.xml diff --git a/res/values-sw720dp/dimens.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values-sw720dp/dimens.xml index 85c370ab9..85c370ab9 100644 --- a/res/values-sw720dp/dimens.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values-sw720dp/dimens.xml diff --git a/res/values-v31/colors.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values-v31/colors.xml index 72de6e574..72de6e574 100644 --- a/res/values-v31/colors.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values-v31/colors.xml diff --git a/res/values-v31/dimens.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values-v31/dimens.xml index 79b300541..a4e39319a 100644 --- a/res/values-v31/dimens.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values-v31/dimens.xml @@ -18,7 +18,7 @@ <dimen name="action_bar_margin">0dp</dimen> <dimen name="button_corner_radius">20dp</dimen> <dimen name="tab_selector_indicator_height">0dp</dimen> - <dimen name="tab_height">36dp</dimen> + <dimen name="tab_height">48dp</dimen> <dimen name="tab_container_height">48dp</dimen> <dimen name="profile_tab_padding">20dp</dimen> <dimen name="profile_tab_margin_top">16dp</dimen> diff --git a/res/values-v31/styles.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values-v31/styles.xml index c82ff5814..c82ff5814 100644 --- a/res/values-v31/styles.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values-v31/styles.xml diff --git a/res/values-v31/styles_text.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values-v31/styles_text.xml index 02b91247b..02b91247b 100644 --- a/res/values-v31/styles_text.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values-v31/styles_text.xml diff --git a/res/values/colors.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values/colors.xml index 12b8762aa..6ccaa6faf 100644 --- a/res/values/colors.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values/colors.xml @@ -67,4 +67,6 @@ <color name="fragment_pick_inactive_text_color">#5F6368</color> <color name="fragment_pick_active_button_color">@color/primary</color> <color name="fragment_pick_active_text_color">@android:color/white</color> + + <color name="search_chip_text_selected_color">@android:color/white</color> </resources> diff --git a/res/values/dimens.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values/dimens.xml index 037375385..037375385 100644 --- a/res/values/dimens.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values/dimens.xml diff --git a/res/values/layouts.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values/layouts.xml index a60ce87ba..a60ce87ba 100644 --- a/res/values/layouts.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values/layouts.xml diff --git a/res/values/styles.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values/styles.xml index 1efd1d5d1..1efd1d5d1 100644 --- a/res/values/styles.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values/styles.xml diff --git a/res/values/styles_text.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values/styles_text.xml index 084480c2c..084480c2c 100644 --- a/res/values/styles_text.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values/styles_text.xml diff --git a/res/values/themes.xml b/res/flag(!com.android.documentsui.flags.use_material3)/values/themes.xml index 443374282..443374282 100644 --- a/res/values/themes.xml +++ b/res/flag(!com.android.documentsui.flags.use_material3)/values/themes.xml diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_badge_icon_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_badge_icon_color.xml new file mode 100644 index 000000000..de2849840 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_badge_icon_color.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_selected="true" android:color="?attr/colorOnPrimary" /> + <item android:color="?attr/colorSecondary" /> +</selector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_label_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_label_color.xml new file mode 100644 index 000000000..2b8f2726b --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_label_color.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_selected="true" android:color="?attr/colorOnPrimary" /> + <item android:color="?attr/colorOnSurface" /> +</selector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_subtitle_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_subtitle_color.xml new file mode 100644 index 000000000..d3d48f152 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_subtitle_color.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_selected="true" android:color="?attr/colorOnPrimary" /> + <item android:color="?attr/colorOnSurfaceVariant" /> +</selector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/fragment_pick_button_background_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/fragment_pick_button_background_color.xml new file mode 100644 index 000000000..cf6d480ea --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/fragment_pick_button_background_color.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + Copyright 2018 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 + + https://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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@color/fragment_pick_active_button_color" android:state_enabled="true" /> + <item android:color="@color/fragment_pick_inactive_button_color" android:state_enabled="false" /> +</selector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/fragment_pick_button_text_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/fragment_pick_button_text_color.xml new file mode 100644 index 000000000..e4e1edc48 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/fragment_pick_button_text_color.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + Copyright 2018 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 + + https://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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@color/fragment_pick_active_text_color" android:state_enabled="true" /> + <item android:color="@color/fragment_pick_inactive_text_color" android:state_enabled="false" /> +</selector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/horizontal_breadcrumb_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/horizontal_breadcrumb_color.xml new file mode 100644 index 000000000..ab511326d --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/horizontal_breadcrumb_color.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="true" + android:color="?android:colorAccent" /> + <item android:color="?android:attr/colorControlNormal" /> +</selector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/item_action_icon.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/item_action_icon.xml new file mode 100644 index 000000000..a65a72517 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/item_action_icon.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- TODO(b/379776735): remove this file after M3 uplift --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:alpha="@dimen/root_icon_disabled_alpha" + android:color="?android:colorControlNormal" /> + <item android:color="?android:colorControlNormal" /> +</selector> diff --git a/res/drawable/selection_demo_item_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/item_details.xml index de5c14236..321ec9cb1 100644 --- a/res/drawable/selection_demo_item_background.xml +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/item_details.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2017 The Android Open Source Project +<!-- 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. @@ -15,7 +15,7 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_activated="true"> - <color android:color="?android:attr/colorControlHighlight"></color> - </item> + <item + android:state_enabled="true" + android:color="?android:textColorSecondary" /> </selector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/item_doc_grid_border.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/item_doc_grid_border.xml new file mode 100644 index 000000000..36ea36f93 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/item_doc_grid_border.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:state_focused="true" + android:state_selected="false" + android:color="?android:attr/colorAccent"/> + <item + android:state_selected="true" + android:color="?android:attr/colorAccent"/> + <item + android:color="@android:color/transparent"/> +</selector> diff --git a/res/color/selection_demo_item_selector.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/item_doc_grid_tint.xml index bd87b4c6b..c20b7d032 100644 --- a/res/color/selection_demo_item_selector.xml +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/item_doc_grid_tint.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2017 The Android Open Source Project +<!-- 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. @@ -17,11 +17,8 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_activated="true" - android:color="?android:attr/colorForeground" - /> + android:color="?android:colorAccent" + android:alpha=".15" /> <item - android:state_activated="false" - android:color="?android:attr/colorForeground" - android:alpha=".3" - /> + android:color="@android:color/transparent" /> </selector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/item_root_icon.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/item_root_icon.xml new file mode 100644 index 000000000..e30080679 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/item_root_icon.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:state_activated="true" + android:color="?attr/colorOnSecondaryContainer" /> + <item + android:color="?attr/colorOnSurfaceVariant" /> +</selector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/item_root_primary_text.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/item_root_primary_text.xml new file mode 100644 index 000000000..c0175ca1b --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/item_root_primary_text.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_activated="true" android:color="?attr/colorOnSecondaryContainer" /> + <item android:color="?attr/colorOnSurfaceVariant" /> +</selector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/item_root_ripple_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/item_root_ripple_color.xml new file mode 100644 index 000000000..8c974f1f0 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/item_root_ripple_color.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 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 + + https://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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_activated="true" + android:alpha="@dimen/ripple_overlay_alpha" android:color="?attr/colorOnSecondaryContainer"/> + <item android:alpha="@dimen/ripple_overlay_alpha" android:color="?attr/colorOnSurface"/> +</selector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/item_root_secondary_text.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/item_root_secondary_text.xml new file mode 100644 index 000000000..50932a8c9 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/item_root_secondary_text.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_activated="true" android:color="?attr/colorOnSecondaryContainer" /> + <item android:color="?attr/colorOnSurfaceVariant" /> +</selector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/nav_rail_item_text_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/nav_rail_item_text_color.xml new file mode 100644 index 000000000..ec5aecb33 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/nav_rail_item_text_color.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_activated="true" android:color="?attr/colorSecondary" /> + <item android:color="?attr/colorOnSurfaceVariant" /> +</selector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/profile_tab_ripple_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/profile_tab_ripple_color.xml new file mode 100644 index 000000000..de985a40f --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/profile_tab_ripple_color.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 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 + + https://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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_activated="true" + android:alpha="@dimen/ripple_overlay_alpha" android:color="?attr/colorOnPrimaryContainer"/> + <item android:alpha="@dimen/ripple_overlay_alpha" android:color="?attr/colorOnSurfaceVariant"/> +</selector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/search_chip_background_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/search_chip_background_color.xml new file mode 100644 index 000000000..08c0ac3ca --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/search_chip_background_color.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2018 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 + + https://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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- Disabled --> + <item android:color="@android:color/transparent" android:state_enabled="false"/> + + <!-- Selected --> + <item android:color="?attr/colorSecondaryContainer" android:state_selected="true"/> + + <!-- Not selected: different from default value --> + <item android:color="@android:color/transparent" /> +</selector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/search_chip_ripple_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/search_chip_ripple_color.xml new file mode 100644 index 000000000..b4aa0b8a7 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/search_chip_ripple_color.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2018 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 + + https://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. + --> + +<!-- TODO(b/379776735): remove this file after M3 uplift --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- Selected. --> + <item android:state_pressed="true" android:state_selected="true" + android:alpha="0.16" android:color="?android:colorSecondary"/> + <item android:state_focused="true" android:state_hovered="true" android:state_selected="true" + android:alpha="0.16" android:color="?android:colorSecondary"/> + <item android:state_focused="true" android:state_selected="true" + android:alpha="0.12" android:color="?android:colorSecondary"/> + <item android:state_hovered="true" android:state_selected="true" + android:alpha="0.04" android:color="?android:colorSecondary"/> + <item android:state_selected="true" + android:alpha="0.00" android:color="?android:colorSecondary"/> + + <!-- Unselected. --> + <item android:state_pressed="true" android:alpha="0.16" android:color="?android:textColorSecondary"/> + <item android:state_focused="true" android:state_hovered="true" + android:alpha="0.16" android:color="?android:textColorSecondary"/> + <item android:state_focused="true" android:alpha="0.12" android:color="?android:textColorSecondary"/> + <item android:state_hovered="true" android:alpha="0.04" android:color="?android:textColorSecondary"/> + <item android:alpha="0.00" android:color="?android:textColorSecondary"/> +</selector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/search_chip_stroke_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/search_chip_stroke_color.xml new file mode 100644 index 000000000..518352c0d --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/search_chip_stroke_color.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2018 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 + + https://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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- Disabled --> + <item android:alpha="0.12" android:color="?attr/colorOnSurface" android:state_enabled="false"/> + + <!-- Focused: different from default value --> + <item android:color="?attr/colorSecondary" android:state_focused="true"/> + + <!-- Selected --> + <item android:color="@android:color/transparent" android:state_selected="true"/> + + <!-- Other states --> + <item android:color="?attr/colorOutline"/> +</selector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/search_chip_text_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/search_chip_text_color.xml new file mode 100644 index 000000000..be0cc404b --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/search_chip_text_color.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2018 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 + + https://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. + --> + +<!-- TODO(b/379776735): remove this file after M3 uplift --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_selected="true" android:color="@color/search_chip_text_selected_color"/> + <item android:state_enabled="true" android:color="?android:textColorSecondary"/> + <item android:state_enabled="false" android:color="?android:textColorSecondary" android:alpha="0.3"/> +</selector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/sort_list_text.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/sort_list_text.xml new file mode 100644 index 000000000..a1e93630b --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/sort_list_text.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:state_checked="true" + android:color="?android:attr/colorAccent"/> + <item + android:color="?android:attr/textColorPrimary"/> +</selector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable-ldrtl/roots_list_border.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable-ldrtl/roots_list_border.xml new file mode 100644 index 000000000..6c2b50857 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable-ldrtl/roots_list_border.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<inset xmlns:android="http://schemas.android.com/apk/res/android" + android:insetTop="-1dp" + android:insetBottom="-1dp" + android:insetRight="-1dp"> + <shape android:shape="rectangle"> + <stroke + android:width="1dp" + android:color="?android:strokeColor"/> + </shape> +</inset>
\ No newline at end of file diff --git a/res/drawable/selection_demo_band_overlay.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/band_select_overlay.xml index adf2b27f8..53f969284 100644 --- a/res/drawable/selection_demo_band_overlay.xml +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/band_select_overlay.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - ~ Copyright (C) 2015 The Android Open Source Project + ~ 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. @@ -17,6 +17,6 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> - <solid android:color="#339999ff" /> - <stroke android:width="1dp" android:color="#44000000" /> + <solid android:color="@color/band_select_background" /> + <stroke android:width="1dp" android:color="@color/band_select_border" /> </shape> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/bottom_sheet_dialog_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/bottom_sheet_dialog_background.xml new file mode 100644 index 000000000..eba36783f --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/bottom_sheet_dialog_background.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + + <solid android:color="?android:attr/colorBackground" /> + + <corners android:topLeftRadius="@dimen/grid_item_radius" + android:topRightRadius="@dimen/grid_item_radius" + android:bottomLeftRadius="0dp" + android:bottomRightRadius="0dp"/> + +</shape> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/breadcrumb_item_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/breadcrumb_item_background.xml new file mode 100644 index 000000000..8e6282199 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/breadcrumb_item_background.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<ripple + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:color="?attr/colorControlHighlight"> + <item + android:id="@android:id/mask" + android:drawable="@android:color/white"/> + + <item> + <selector> + <item + app:state_highlighted="true" + android:drawable="@color/item_breadcrumb_background_hovered"/> + <item + app:state_highlighted="false" + android:drawable="@android:color/transparent"> + <corners + android:topLeftRadius="2dp" + android:topRightRadius="2dp" + android:bottomLeftRadius="2dp" + android:bottomRightRadius="2dp" + /> + </item> + </selector> + </item> +</ripple>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/circle_button_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/circle_button_background.xml new file mode 100644 index 000000000..be2874119 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/circle_button_background.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="oval"> + <solid + android:color="#66000000"/> +</shape>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/debug_msg_1.png b/res/flag(com.android.documentsui.flags.use_material3)/drawable/debug_msg_1.png Binary files differnew file mode 100644 index 000000000..862769a39 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/debug_msg_1.png diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/debug_msg_2.png b/res/flag(com.android.documentsui.flags.use_material3)/drawable/debug_msg_2.png Binary files differnew file mode 100644 index 000000000..e4c62591c --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/debug_msg_2.png diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/drag_shadow_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/drag_shadow_background.xml new file mode 100644 index 000000000..eed005eca --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/drag_shadow_background.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="@color/item_drag_shadow_background" /> + <corners + android:bottomRightRadius="2dp" + android:bottomLeftRadius="2dp" + android:topLeftRadius="2dp" + android:topRightRadius="2dp"/> +</shape> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/drop_badge_states.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/drop_badge_states.xml new file mode 100644 index 000000000..7b78a7b69 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/drop_badge_states.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <!-- state when we can't drop --> + <item + app:state_reject_drop="true" + android:drawable="@drawable/ic_reject_drop_badge"/> + + <!-- state when we can drop, and it will be a copy --> + <item + app:state_reject_drop="false" + app:state_copy="true" + android:drawable="@drawable/ic_drop_copy_badge"/> + + <!-- default state. Also used to show state when we can drop, and it will be a move --> + <item + app:state_reject_drop="false" + app:state_copy="false" + android:drawable="@android:color/transparent" /> +</selector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/dropdown_sort_widget_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/dropdown_sort_widget_background.xml new file mode 100644 index 000000000..20179035e --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/dropdown_sort_widget_background.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. + --> + +<ripple xmlns:android="http://schemas.android.com/apk/res/android" + android:color="?attr/colorControlHighlight" > + <item + android:id="@android:id/mask" + android:drawable="@android:color/white"/> +</ripple> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/empty.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/empty.xml new file mode 100644 index 000000000..cddd96821 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/empty.xml @@ -0,0 +1,51 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="210dp" + android:height="210dp" + android:viewportWidth="210" + android:viewportHeight="210"> + + <path + android:fillColor="#DADCE0" + android:pathData="M115,109.44H95c-1.1,0-2-0.9-2-2s0.9-2,2-2h20c1.1,0,2,0.9,2,2S116.1,109.44,115,109.44z" /> + <path + android:fillColor="#DADCE0" + android:pathData="M62.67,85.14l3-0.11L62.67,85.14c-0.04-0.74-0.06-1.48-0.06-2.22c0-0.69,0.02-1.37,0.05-2.05l5.99,0.29 c-0.03,0.58-0.04,1.17-0.04,1.76c0,0.64,0.02,1.28,0.05,1.92l-2.99,0.2L62.67,85.14z" /> + <path + android:fillColor="#DADCE0" + android:pathData="M147.35,84.94l-5.99-0.28c0.03-0.56,0.04-1.12,0.04-1.69c0-0.64-0.02-1.28-0.05-1.92l-0.01-0.13l5.99-0.3 l0,0.08c0.04,0.77,0.06,1.52,0.06,2.26C147.39,83.64,147.38,84.29,147.35,84.94z" /> + <path + android:fillColor="#EA4335" + android:pathData="M72.56,66.45l-5.35-2.72c0.65-1.28,1.38-2.54,2.16-3.75l5.04,3.25C73.74,64.27,73.12,65.35,72.56,66.45z" /> + <path + android:fillColor="#EA4335" + android:pathData="M137.35,66.27c-0.56-1.09-1.19-2.17-1.87-3.21l5.02-3.28c0.79,1.21,1.52,2.46,2.18,3.74L137.35,66.27z" /> + <path + android:fillColor="#DADCE0" + android:pathData="M85.15,52.44l-3.28-5.03c1.2-0.79,2.46-1.52,3.74-2.18l2.75,5.33C87.26,51.14,86.18,51.77,85.15,52.44z" /> + <path + android:fillColor="#DADCE0" + android:pathData="M124.69,52.34c-1.04-0.67-2.12-1.29-3.22-1.85l2.72-5.35c1.28,0.65,2.54,1.38,3.75,2.15L124.69,52.34z" /> + <path + android:fillColor="#EA4335" + android:pathData="M103.12,46.61l-0.4-5.99l0.08,0c1.45-0.07,2.85-0.08,4.25-0.01l-0.28,5.99 C105.56,46.54,104.34,46.54,103.12,46.61z" /> + <path + android:fillColor="#DADCE0" + android:pathData="M154,95.44v70H56v-70H154 M154,91.44H56c-2.21,0-4,1.79-4,4v70c0,2.21,1.79,4,4,4h98c2.21,0,4-1.79,4-4 v-70C158,93.24,156.21,91.44,154,91.44L154,91.44z" /> + <path + android:pathData="M 0 0 H 210 V 210 H 0 V 0 Z" /> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/fast_scroll_thumb_drawable.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/fast_scroll_thumb_drawable.xml new file mode 100644 index 000000000..540a3877e --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/fast_scroll_thumb_drawable.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true"> + <shape android:shape="rectangle"> + <solid android:color="?android:attr/colorControlNormal" /> + <size android:width="8dp" android:height="48dp" /> + </shape> + </item> + <item> + <shape android:shape="rectangle"> + <solid android:color="?android:attr/colorControlNormal" /> + <size android:width="8dp" android:height="48dp" /> + </shape> + </item> +</selector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/fast_scroll_track_drawable.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/fast_scroll_track_drawable.xml new file mode 100644 index 000000000..8daf5e69a --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/fast_scroll_track_drawable.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="@android:color/transparent" /> + <size android:width="8dp" /> +</shape> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/generic_ripple_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/generic_ripple_background.xml new file mode 100644 index 000000000..74e1f9395 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/generic_ripple_background.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<ripple + xmlns:android="http://schemas.android.com/apk/res/android" + android:color="?android:attr/colorControlHighlight"> + <item + android:id="@android:id/mask"> + <shape android:shape="rectangle"> + <solid android:color="@android:color/white"/> + </shape> + </item> +</ripple>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/gradient_actionbar_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/gradient_actionbar_background.xml new file mode 100644 index 000000000..e3ace24a6 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/gradient_actionbar_background.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <gradient + android:startColor="@color/tool_bar_gradient_max" + android:endColor="@android:color/transparent" + android:angle="270" + android:type="linear" > + </gradient> +</shape>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/grid_item_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/grid_item_background.xml new file mode 100644 index 000000000..8ad58f3c9 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/grid_item_background.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_selected="true"> + <color android:color="?android:colorSecondary"/> + </item> + <item android:state_drag_hovered="true"> + <color android:color="?android:strokeColor"/> + </item> + <item android:state_selected="false"> + <color android:color="?android:colorBackground"/> + </item> +</selector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/hourglass.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/hourglass.xml new file mode 100644 index 000000000..e4c803da9 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/hourglass.xml @@ -0,0 +1,168 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="421dp" + android:height="909dp" + android:viewportWidth="421.0" + android:viewportHeight="909.0"> + <path + android:pathData="M36,122.9c-2.8,-2.6,-5.7,-5.1,-8.3,-7.8c-5.6,-6,-9.2,-12.9,-8.8,-21.5c0.3,-7.5,0.6,-15,-0.1,-22.5 c-1.2,-14.1,5.5,-23.9,16,-31.9c16.7,-12.8,36.1,-19.6,56.1,-25.1c23.8,-6.5,48,-10.2,72.5,-12.3C168.6,1.3,174,2.2,179,0 c19.3,0,38.7,0,58,0c6,2.1,12.4,1.3,18.6,1.8c30.2,2.7,59.9,7.6,88.5,17.5c16.5,5.7,32.6,12.6,45.2,25.4c6.5,6.6,10.3,14,9.8,23.6 c-0.4,7.8,-0.5,15.7,0,23.4c0.6,10.3,-3.4,18.4,-10.6,25.2c-2.2,2,-4.4,4,-6.6,6c-3,2,-6.1,4,-9.1,5.9c-9.2,4.5,-18.5,9,-28.2,12.3 c-42.4,14.5,-86.3,18.8,-130.8,19.6c-10.9,0.2,-21.9,-0.4,-32.9,-0.7c-4.6,-0.4,-9.2,-0.8,-13.9,-1.1c-18.9,-1.1,-37.5,-3.9,-56,-7.6 c-15.3,-3.1,-30.2,-7.6,-44.9,-12.6c-7.6,-3.7,-15.3,-7.4,-22.9,-11.1C41.1,125.8,38.6,124.3,36,122.9z M41,72c2.9,6.9,7.1,12.6,13.1,17.2 c13,10,27.9,15.8,43.4,20.6c28.2,8.8,57.2,12.8,86.5,14c31.8,1.2,63.7,0.8,95.3,-4.6c25.3,-4.4,50.1,-10,72.9,-22.2 c10.8,-5.8,20,-13.1,24.7,-24.9c2.3,-11,-2.3,-19.5,-10.2,-26.4c-10.5,-9.2,-23.1,-14.9,-36.2,-19.6C295.2,13.4,258.4,9.7,221.2,8.1 c-11.1,-0.5,-22.2,0,-33.4,0.6c-21.4,1,-42.6,3.1,-63.6,7.3c-22.2,4.5,-44.1,10.3,-63.4,22.6C48.9,46.3,38.4,55.4,41,72z" + android:fillColor="#9F9F9F"/> + <path + android:pathData="M0,829c3.7,-2.8,4.7,-7.6,7.8,-10.9c2.6,-2.8,4.9,-5.7,9.2,-7.6c0,3.4,-0.1,6.5,0,9.5c0,1.5,-0.7,3.5,1.7,4 c0.4,3.3,1.4,6.4,2.9,9.4c3.8,7.7,10,13,16.8,17.9c9.2,6.7,19.7,10.8,29.8,15.5c-0.7,2.4,1.3,0.7,1.8,1.1l0,0c1.5,2.1,3.7,2.2,6,2 l0,0c0.8,0.6,1.5,1.4,2.4,1.7c9.5,2.7,18.9,5.8,28.7,7.4c3.6,0.6,7,3.5,10.9,1.1c2.4,0.4,4.8,0.8,7.1,1.2c0.2,1.5,1.3,1.6,2.5,1.8 c6.6,0.9,13.3,2.4,19.9,2.8c5.1,0.3,10.3,2.9,15.4,0.3c0.4,0,0.8,0.1,1.1,0.1c0.3,2.2,2.1,1.8,3.5,1.8c3.8,0,7.6,0,11.5,0 c1.1,1.4,2.7,1,4.1,1c17.2,0,34.5,0,51.7,0c1.4,0,3,0.4,4.1,-1c3.8,0,7.6,0,11.5,0c1.4,0,3.2,0.4,3.5,-1.8c9.4,-1,18.7,-2.1,28.1,-3.1 c6,1.3,11.6,0.4,16.9,-2.8c21.2,-4.2,42.1,-9.3,61.8,-18.4c15.8,-7.3,30.8,-15.8,38,-33.1c2.4,-2,1.9,-4.8,2.2,-7.4c0.3,-3,0,-6,0.1,-9 c0,-1,-0.3,-2.1,0.7,-2.7c1.1,-0.7,1.7,0.5,2.5,1c7.2,5,12.1,11.7,14.8,20c0.4,1.2,0.6,2.2,2.1,2.3c0,3.3,0,6.7,0,10 c-1.5,0,-1.8,1.1,-2.2,2.2c-3.8,10.2,-11.2,17.5,-20.1,23.3c-20.8,13.6,-44.1,21.2,-68.1,26.7c-29.2,6.7,-58.7,11,-88.7,11.7 c-1.6,0,-3.5,-0.5,-3.9,2c-18.7,0,-37.3,0,-56,0c-0.3,-2.5,-2.3,-1.9,-3.9,-2c-5.6,-0.1,-11.2,-0.5,-16.9,-0.8c-18.5,-1.2,-36.8,-3.8,-55,-7.3 C79.9,893.9,54,887,30.2,874C19,867.9,8.5,860.9,2.5,849C2,848,1.4,847,0,847C0,841,0,835,0,829z" + android:fillColor="#E6E4E4"/> + <path + android:pathData="M372.9,128.9c3,-2,6.1,-4,9.1,-5.9c-0.2,2.7,0.2,5.4,1,8c-1.5,1.6,-0.3,1.8,1,2c0.3,1,0.7,2,1,3 c-1.5,1.6,-0.3,1.8,1,2c0.7,2,1.3,4,2,6c-1.5,1.6,-0.3,1.8,1,2c0.3,1.7,0.7,3.3,1,5c-1,2.3,-0.6,4.1,2,5c4.9,23.8,9,47.6,8,72 c-3.5,1.5,-2.1,3.8,-1,6c-1,6,-2,12,-3,18c-1.3,1,-1.3,2,0,3c0,0.7,0,1.3,0,2c-2.1,0.4,-2.6,1.3,-1,3c0,0.3,0,0.7,0,1 c-1.3,0.2,-2.5,0.4,-1,2c0.4,2.1,-0.7,4,-1,6c-1.3,0.2,-2.5,0.4,-1,2c-3.7,9.3,-7.3,18.7,-11,28c-2.7,1.2,-4.2,2.9,-3,6 c-3.4,6.9,-7.8,13.3,-12.2,19.5c-6.1,8.6,-12.4,17.3,-19.4,25.2c-7.3,8.3,-15.5,15.8,-23.9,23c-11.9,10.3,-24.9,19.3,-38.1,27.7 c-12.2,7.8,-25.4,14.1,-38.4,20.5c-12.1,6,-18.5,15.8,-21,28.6c-1.5,7.8,-0.5,15.4,2,22.8c1.2,3.5,3.7,6.1,5.6,9.2 c5.4,8.6,14.8,10.5,22.6,15c15.3,9,30.8,17.7,45.3,28.1c14.4,10.4,28.2,21.5,40.5,34.1c10.1,10.4,18.5,22.2,26.8,34.3 c6.5,9.5,11.3,19.6,16.1,29.8c-1.5,1.6,-0.3,1.8,1,2c0.7,2,1.3,4,2,6c-1,2.3,-0.6,4.1,2,5c0.7,1.2,1.2,2.5,1,4c-1,2.3,-0.6,4.1,2,5 c1.2,12.3,4.6,24.1,5.7,36.5c0.8,8.4,1.4,16.8,1,25.1c-0.3,5.9,-1.1,12,-1.9,18c-1.2,8.7,-2.3,17.4,-4.2,25.9 c-1.5,6.6,-3.7,13.1,-5.6,19.6c-1.8,3.1,-2.9,6.5,-3.9,9.9c-3.4,6.4,-5.6,13.6,-11.9,18.2c-0.1,-3.8,1.6,-7.1,3,-10.4 c8.7,-20.9,13,-42.8,14.7,-65.1c1,-12.9,0.2,-25.8,-1.7,-38.7c-2.7,-18.5,-7.8,-36.2,-15.8,-53.1c-7.3,-15.4,-16.8,-29.3,-27.7,-42.4 c-2.7,-3.2,-6.3,-5.7,-9.6,-8.6c0.4,0.8,0.7,1.4,1,1.9c0.7,1.1,1.5,2.2,2.3,3.3c16.5,21.5,28.5,45.2,34.2,71.7c0.7,3.3,3.1,6.9,0.3,10.4 c-1,-1.9,-2.1,-3.7,-3.1,-5.6c-3.3,-6.3,-6.1,-12.9,-11.7,-17.6c-0.4,-0.9,-0.8,-1.8,-1.3,-2.6c-4,-6.3,-10.4,-10.4,-14.8,-16.2c0,-5.4,-2.7,-9.9,-4.8,-14.5 c-8.4,-18.6,-20.4,-34.9,-32.9,-50.8c-8.4,-10.8,-15.5,-22.8,-28.7,-28.8c-5.3,-2.4,-10,-6,-15.1,-8.6c-5.1,-2.6,-9.9,-6.4,-16.3,-5.2 c-5.2,1,-10.4,2.1,-15.3,4.1c-29.3,11.9,-48.4,34.1,-61.8,61.9c-0.3,0.3,-0.7,0.6,-1,1c-7.1,0.8,-13.9,2.9,-20.7,5.1 c-32.6,10.6,-61,27.4,-82.3,54.9c-9.2,11.6,-15.4,24.7,-18.9,39c-1.5,-1.1,-1.1,-2.7,-1.1,-4.1c-0.1,-9.6,0.3,-19.2,1.8,-28.7 c3.7,-22.6,11.8,-43.5,24,-62.8c12.6,-20,28.6,-36.9,47,-51.7c21.3,-17.3,44.6,-31.3,69.3,-42.9c14.5,-6.8,20,-18.8,21.8,-33.1 c1.8,-13.3,-4.9,-24.1,-12.2,-34.4c-3.6,-5,-7.4,-9.8,-13.2,-12.5c-5.8,-2.8,-11.6,-5.7,-17.4,-8.7c-22,-11.6,-42.6,-25.1,-61.1,-41.7 c-20.7,-18.6,-37.9,-40,-48.8,-65.9c-6.7,-15.7,-10.9,-32.1,-12,-49c-1.8,-27.1,2.1,-53.6,11.7,-79.1c3.8,-10.1,7.1,-20.4,13.3,-29.4 c14.7,5,29.6,9.5,44.9,12.6c18.5,3.7,37.2,6.5,56,7.6c4.6,0.3,9.3,0.7,13.9,1.1c0.2,3.6,-1.5,6.8,-2.6,10 c-11.9,33.6,-17.8,68.2,-17.2,103.8c0.2,9.7,1.3,19.4,2.7,29.1c3.8,24.6,11.4,47.7,26,68.1c12.2,17.1,28.4,28.6,49,33.4 c4.7,1.1,9.5,2.2,14.5,-0.5c18.7,-10.2,36.8,-21.2,53.7,-34.2c15.4,-11.9,29.4,-25.3,41.5,-40.5c12.9,-16.2,23.4,-33.8,30.4,-53.4 c6.4,-17.6,10.3,-35.6,10.9,-54.3c0.5,-15.9,0.2,-31.9,-3,-47.6C383.8,158.7,380.1,143.3,372.9,128.9z" + android:fillColor="#EDECEC"/> + <path + android:pathData="M383,780c1.1,-3.4,2.1,-6.8,3.9,-9.9c7.8,7.1,12.8,15.2,12.2,26.4c-0.6,10.7,-0.3,21.5,-0.5,32.3 c-7.2,17.3,-22.2,25.8,-38,33.1c-19.7,9.1,-40.6,14.1,-61.8,18.4c-5.6,0.9,-11.3,1.9,-16.9,2.8c-9.4,1,-18.7,2.1,-28.1,3.1 c-5,0.3,-9.9,0.7,-14.9,1c-20,1.2,-40,0.9,-60,0c-5,-0.3,-9.9,-0.7,-14.9,-1c-0.4,0,-0.8,-0.1,-1.1,-0.1c-12.6,-1.6,-25.2,-3.2,-37.9,-4.8 c-2.4,-0.4,-4.8,-0.8,-7.1,-1.2c-2.6,-0.6,-5.1,-1.3,-7.7,-1.8c-11.6,-2,-22.6,-6.3,-34.2,-8.4c0,0,0,0,0,0c-1.7,-1.6,-3.7,-2.2,-6,-2c0,0,0,0,0,0 c-0.2,-1,-1.1,-0.9,-1.8,-1.1c-10.2,-4.7,-20.6,-8.8,-29.8,-15.5c-6.8,-4.9,-13,-10.2,-16.8,-17.9c-1.5,-3,-2.4,-6.1,-2.9,-9.4 c0.1,-10.3,0,-20.6,0.2,-30.9c0.1,-8.3,3.5,-15,10,-20.2c2,3.5,3.4,7.1,4.1,11c-1.1,0.8,-1,2,-1.1,3.1c-0.6,8.2,2.9,14.9,8.3,20.6 c8.9,9.6,20.4,15.4,32.3,20.2c17.9,7.2,36.5,11.9,55.4,15.4c20.1,3.7,40.3,5.7,60.6,6.5c21.4,0.8,42.8,0.4,64.2,-1.6 c19.8,-1.9,39.4,-4.6,58.7,-9.3c19.9,-4.8,39.3,-11.2,56.4,-22.9c7.8,-5.3,15.2,-11.3,17.4,-21C386.4,790.1,388.3,784.3,383,780z" + android:fillColor="#9F9F9F"/> + <path + android:pathData="M378,305c-1.2,-3.1,0.3,-4.8,3,-6C380.6,301.3,379.7,303.3,378,305z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M399,234c-1.1,-2.2,-2.5,-4.5,1,-6C399.7,230,400.8,232.2,399,234z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M392,156c-2.6,-0.9,-3,-2.7,-2,-5C391.4,152.4,391.6,154.2,392,156z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M389,636c-2.6,-0.9,-3,-2.7,-2,-5C388.4,632.4,388.6,634.2,389,636z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M392,645c-2.6,-0.9,-3,-2.7,-2,-5C391.4,641.4,391.6,643.2,392,645z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M396,255c-1.3,-1,-1.3,-2,0,-3C397.3,253,397.3,254,396,255z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M395,260c-1.6,-1.7,-1.1,-2.6,1,-3C395.7,258,395.3,259,395,260z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M384,133c-1.3,-0.2,-2.5,-0.4,-1,-2C383.8,131.4,384,132.2,384,133z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M385,625c-1.3,-0.2,-2.5,-0.4,-1,-2C384.8,623.4,385,624.2,385,625z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M392,271c-1.5,-1.6,-0.3,-1.8,1,-2C393,269.8,392.8,270.6,392,271z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M394,263c-1.5,-1.6,-0.3,-1.8,1,-2C395,261.8,394.8,262.6,394,263z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M386,138c-1.3,-0.2,-2.5,-0.4,-1,-2C385.8,136.4,386,137.2,386,138z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M389,146c-1.3,-0.2,-2.5,-0.4,-1,-2C388.8,144.4,389,145.2,389,146z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M33.1,783.9c-0.8,-3.9,-2.2,-7.6,-4.1,-11c-3.7,-11.7,-7.2,-23.5,-9.2,-35.5c-1.3,-7.6,-1.9,-15.4,-2.7,-23.2 c-0.6,-6.2,-0.9,-12.4,-1,-18.5c-0.2,-7.9,1.9,-15.7,2.3,-23.4c0.5,-10.1,2.9,-19.5,5.5,-29c6.3,-23.1,17.3,-43.9,31.5,-62.8 c23.4,-31.1,53.3,-54.7,86.9,-74.1c10.1,-5.8,20.3,-11.6,30.9,-16.2c11.7,-5.2,16.3,-14.9,18.8,-26.3c3.2,-14.9,-2.8,-26.6,-12.7,-37.1 c-1.8,-1.9,-3.9,-3.1,-6.2,-4.2c-23.7,-11.4,-46.4,-24.4,-67.2,-40.7c-16.2,-12.6,-31.3,-26.5,-44.2,-42.6c-16.2,-20.3,-28.8,-42.5,-36.2,-67.5 c-3.1,-10.6,-5.4,-21.3,-6.2,-32.4c-0.7,-9.6,-3.2,-19.3,-2,-28.8c0.8,-6.6,1.5,-13.4,1.9,-20c1,-15.2,4.9,-29.6,9.2,-44c1.7,-5.7,4,-11.3,6.4,-16.8 c0.9,-2.2,1.3,-4.4,1.3,-6.8c2.6,1.4,5.1,2.9,7.2,4.9c-0.6,0.8,-1.4,1.4,-1.8,2.3c-11.2,26.2,-16.2,53.8,-17.4,82.2 c-0.4,8.8,1,17.5,1.9,26.2c2,19.7,7.4,38.4,15.6,56.3c17.9,39.2,46.6,69.1,81.3,93.6c18.5,13.1,38.1,24.3,58.5,34.1 c3.3,1.6,6,3.7,8.1,6.5c8,10.6,12.6,22.1,9.6,35.7c-2.1,9.4,-6.5,17.9,-14.8,22.7c-8.2,4.7,-16.9,8.5,-25.3,12.9 c-22.5,12,-43.8,25.8,-62.6,43c-21.9,19.9,-40.8,42.1,-53.7,69.2C26.3,646.5,20.6,682,24.1,719c1.8,18.7,7,36.7,12.7,54.6 c5.9,18.7,18.2,30.9,35.3,38.9c15.4,7.2,31.5,12.2,48.1,15.8c1.6,0.4,4.3,-0.3,4.8,2.6c-18,-2.8,-35.4,-7.5,-52.3,-14.5 c-12.2,-5.1,-23.4,-11.4,-32.4,-21.4C37.2,791.7,36.5,787,33.1,783.9z" + android:fillColor="#EDECEC"/> + <path + android:pathData="M372.9,128.9c7.2,14.3,10.9,29.8,14.1,45.4c3.2,15.7,3.5,31.6,3,47.6c-0.6,18.7,-4.6,36.7,-10.9,54.3 c-7.1,19.6,-17.6,37.2,-30.4,53.4c-12.1,15.2,-26.1,28.6,-41.5,40.5c-16.9,13,-35,24,-53.7,34.2c-5,2.7,-9.8,1.6,-14.5,0.5 c-20.6,-4.8,-36.8,-16.3,-49,-33.4c-14.6,-20.4,-22.3,-43.5,-26,-68.1c-1.5,-9.7,-2.6,-19.4,-2.7,-29.1c-0.6,-35.6,5.4,-70.2,17.2,-103.8 c1.2,-3.3,2.8,-6.4,2.6,-10c11,0.2,21.9,0.9,32.9,0.7c44.4,-0.8,88.4,-5.2,130.8,-19.6C354.4,137.9,363.7,133.5,372.9,128.9z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M377,72c-4.6,11.9,-13.9,19.1,-24.7,24.9c-22.9,12.2,-47.6,17.9,-72.9,22.2c-31.6,5.4,-63.5,5.9,-95.3,4.6 c-29.3,-1.1,-58.3,-5.1,-86.5,-14C82.1,105,67.2,99.1,54.2,89.2C48.2,84.6,43.9,78.8,41,72c3.9,-1.8,4.6,-6.2,7.3,-9 c10.3,-10.5,22.9,-16.9,36.5,-21.8c19.7,-7.1,40,-11.5,60.7,-14.5c19.4,-2.8,38.9,-3.9,58.4,-4.5c17.9,-0.6,35.8,0.8,53.6,2.8 c15,1.6,29.9,3.5,44.5,7.1c20,4.9,39.7,10.7,57.2,22.1C366.5,58.8,371.5,65.5,377,72z" + android:fillColor="#8D8E8E"/> + <path + android:pathData="M125,831c-0.4,-2.9,-3.2,-2.3,-4.8,-2.6c-16.6,-3.7,-32.7,-8.7,-48.1,-15.8c-17.1,-8,-29.4,-20.2,-35.3,-38.9 c-5.7,-17.9,-10.9,-35.9,-12.7,-54.6c-3.6,-37.1,2.1,-72.5,18.4,-106.4c13,-27.1,31.9,-49.3,53.7,-69.2c18.8,-17.1,40.2,-30.9,62.6,-43 c8.4,-4.5,17.1,-8.2,25.3,-12.9c8.4,-4.8,12.7,-13.3,14.8,-22.7c3.1,-13.6,-1.6,-25.1,-9.6,-35.7c-2.1,-2.8,-4.8,-4.9,-8.1,-6.5 c-20.4,-9.9,-40,-21.1,-58.5,-34.1c-34.7,-24.6,-63.4,-54.5,-81.3,-93.6c-8.2,-17.9,-13.6,-36.6,-15.6,-56.3c-0.9,-8.7,-2.3,-17.5,-1.9,-26.2 c1.2,-28.3,6.2,-55.9,17.4,-82.2c0.4,-0.9,1.2,-1.5,1.8,-2.3c7.6,3.7,15.3,7.4,22.9,11.1c-6.2,9,-9.5,19.3,-13.3,29.4 c-9.6,25.5,-13.5,52,-11.7,79.1c1.1,16.9,5.4,33.3,12,49c11,25.9,28.1,47.4,48.8,65.9c18.5,16.6,39.1,30.2,61.1,41.7 c5.7,3,11.5,5.9,17.4,8.7c5.8,2.8,9.7,7.6,13.2,12.5c7.3,10.3,14,21.1,12.2,34.4c-1.9,14.3,-7.4,26.3,-21.8,33.1 c-24.7,11.6,-48,25.7,-69.3,42.9c-18.3,14.9,-34.3,31.7,-47,51.7c-12.2,19.3,-20.3,40.2,-24,62.8c-1.6,9.6,-2,19.1,-1.8,28.7 c0,1.4,-0.4,3.1,1.1,4.1c-0.6,14.9,0.1,29.8,3,44.5c4.2,21.4,9.1,42.6,26,58.4c-0.2,2.3,0.9,4.1,2.2,5.9c8.8,12.3,22,18.6,35.3,24.1 c26.4,10.9,54.2,16.1,82.4,19.1c1.7,0.2,3,0.4,3,2.4c-4.5,0.7,-9,0.9,-13.4,0.5c-13.2,-1,-26.5,-1.9,-39.6,-4.1c-0.6,-2.4,-1.7,-2.3,-3.1,-0.6 c-1.3,-0.1,-2.6,-0.3,-3.9,-0.4c-0.6,-2.3,-1.6,-2.4,-3.1,-0.7c-0.6,-0.1,-1.3,-0.2,-1.9,-0.3c-0.6,-2.4,-1.7,-2.4,-3.1,-0.6 C126.2,831.2,125.6,831.1,125,831z" + android:fillColor="#E8E8E7"/> + <path + android:pathData="M377,72c-5.4,-6.4,-10.5,-13.2,-17.7,-17.9C341.7,42.7,322.1,36.9,302,32c-14.6,-3.6,-29.5,-5.5,-44.5,-7.1 c-17.8,-1.9,-35.7,-3.3,-53.6,-2.8c-19.5,0.6,-39,1.7,-58.4,4.5c-20.7,3,-41,7.4,-60.7,14.5C71.3,46.1,58.7,52.4,48.4,63 c-2.7,2.8,-3.5,7.2,-7.3,9c-2.6,-16.6,7.9,-25.6,19.8,-33.3c19.3,-12.3,41.2,-18.2,63.4,-22.6c21,-4.2,42.2,-6.3,63.6,-7.3 c11.1,-0.5,22.3,-1,33.4,-0.6c37.2,1.5,74,5.3,109.4,17.9c13.1,4.6,25.6,10.4,36.2,19.6C374.7,52.5,379.3,61,377,72z" + android:fillColor="#808080"/> + <path + android:pathData="M179,887.2c20,0.9,40,1.2,60,0c0,0.3,0,0.5,0,0.8c-1.1,1.4,-2.7,1,-4.1,1c-17.2,0,-34.5,0,-51.7,0 c-1.4,0,-3,0.4,-4.1,-1C179,887.7,179,887.5,179,887.2z" + android:fillColor="#F4F3F2"/> + <path + android:pathData="M76,869.9c11.6,2.2,22.6,6.5,34.2,8.4c2.6,0.4,5.2,1.2,7.7,1.8c-3.9,2.3,-7.3,-0.6,-10.9,-1.1 c-9.8,-1.6,-19.2,-4.7,-28.7,-7.4C77.5,871.3,76.8,870.5,76,869.9z" + android:fillColor="#F4F3F2"/> + <path + android:pathData="M125.1,881.3c12.6,1.6,25.2,3.2,37.9,4.8c-5.2,2.6,-10.3,0,-15.4,-0.3c-6.7,-0.4,-13.3,-1.9,-19.9,-2.8 C126.3,882.9,125.2,882.8,125.1,881.3z" + android:fillColor="#F4F3F2"/> + <path + android:pathData="M282,883.1c5.6,-0.9,11.3,-1.9,16.9,-2.8C293.7,883.4,288.1,884.4,282,883.1z" + android:fillColor="#F4F3F2"/> + <path + android:pathData="M179,887.2c0,0.3,0,0.5,0,0.8c-3.8,0,-7.6,0,-11.5,0c-1.4,0,-3.2,0.4,-3.5,-1.8C169,886.5,174,886.9,179,887.2z" + android:fillColor="#FFFFFF"/> + <path + android:pathData="M239,888c0,-0.3,0,-0.5,0,-0.8c5,-0.3,9.9,-0.7,14.9,-1c-0.3,2.2,-2.1,1.8,-3.5,1.8C246.6,888,242.8,888,239,888z" + android:fillColor="#FFFFFF"/> + <path + android:pathData="M70,867.9c2.3,-0.2,4.3,0.4,6,2C73.8,870.1,71.6,870,70,867.9z" + android:fillColor="#F4F3F2"/> + <path + android:pathData="M68.2,866.8c0.7,0.2,1.6,0.2,1.8,1.1C69.5,867.4,67.6,869.2,68.2,866.8z" + android:fillColor="#F4F3F2"/> + <path + android:pathData="M165,584c0.3,-0.3,0.7,-0.6,1,-1c10.5,-1.3,21,-3.3,31.5,-3.8c20.8,-1.1,41.4,0.7,61.7,5.4 c30.5,7,57.8,20.3,81.8,40.5c4.4,5.9,10.8,10,14.8,16.2c0.5,0.8,0.9,1.7,1.3,2.6c-2.4,4.1,-4.7,8.1,-7.1,12.2c-4,3.7,-6.3,8.9,-11,12 c-1.6,-0.1,-2.8,0.5,-4.1,1.5c-12.6,9.3,-26.7,15.6,-41.5,20.1c-31,9.4,-62.6,13.3,-95.1,11.6c-12.3,-0.6,-24.5,-1.5,-36.5,-3.4 c-4.5,-0.7,-5.3,0.5,-4.8,4.2c-0.5,0,-1,0.1,-1.5,0c-17.8,-3.9,-34.7,-10.3,-50.9,-18.7c-1,-0.5,-1.6,-1.1,-1.6,-2.3c2.3,-0.3,4.1,1.1,6.1,2 c14.2,6.2,28.9,10.6,44.1,13.3c2.5,0.4,3,0.2,2.4,-2.3c-2.5,-9.3,-3.7,-18.7,-4.8,-28.3c-1.5,-13.7,-0.3,-27.1,1.7,-40.5 C154.6,610.8,159.7,597.4,165,584z" + android:fillColor="#E57474"/> + <path + android:pathData="M103,681c0.1,1.1,0.7,1.8,1.6,2.3c16.2,8.4,33.1,14.8,50.9,18.7c0.5,0.1,1,0,1.5,0c0.6,0.4,1.3,0.7,1.9,1.1 c-0.1,2.7,1,5.2,1.9,7.6c6.5,17.8,16.5,33.6,27.5,48.8c12.5,17.1,27.1,32.1,45.1,43.6c6.6,4.2,13.7,7.3,20.5,11 c-15.6,2.8,-31.4,2.5,-47.1,2.4c-9.9,0,-19.9,-0.2,-29.8,-1.1c-18.2,-1.6,-36.2,-3.9,-54,-8.3c-18.1,-4.4,-35.9,-9.5,-51,-21.1 c-16.9,-15.8,-21.8,-37,-26,-58.4c-2.9,-14.7,-3.6,-29.6,-3,-44.5c3.5,-14.4,9.7,-27.4,18.9,-39c3.4,4.8,6.2,10.1,10.3,14.2 c6,6.1,11.6,13,19.7,16.8c0.5,0.8,1.2,1,2.1,1c0,0,0,0,0,0c0.3,0.3,0.7,0.7,1,1c0,0,0,0,0,0c0.3,0.3,0.7,0.7,1,1l0,0 c1,1.3,2.4,1.8,4,2l0,0C100.7,681.2,101.9,681,103,681L103,681z" + android:fillColor="#E6A3A3"/> + <path + android:pathData="M341,625c-24,-20.1,-51.3,-33.5,-81.8,-40.5c-20.3,-4.7,-41,-6.5,-61.7,-5.4c-10.5,0.6,-21,2.5,-31.5,3.8 c13.4,-27.8,32.5,-49.9,61.8,-61.9c4.9,-2,10.1,-3.1,15.3,-4.1c6.3,-1.2,11.2,2.6,16.3,5.2c5.2,2.6,9.9,6.2,15.1,8.6 c13.3,6,20.3,18,28.7,28.8c12.5,16,24.6,32.2,32.9,50.8C338.3,615.2,341,619.7,341,625z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M91.9,675c-8,-3.8,-13.6,-10.7,-19.7,-16.8c-4.1,-4.1,-6.9,-9.4,-10.3,-14.2c21.3,-27.5,49.8,-44.3,82.3,-54.9 c6.8,-2.2,13.6,-4.3,20.7,-5.1c-5.3,13.4,-10.4,26.9,-12.5,41.2c-2,13.4,-3.2,26.8,-1.7,40.5c1.1,9.6,2.3,19,4.8,28.3 c0.7,2.5,0.1,2.7,-2.4,2.3c-15.2,-2.6,-29.9,-7.1,-44.1,-13.3c-2,-0.9,-3.7,-2.3,-6.1,-2c0,0,0,0,0,0c-0.7,-1.2,-1.9,-1,-3,-1c0,0,0,0,0,0 c-0.3,-2.7,-2.4,-1.8,-4,-2c0,0,0,0,0,0c-0.3,-0.3,-0.7,-0.7,-1,-1c0,0,0,0,0,0c-0.3,-0.3,-0.7,-0.7,-1,-1c0,0,0,0,0,0 C93.6,675.2,92.8,675,91.9,675z" + android:fillColor="#D86868"/> + <path + android:pathData="M135,832.8c1.3,0.1,2.6,0.3,3.9,0.4c0.9,0.8,2,0.7,3.1,0.6c13.1,2.2,26.4,3,39.6,4.1 c4.5,0.3,9,0.2,13.4,-0.5c3.1,0.3,6.3,0.7,9.4,0.8c22.6,0.4,45.2,-0.9,67.6,-4.1c23.9,-3.3,47.4,-8.2,69.8,-17.6 c10.7,-4.5,21.4,-9.3,29.3,-18.3l0,0.1c6.2,-4.6,8.5,-11.8,11.9,-18.2c5.2,4.3,3.3,10.1,2.2,15c-2.2,9.7,-9.6,15.7,-17.4,21 c-17.1,11.7,-36.5,18.1,-56.4,22.9c-19.3,4.7,-38.9,7.4,-58.7,9.3c-21.4,2,-42.8,2.5,-64.2,1.6c-20.3,-0.8,-40.5,-2.8,-60.6,-6.5 c-19,-3.5,-37.6,-8.2,-55.4,-15.4c-11.9,-4.8,-23.4,-10.6,-32.3,-20.2c-5.3,-5.8,-8.9,-12.4,-8.3,-20.6c0.1,-1.2,0,-2.4,1.1,-3.1 c3.3,3.1,4.1,7.8,7.2,11.1c9,9.9,20.2,16.3,32.4,21.4c16.8,7,34.3,11.7,52.3,14.5c0.6,0.1,1.2,0.2,1.9,0.3c0.9,0.8,2,0.7,3.1,0.6 c0.6,0.1,1.3,0.2,1.9,0.3C132.8,833,133.9,833,135,832.8z" + android:fillColor="#999899"/> + <path + android:pathData="M371.9,667c2.8,-3.5,0.4,-7.1,-0.3,-10.4c-5.7,-26.6,-17.7,-50.3,-34.2,-71.7c-0.8,-1,-1.5,-2.2,-2.3,-3.3 c-0.3,-0.5,-0.6,-1.1,-1,-1.9c3.4,3,6.9,5.4,9.6,8.6c10.8,13.1,20.4,27,27.7,42.4c8,16.9,13.1,34.6,15.8,53.1 c1.9,12.9,2.6,25.8,1.7,38.7c-1.7,22.4,-6,44.3,-14.7,65.1c-1.4,3.3,-3.1,6.6,-3,10.4c0,0,0,-0.1,0,-0.1c-1.8,-0.3,-3.3,0.4,-4.7,1.2 c-6.3,3.7,-12.6,7.3,-19.4,10.2c-24,10.3,-48.8,14.5,-74.7,9.2c-4.2,-0.9,-9.4,-0.2,-12.4,-4.8c13.8,-2,27.6,-4.4,41.1,-8 c10,-2.7,20,-5.4,29,-10.8c1.5,-0.5,3.2,-0.9,4.6,-1.6c10.6,-5.1,19.5,-12.1,25.3,-22.6c4.7,-3.1,8.2,-10.7,6.9,-15c0.3,-1.4,0.6,-2.9,1,-4.3 c5.4,-16.2,7.5,-33.1,9,-50C378,689.7,375.5,678.3,371.9,667z" + android:fillColor="#F1F0F0"/> + <path + android:pathData="M371.9,667c3.6,11.3,6.1,22.7,5.1,34.6c-1.5,16.9,-3.6,33.8,-9,50c-0.5,1.4,-0.7,2.9,-1,4.3 c-2.3,5,-4.6,10,-6.9,15c-5.8,10.5,-14.7,17.5,-25.3,22.6c-1.5,0.7,-3.1,1.1,-4.6,1.6c-0.3,-2.1,0.3,-3.9,1.1,-5.7 c3.4,-7.4,6.4,-14.9,8.9,-22.6c6,-18.1,10,-36.5,12,-55.6c1.2,-11.6,0.9,-23.2,0.6,-34.8c-0.2,-6.8,-0.7,-13.8,-2.8,-20.5 c2.4,-4.1,4.7,-8.1,7.1,-12.2c5.6,4.7,8.4,11.3,11.7,17.6C369.8,663.3,370.8,665.2,371.9,667z" + android:fillColor="#E6A3A3"/> + <path + android:pathData="M260,814c2.9,4.6,8.1,3.9,12.4,4.8c25.9,5.3,50.7,1.1,74.7,-9.2c6.7,-2.9,13.1,-6.4,19.4,-10.2 c1.4,-0.9,2.9,-1.6,4.7,-1.2c-7.9,9.1,-18.6,13.8,-29.3,18.3c-22.3,9.4,-45.9,14.3,-69.8,17.6c-22.4,3.1,-45,4.4,-67.6,4.1 c-3.1,-0.1,-6.3,-0.5,-9.4,-0.8c-0.1,-2,-1.4,-2.2,-3,-2.4c-28.3,-3,-56,-8.2,-82.4,-19.1c-13.4,-5.5,-26.5,-11.8,-35.3,-24.1c-1.3,-1.8,-2.4,-3.6,-2.2,-5.9 c15.1,11.6,32.9,16.7,51,21.1c17.7,4.4,35.8,6.6,54,8.3c10,0.9,20,1.1,29.8,1.1c15.7,0.1,31.5,0.4,47.1,-2.4 C256,814,258,814,260,814z" + android:fillColor="#EDECEC"/> + <path + android:pathData="M130,831.9c-1.1,0.1,-2.2,0.2,-3.1,-0.6C128.3,829.5,129.4,829.5,130,831.9z" + android:fillColor="#EDECEC"/> + <path + android:pathData="M135,832.8c-1.1,0.1,-2.2,0.2,-3.1,-0.7C133.4,830.5,134.4,830.6,135,832.8z" + android:fillColor="#EDECEC"/> + <path + android:pathData="M142,833.8c-1.1,0.1,-2.2,0.2,-3.1,-0.6C140.3,831.5,141.4,831.5,142,833.8z" + android:fillColor="#EDECEC"/> + <path + android:pathData="M260,814c-2,0,-4,0,-6,0c-6.8,-3.7,-13.9,-6.8,-20.5,-11c-18,-11.5,-32.7,-26.4,-45.1,-43.6c-11,-15.2,-21,-31,-27.5,-48.8 c-0.9,-2.5,-2,-4.9,-1.9,-7.7c0.7,0,1.4,-0.1,2,0.1c16.2,4.6,33.1,5.3,49.6,5.3c10,0,20.1,-0.2,30.2,-1.3c19.5,-2,38.7,-5.3,57,-12.4 c15.6,-6,30.1,-13.9,41.3,-26.9c4.7,-3.1,7,-8.3,11,-12c2.1,6.7,2.6,13.7,2.8,20.5c0.3,11.6,0.6,23.1,-0.6,34.8c-2,19,-6,37.5,-12,55.6 c-2.6,7.7,-5.5,15.3,-8.9,22.6c-0.9,1.9,-1.5,3.7,-1.1,5.7c-9,5.4,-19,8.1,-29,10.8C287.6,809.6,273.8,811.9,260,814z" + android:fillColor="#E6A3A3"/> + <path + android:pathData="M339,668c-11.1,13,-25.7,20.8,-41.3,26.9c-18.3,7.1,-37.5,10.4,-57,12.4c-10.1,1,-20.3,1.3,-30.2,1.3 c-16.6,0,-33.4,-0.7,-49.6,-5.3c-0.6,-0.2,-1.3,-0.1,-2,-0.1c-0.6,-0.4,-1.3,-0.7,-1.9,-1.1c-0.4,-3.8,0.3,-5,4.8,-4.2c12.1,2,24.3,2.8,36.5,3.4 c32.4,1.7,64.1,-2.3,95.1,-11.6c14.8,-4.5,29,-10.8,41.5,-20.1C336.3,668.5,337.5,667.9,339,668z" + android:fillColor="#FFFFFF"/> + <path + android:pathData="M96,678c1.6,0.2,3.7,-0.7,4,2C98.4,679.8,97,679.3,96,678z" + android:fillColor="#FFFFFF"/> + <path + android:pathData="M100,680c1.1,0,2.3,-0.2,3,1C101.9,681,100.7,681.2,100,680z" + android:fillColor="#FFFFFF"/> + <path + android:pathData="M91.9,675c0.8,0,1.6,0.2,2.1,1C93.2,676,92.4,675.8,91.9,675z" + android:fillColor="#FFFFFF"/> + <path + android:pathData="M94,676c0.3,0.3,0.7,0.7,1,1C94.7,676.7,94.3,676.3,94,676z" + android:fillColor="#FFFFFF"/> + <path + android:pathData="M95,677c0.3,0.3,0.7,0.7,1,1C95.7,677.7,95.3,677.3,95,677z" + android:fillColor="#C5C5C5"/> + <path + android:pathData="M360,771c2.3,-5,4.6,-10,6.9,-15C368.2,760.3,364.7,767.8,360,771z" + android:fillColor="#EDECEC"/> +</vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_action_clear.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_action_clear.xml new file mode 100644 index 000000000..6b12b0d61 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_action_clear.xml @@ -0,0 +1,25 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0" + android:tint="?android:attr/colorControlNormal" > + <path + android:fillColor="@android:color/white" + android:pathData="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_action_open.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_action_open.xml new file mode 100644 index 000000000..96d4ce250 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_action_open.xml @@ -0,0 +1,24 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF737373" + android:pathData="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_advanced_shortcut.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_advanced_shortcut.xml new file mode 100644 index 000000000..23b1be846 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_advanced_shortcut.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@color/shortcut_background" /> + <foreground> + <inset android:inset="33%"> + <vector + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="@color/shortcut_foreground" + android:pathData="M17 1.01L7 1c-1.1 0,-2 .9,-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2,-.9 2,-2V3c0,-1.1,-.9,-1.99,-2,-1.99zM17 19H7V5h10v14z"/> + </vector> + </inset> + </foreground> +</adaptive-icon> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_arrow_back.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_arrow_back.xml new file mode 100644 index 000000000..1a9993033 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_arrow_back.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="?android:colorControlNormal" + android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_arrow_upward.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_arrow_upward.xml new file mode 100644 index 000000000..dbee1c363 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_arrow_upward.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="28dp" + android:height="32dp" + android:viewportHeight="32" + android:viewportWidth="28"> + + <path + android:fillColor="?attr/colorOnSecondaryContainer" + android:pathData="M13.25 19.125V10.75c0-.208.07-.382.208-.52A.74.74 0 0 1 14 10c.208 0 .382.076.52.23.154.138.23.312.23.52v8.375l3.667-3.667a.718.718 0 0 1 .52-.229c.209 0 .39.077.542.23.153.152.23.333.23.541a.718.718 0 0 1-.23.52l-4.958 4.96a.786.786 0 0 1-.25.166.85.85 0 0 1-.271.041c-.097 0-.194-.013-.292-.041a.878.878 0 0 1-.229-.167l-4.958-4.958A.718.718 0 0 1 8.29 16a.822.822 0 0 1 .25-.542.718.718 0 0 1 .521-.229.74.74 0 0 1 .542.23l3.646 3.666Z" /> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_breadcrumb_arrow.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_breadcrumb_arrow.xml new file mode 100644 index 000000000..5305b4ae3 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_breadcrumb_arrow.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:autoMirrored="true" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="?android:attr/colorControlNormal" + android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6 -6,-6z"/> +</vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_briefcase.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_briefcase.xml new file mode 100644 index 000000000..8fc7d4a44 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_briefcase.xml @@ -0,0 +1,25 @@ +<!-- + ~ 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. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="?android:attr/colorAccent" + android:pathData="M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v2L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM12,15c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM14,6h-4L10,4h4v2z"/> +</vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_briefcase_white.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_briefcase_white.xml new file mode 100644 index 000000000..7fb9b3c8a --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_briefcase_white.xml @@ -0,0 +1,25 @@ +<!-- + ~ 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. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="@android:color/white" + android:pathData="M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v2L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM12,15c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM14,6h-4L10,4h4v2z"/> +</vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_cab_cancel.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_cab_cancel.xml new file mode 100644 index 000000000..ded7fd678 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_cab_cancel.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12 19,6.41z"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_check.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_check.xml new file mode 100644 index 000000000..445d9969d --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_check.xml @@ -0,0 +1,25 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0" + android:tint="@color/search_chip_text_selected_color"> + <path + android:fillColor="@android:color/white" + android:pathData="vM9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/> +</vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_check_circle.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_check_circle.xml new file mode 100644 index 000000000..71ad135b1 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_check_circle.xml @@ -0,0 +1,25 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="20dp" + android:height="20dp" + android:viewportWidth="960" + android:viewportHeight="960"> + <path + android:fillColor="?attr/colorOnPrimaryContainer" + android:pathData="M428.28,628.78L669.87,388.2L612.41,330.5L428.28,513.63L346.15,432.5L288.7,490.2L428.28,628.78ZM480,872.13Q399.09,872.13 327.66,841.51Q256.22,810.89 202.66,757.34Q149.11,703.78 118.49,632.34Q87.87,560.91 87.87,480Q87.87,398.09 118.49,327.16Q149.11,256.22 202.66,202.66Q256.22,149.11 327.66,118.49Q399.09,87.87 480,87.87Q561.91,87.87 632.84,118.49Q703.78,149.11 757.34,202.66Q810.89,256.22 841.51,327.16Q872.13,398.09 872.13,480Q872.13,560.91 841.51,632.34Q810.89,703.78 757.34,757.34Q703.78,810.89 632.84,841.51Q561.91,872.13 480,872.13Z"/> +</vector> + diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_chip_from_this_week.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_chip_from_this_week.xml new file mode 100644 index 000000000..dca3b19a0 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_chip_from_this_week.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#5F6368" + android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l4,3.99L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.25,2.52 0.77,-1.28 -3.52,-2.09L13.5,8z"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_chip_large_files.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_chip_large_files.xml new file mode 100644 index 000000000..d0fe55090 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_chip_large_files.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#5F6368" + android:pathData="M21.41,11.58l-9,-9C12.05,2.22 11.55,2 11,2H4c-1.1,0 -2,0.9 -2,2v7c0,0.55 0.22,1.05 0.59,1.42l9,9c0.36,0.36 0.86,0.58 1.41,0.58s1.05,-0.22 1.41,-0.59l7,-7c0.37,-0.36 0.59,-0.86 0.59,-1.41s-0.23,-1.06 -0.59,-1.42zM13,20.01L4,11V4h7v-0.01l9,9 -7,7.02zM8,6.5C8,7.33 7.33,8 6.5,8S5,7.33 5,6.5 5.67,5 6.5,5 8,5.67 8,6.5z"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_create_new_folder.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_create_new_folder.xml new file mode 100644 index 000000000..cdd126a4a --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_create_new_folder.xml @@ -0,0 +1,28 @@ +<!-- + ~ 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. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M12 12h2v-2h2v2h2v2h-2v2h-2v-2h-2v-2zm10-4v10c0 1.1-0.9 2-2 2H4c-1.1 0-2-0.9-2-2l0.01-12c0-1.1 0.89 -2 1.99-2h6l2 2h8c1.1 0 2 0.9 2 2zm-2 0H4v10h16V8z" /> + <path + android:pathData="M0 0h24v24H0V0z" /> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_debug_menu.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_debug_menu.xml new file mode 100644 index 000000000..c0e884b47 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_debug_menu.xml @@ -0,0 +1,24 @@ +<!-- + Copyright 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960"> + <path android:fillColor="?android:attr/colorControlNormal" + android:pathData="M 180 460 C 152 460 128.334 450.333 109 431 C 89.667 411.667 80 388 80 360 C 80 332 89.667 308.333 109 289 C 128.334 269.667 152 260 180 260 C 208 260 231.667 269.667 251 289 C 270.334 308.333 280 332 280 360 C 280 388 270.334 411.667 251 431 C 231.667 450.333 208 460 180 460 Z M 360 300 C 332 300 308.334 290.333 289 271 C 269.667 251.667 260 228 260 200 C 260 172 269.667 148.333 289 129 C 308.334 109.667 332 100 360 100 C 388 100 411.667 109.667 431 129 C 450.334 148.333 460 172 460 200 C 460 228 450.334 251.667 431 271 C 411.667 290.333 388 300 360 300 Z M 600 300 C 572 300 548.334 290.333 529 271 C 509.667 251.667 500 228 500 200 C 500 172 509.667 148.333 529 129 C 548.334 109.667 572 100 600 100 C 628 100 651.667 109.667 671 129 C 690.334 148.333 700 172 700 200 C 700 228 690.334 251.667 671 271 C 651.667 290.333 628 300 600 300 Z M 780 460 C 752 460 728.334 450.333 709 431 C 689.667 411.667 680 388 680 360 C 680 332 689.667 308.333 709 289 C 728.334 269.667 752 260 780 260 C 808 260 831.667 269.667 851 289 C 870.334 308.333 880 332 880 360 C 880 388 870.334 411.667 851 431 C 831.667 450.333 808 460 780 460 Z M 266 860 C 236 860 210.834 848.5 190.5 825.5 C 170.167 802.5 160 775.333 160 744 C 160 709.333 171.834 679 195.5 653 C 219.167 627 242.667 601.333 266 576 C 285.334 555.333 302 532.833 316 508.5 C 330 484.167 346.667 461.333 366 440 C 380.667 422.667 397.667 408.333 417 397 C 436.334 385.667 457.334 380 480 380 C 502.667 380 523.667 385.333 543 396 C 562.334 406.667 579.334 420.667 594 438 C 612.667 459.333 629.167 482.333 643.5 507 C 657.834 531.667 674.667 554.667 694 576 C 717.334 601.333 740.834 627 764.5 653 C 788.167 679 800 709.333 800 744 C 800 775.333 789.834 802.5 769.5 825.5 C 749.167 848.5 724 860 694 860 C 658 860 622.334 857 587 851 C 551.667 845 516 842 480 842 C 444 842 408.334 845 373 851 C 337.667 857 302 860 266 860 Z"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_dialog_alert.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_dialog_alert.xml new file mode 100644 index 000000000..e31cff30a --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_dialog_alert.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="?android:attr/colorControlNormal" + android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_dialog_info.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_dialog_info.xml new file mode 100644 index 000000000..dface66f6 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_dialog_info.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0" + android:tint="?android:attr/colorAccent"> + <path + android:fillColor="?android:attr/colorBackground" + android:pathData="M11 15h2v2h-2v-2zm0-8h2v6h-2V7zm0.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z" /> + <path + android:pathData="M0 0h24v24H0V0z" /> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_done.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_done.xml new file mode 100644 index 000000000..8439cb2a5 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_done.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="?android:colorAccent" + android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z"/> +</vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_drop_copy_badge.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_drop_copy_badge.xml new file mode 100644 index 000000000..370c4fe70 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_drop_copy_badge.xml @@ -0,0 +1,37 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="14dp" + android:height="14dp" + android:viewportWidth="28.0" + android:viewportHeight="28.0"> + + <group + android:name="whiteBg"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M0,15a15,15 0 1,0 30,0a15,15 0 1,0 -30,0" /> + </group> + + <group + android:name="badge" + android:translateX="2" + android:translateY="2"> + <path + android:fillColor="#FF0B8043" + android:pathData="M13,0 C5.824,0 0,5.824 0,13 C0,20.176 5.824,26 13,26 C20.176,26 26,20.176 26,13 C26,5.824 20.176,0 13,0 L13,0 Z M19,14 L14,14 L14,19 L12,19 L12,14 L7,14 L7,12 L12,12 L12,7 L14,7 L14,12 L19,12 L19,14 Z" /> + </group> +</vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_eject.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_eject.xml new file mode 100644 index 000000000..11c8af06f --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_eject.xml @@ -0,0 +1,24 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#5F6368" + android:pathData="M5 17h14v2H5zm7-12L5.33 15h13.34z"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_exit_to_app.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_exit_to_app.xml new file mode 100644 index 000000000..e0ebf7319 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_exit_to_app.xml @@ -0,0 +1,24 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#5F6368" + android:pathData="M10.09 15.59L11.5 17l5-5-5-5-1.41 1.41L12.67 11H3v2h9.67l-2.58 2.59zM19 3H5c-1.11 0-2 .9-2 2v4h2V5h14v14H5v-4H3v4c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/> +</vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_folder_shortcut.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_folder_shortcut.xml new file mode 100644 index 000000000..fb2427a38 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_folder_shortcut.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@color/shortcut_background" /> + <foreground> + <inset android:inset="33%"> + <vector + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="@color/shortcut_foreground" + android:pathData="M10 4H4c-1.1 0,-1.99.9,-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2,-.9 2,-2V8c0,-1.1,-.9,-2,-2,-2h-8l-2,-2z"/> + </vector> + </inset> + </foreground> +</adaptive-icon> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_hamburger.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_hamburger.xml new file mode 100644 index 000000000..1d3990887 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_hamburger.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="?android:attr/colorControlNormal" + android:pathData="M3,18h18v-2H3V18zM3,13h18v-2H3V13zM3,6v2h18V6H3z"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_history.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_history.xml new file mode 100644 index 000000000..516b76daa --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_history.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="?android:textColorSecondary" + android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l4,3.99L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.25,2.52 0.77,-1.28 -3.52,-2.09L13.5,8z"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_images_shortcut.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_images_shortcut.xml new file mode 100644 index 000000000..66de1938c --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_images_shortcut.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@color/shortcut_background" /> + <foreground> + <inset android:inset="33%"> + <vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24" + android:viewportWidth="24"> + <path + android:fillColor="@color/shortcut_foreground" + android:pathData="M21 19V5c0,-1.1,-.9,-2,-2,-2H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5,-4.5z" /> + </vector> + </inset> + </foreground> +</adaptive-icon> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_compress.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_compress.xml new file mode 100644 index 000000000..e88245ec0 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_compress.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> +<path + android:fillColor="?android:attr/colorControlNormal" + android:pathData="M20.54,5.23l-1.39,-1.68C18.88,3.21 18.47,3 18,3H6c-0.47,0 -0.88,0.21 -1.16,0.55L3.46,5.23C3.17,5.57 3,6.02 3,6.5V19c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V6.5c0,-0.48 -0.17,-0.93 -0.46,-1.27zM12,17.5L6.5,12H10v-2h4v2h3.5L12,17.5zM5.12,5l0.81,-1h12l0.94,1H5.12z"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_copy.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_copy.xml new file mode 100644 index 000000000..ea45ba341 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_copy.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="?android:attr/colorControlNormal" + android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM15,5L8,5c-1.1,0 -1.99,0.9 -1.99,2L6,21c0,1.1 0.89,2 1.99,2L19,23c1.1,0 2,-0.9 2,-2L21,11l-6,-6zM8,21L8,7h6v5h5v9L8,21z"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_delete.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_delete.xml new file mode 100644 index 000000000..677fbd25c --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_delete.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="?android:attr/colorControlNormal" + android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_extract.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_extract.xml new file mode 100644 index 000000000..6a48e697c --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_extract.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <group> + <clip-path android:pathData="M0,0h24v24H0V0z M 0,0"/> + <path + android:fillColor="?android:attr/colorControlNormal" + android:pathData="M20.55 5.22l-1.39,-1.68C18.88 3.21 18.47 3 18 3H6c-.47 0,-.88.21,-1.15.55L3.46 5.22C3.17 5.57 3 6.01 3 6.5V19c0 1.1.89 2 2 2h14c1.1 0 2,-.9 2,-2V6.5c0,-.49,-.17,-.93,-.45,-1.28zM12 9.5l5.5 5.5H14v2h-4v-2H6.5L12 9.5zM5.12 5l.82,-1h12l.93 1H5.12z"/> + </group> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_search.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_search.xml new file mode 100644 index 000000000..6d896b75d --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_search.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="?android:attr/colorControlNormal" + android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_share.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_share.xml new file mode 100644 index 000000000..78fae8ed1 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_share.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="?android:attr/colorControlNormal" + android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_view_grid.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_view_grid.xml new file mode 100644 index 000000000..9818c4c4a --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_view_grid.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="?android:attr/colorControlNormal" + android:pathData="M4,5v13h17L21,5L4,5zM14,7v3.5h-3L11,7h3zM6,7h3v3.5L6,10.5L6,7zM6,16v-3.5h3L9,16L6,16zM11,16v-3.5h3L14,16h-3zM19,16h-3v-3.5h3L19,16zM16,10.5L16,7h3v3.5h-3z"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_view_list.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_view_list.xml new file mode 100644 index 000000000..81bdd5e85 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_menu_view_list.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="?android:attr/colorControlNormal" + android:pathData="M3,5v14h17L20,5L3,5zM7,7v2L5,9L5,7h2zM5,13v-2h2v2L5,13zM5,15h2v2L5,17v-2zM18,17L9,17v-2h9v2zM18,13L9,13v-2h9v2zM18,9L9,9L9,7h9v2z"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_reject_drop_badge.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_reject_drop_badge.xml new file mode 100644 index 000000000..06db34617 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_reject_drop_badge.xml @@ -0,0 +1,38 @@ +<!-- +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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="14dp" + android:height="14dp" + android:viewportWidth="28.0" + android:viewportHeight="28.0"> + + <group + android:name="whiteBg"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M0,15a15,15 0 1,0 30,0a15,15 0 1,0 -30,0" /> + </group> + + <group + android:name="badge" + android:translateX="2" + android:translateY="2"> + <path + android:fillColor="#FFC53929" + android:pathData="M3.8056487,3.8056487 C-1.26854957,8.87984696 -1.26854957,17.1162267 3.8056487,22.190425 C8.87984696,27.2646233 17.1162267,27.2646233 22.190425,22.190425 C27.2646233,17.1162267 27.2646233,8.87984696 22.190425,3.8056487 C17.1162267,-1.26854957 8.87984696,-1.26854957 3.8056487,3.8056487 L3.8056487,3.8056487 Z M16.5335708,17.9477843 L12.9980369,14.4122504 L9.46250295,17.9477843 L8.04828938,16.5335708 L11.5838233,12.9980369 L8.04828938,9.46250295 L9.46250295,8.04828938 L12.9980369,11.5838233 L16.5335708,8.04828938 L17.9477843,9.46250295 L14.4122504,12.9980369 L17.9477843,16.5335708 L16.5335708,17.9477843 L16.5335708,17.9477843 Z" /> + </group> +</vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_root_bugreport.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_root_bugreport.xml new file mode 100644 index 000000000..20517f951 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_root_bugreport.xml @@ -0,0 +1,25 @@ +<!-- + ~ 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. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#5F6368" + android:pathData="M20 10V8h-2.81c-.45-.78-1.07-1.46-1.82-1.96L17 4.41 15.59 3l-2.17 2.17c-.03-.01-.05-.01-.08-.01-.16-.04-.32-.06-.49-.09l-.17-.03C12.46 5.02 12.23 5 12 5c-.49 0-.97.07-1.42.18l.02-.01L8.41 3 7 4.41l1.62 1.63h.01c-.75.5-1.37 1.18-1.82 1.96H4v2h2.09c-.06.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20zm-4 5c0 2.21-1.79 4-4 4s-4-1.79-4-4v-4c0-2.21 1.79-4 4-4s4 1.79 4 4v4zm-6-1h4v2h-4zm0-4h4v2h-4z" /> +</vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_root_download.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_root_download.xml new file mode 100644 index 000000000..caea0922f --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_root_download.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24" + android:viewportWidth="24"> + <path + android:fillColor="#5F6368" + android:pathData="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z" /> +</vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_root_recent.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_root_recent.xml new file mode 100644 index 000000000..fc26692c7 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_root_recent.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + + <path + android:fillColor="#5F6368" + android:pathData="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 +11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z" /> + + <path + android:fillColor="#5F6368" + android:pathData="M12.5 7H11v6l5.25 3.15 .75 -1.23-4.5-2.67z" /> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_root_smartphone.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_root_smartphone.xml new file mode 100644 index 000000000..01af619a0 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_root_smartphone.xml @@ -0,0 +1,24 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#5F6368" + android:pathData="M17 1.01L7 1c-1.1 0,-2 .9,-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2,-.9 2,-2V3c0,-1.1,-.9,-1.99,-2,-1.99zM17 19H7V5h10v14z"/> +</vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_sd_storage.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_sd_storage.xml new file mode 100644 index 000000000..bd54eb31b --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_sd_storage.xml @@ -0,0 +1,24 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#5F6368" + android:pathData="M18 2h-8L4.02 8 4 20c0 1.1.9 2 2 2h12c1.1 0 2,-.9 2,-2V4c0,-1.1,-.9,-2,-2,-2zm-6 6h-2V4h2v4zm3 0h-2V4h2v4zm3 0h-2V4h2v4z"/> +</vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_sort.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_sort.xml new file mode 100644 index 000000000..a64bb9ef1 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_sort.xml @@ -0,0 +1,26 @@ +<!-- + ~ 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. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M3,18h6v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h12v-2L3,11v2z"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_sort_arrow.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_sort_arrow.xml new file mode 100644 index 000000000..ec23152ab --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_sort_arrow.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. + --> + +<rotate xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/ic_sort_icon" + android:fromDegrees="0" + android:toDegrees="180" + android:pivotX="50%" + android:pivotY="50%"/> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_sort_icon.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_sort_icon.xml new file mode 100644 index 000000000..52a265729 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_sort_icon.xml @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. + --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:state_focused="true" + android:state_hovered="true"> + <layer-list> + <item> + <shape + android:background="?attr/colorSurfaceBright" + android:shape="rectangle" + android:tint="?attr/colorSecondaryContainer" + android:tintMode="multiply"> + <corners android:radius="14dp" /> + <size + android:width="28dp" + android:height="32dp" /> + <solid android:color="?attr/colorSecondaryContainer" /> + <stroke + android:width="@dimen/focus_ring_width" + android:color="?attr/colorSecondary" /> + </shape> + </item> + <item android:drawable="@drawable/ic_arrow_upward" /> + </layer-list> + </item> + <item + android:state_focused="false" + android:state_hovered="true"> + <layer-list> + <item> + <shape + android:background="?attr/colorSurfaceBright" + android:shape="rectangle" + android:tint="?attr/colorSecondaryContainer" + android:tintMode="multiply"> + <corners android:radius="14dp" /> + <size + android:width="28dp" + android:height="32dp" /> + <solid android:color="?attr/colorSecondaryContainer" /> + </shape> + </item> + <item android:drawable="@drawable/ic_arrow_upward" /> + </layer-list> + </item> + <item + android:state_focused="true" + android:state_hovered="false"> + <layer-list> + <item> + <shape + android:background="?attr/colorSurfaceBright" + android:shape="rectangle"> + <corners android:radius="14dp" /> + <size + android:width="28dp" + android:height="32dp" /> + <solid android:color="?attr/colorSecondaryContainer" /> + <stroke + android:width="@dimen/focus_ring_width" + android:color="?attr/colorSecondary" /> + </shape> + </item> + <item android:drawable="@drawable/ic_arrow_upward" /> + </layer-list> + </item> + <item> + <layer-list> + <item> + <shape + android:background="?attr/colorSurfaceBright" + android:shape="rectangle"> + <corners android:radius="14dp" /> + <size + android:width="28dp" + android:height="32dp" /> + <solid android:color="?attr/colorSecondaryContainer" /> + </shape> + </item> + <item android:drawable="@drawable/ic_arrow_upward" /> + </layer-list> + </item> +</selector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_subdirectory_arrow.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_subdirectory_arrow.xml new file mode 100644 index 000000000..684565bf0 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_subdirectory_arrow.xml @@ -0,0 +1,24 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="?android:textColorSecondary" + android:pathData="M19 15l-6 6,-1.42,-1.42L15.17 16H4V4h2v10h9.17l-3.59,-3.58L13 9l6 6z"/> +</vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_usb_shortcut.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_usb_shortcut.xml new file mode 100644 index 000000000..6e53700f9 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_usb_shortcut.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@color/shortcut_background" /> + <foreground> + <inset android:inset="33%"> + <vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="24" + android:viewportWidth="24"> + <path + android:fillColor="@color/shortcut_foreground" + android:pathData="M15 7v4h1v2h-3V5h2l-3,-4,-3 4h2v8H8v-2.07c.7,-.37 1.2,-1.08 1.2,-1.93 0,-1.21,-.99,-2.2,-2.2,-2.2,-1.21 0,-2.2.99,-2.2 2.2 0 .85.5 1.56 1.2 1.93V13c0 1.11.89 2 2 2h3v3.05c-.71.37,-1.2 1.1,-1.2 1.95 0 1.22.99 2.2 2.2 2.2 1.21 0 2.2,-.98 2.2,-2.2 0,-.85,-.49,-1.58,-1.2,-1.95V15h3c1.11 0 2,-.89 2,-2v-2h1V7h-4z"/> + </vector> + </inset> + </foreground> +</adaptive-icon> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_usb_storage.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_usb_storage.xml new file mode 100644 index 000000000..6dde75108 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_usb_storage.xml @@ -0,0 +1,24 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="?android:textColorSecondary" + android:pathData="M15 7v4h1v2h-3V5h2l-3,-4,-3 4h2v8H8v-2.07c.7,-.37 1.2,-1.08 1.2,-1.93 0,-1.21,-.99,-2.2,-2.2,-2.2,-1.21 0,-2.2.99,-2.2 2.2 0 .85.5 1.56 1.2 1.93V13c0 1.11.89 2 2 2h3v3.05c-.71.37,-1.2 1.1,-1.2 1.95 0 1.22.99 2.2 2.2 2.2 1.21 0 2.2,-.98 2.2,-2.2 0,-.85,-.49,-1.58,-1.2,-1.95V15h3c1.11 0 2,-.89 2,-2v-2h1V7h-4z"/> +</vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_user_profile.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_user_profile.xml new file mode 100644 index 000000000..42e06a59e --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_user_profile.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm6.36 14.83c-1.43-1.74-4.9-2.33-6.36-2.33s-4.93.59-6.36 2.33C4.62 15.49 4 13.82 4 12c0-4.41 3.59-8 8-8s8 3.59 8 8c0 1.82-.62 3.49-1.64 4.83zM12 6c-1.94 0-3.5 1.56-3.5 3.5S10.06 13 12 13s3.5-1.56 3.5-3.5S13.94 6 12 6z" + android:fillColor="#4285F4"/> +</vector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_zoom_out.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_zoom_out.xml new file mode 100644 index 000000000..c986d6579 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_zoom_out.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="@android:color/white" + android:pathData="M15,3l2.3,2.3 -2.89,2.87 1.42,1.42L18.7,6.7 21,9L21,3zM3,9l2.3,-2.3 2.87,2.89 1.42,-1.42L6.7,5.3 9,3L3,3zM9,21l-2.3,-2.3 2.89,-2.87 -1.42,-1.42L5.3,17.3 3,15v6zM21,15l-2.3,2.3 -2.87,-2.89 -1.42,1.42 2.89,2.87L15,21h6z"/> +</vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/inspector_separator.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/inspector_separator.xml new file mode 100644 index 000000000..fcfd61f1d --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/inspector_separator.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<inset xmlns:android="http://schemas.android.com/apk/res/android" + android:insetTop="10dp" + android:insetBottom="10dp" > + <shape xmlns:android="http://schemas.android.com/apk/res/android" + android:tint="?android:attr/colorForeground"> + <size android:height="1dp"/> + <solid android:color="#1f000000"/> + </shape> +</inset>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/item_doc_grid_border.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/item_doc_grid_border.xml new file mode 100644 index 000000000..411085500 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/item_doc_grid_border.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- 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. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <stroke + android:width="2dp" + android:color="@color/item_doc_grid_border"/> +</shape> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/item_doc_grid_border_rounded.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/item_doc_grid_border_rounded.xml new file mode 100644 index 000000000..249bda702 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/item_doc_grid_border_rounded.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- 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. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <stroke + android:width="2dp" + android:color="@color/item_doc_grid_border"/> + <corners android:radius="@dimen/grid_item_radius"/> +</shape> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/launcher_screen.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/launcher_screen.xml new file mode 100644 index 000000000..c0d814632 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/launcher_screen.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > + <item android:drawable="@android:color/white"/> + + <item + android:drawable="@drawable/splash_screen" + android:height="150dp" + android:width="150dp" + android:gravity="center"/> + +</layer-list> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/launcher_screen_night.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/launcher_screen_night.xml new file mode 100644 index 000000000..983c4977d --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/launcher_screen_night.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > + <item android:drawable="@color/app_background_color"/> + + <item + android:drawable="@drawable/splash_screen" + android:height="150dp" + android:width="150dp" + android:gravity="center"/> + +</layer-list> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/list_checker.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/list_checker.xml new file mode 100644 index 000000000..c3371b71a --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/list_checker.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:state_checked="true" + android:drawable="@drawable/ic_done"/> + <item + android:drawable="@android:color/transparent"/> +</selector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/list_divider.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/list_divider.xml new file mode 100644 index 000000000..ea48565c1 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/list_divider.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:tint="?android:attr/colorForeground"> + <solid android:color="@color/list_divider_color" /> + <size + android:height="1dp" + android:width="1dp" /> +</shape>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/list_item_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/list_item_background.xml new file mode 100644 index 000000000..797685ce6 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/list_item_background.xml @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- Use @color/list_item_selected_background_color instead of the "?attr/colorPrimary" + because the variable is exposed in overlayable.xml. --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- selected --> + <item android:state_selected="true" android:state_drag_hovered="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/list_item_height" /> + <solid android:color="@color/list_item_selected_background_color" /> + </shape> + </item> + <item> + <shape android:tint="?attr/colorOnPrimary"> + <corners android:radius="@dimen/list_item_height" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + </layer-list> + </item> + <item android:state_selected="true" android:state_focused="true"> + <layer-list> + <item + android:bottom="@dimen/focus_ring_gap" + android:left="@dimen/focus_ring_gap" + android:right="@dimen/focus_ring_gap" + android:top="@dimen/focus_ring_gap"> + <shape> + <corners android:radius="@dimen/list_item_height" /> + <solid android:color="@color/list_item_selected_background_color" /> + </shape> + </item> + <item> + <shape> + <corners android:radius="@dimen/list_item_height" /> + <stroke + android:width="@dimen/focus_ring_width" + android:color="?attr/colorSecondary" /> + </shape> + </item> + </layer-list> + </item> + <item android:state_selected="true" android:state_hovered="true"> + <shape> + <corners android:radius="@dimen/list_item_height" /> + <solid android:color="@color/list_item_selected_background_color" /> + </shape> + </item> + <item android:state_selected="true"> + <shape> + <corners android:radius="@dimen/list_item_height" /> + <solid android:color="@color/list_item_selected_background_color" /> + </shape> + </item> + + <!-- unselected --> + <item android:state_drag_hovered="true"> + <shape android:tint="?attr/colorOnSurface"> + <corners android:radius="@dimen/list_item_height" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + <item android:state_focused="true"> + <shape> + <corners android:radius="@dimen/list_item_height" /> + <stroke + android:width="@dimen/focus_ring_width" + android:color="?attr/colorSecondary" /> + </shape> + </item> + <item android:state_hovered="true"> + <color android:color="@android:color/transparent"/> + </item> + <item> + <color android:color="?attr/colorSurfaceBright"/> + </item> +</selector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/main_container_bottom_section_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/main_container_bottom_section_background.xml new file mode 100644 index 000000000..04f425e16 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/main_container_bottom_section_background.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="?attr/colorSurfaceBright" /> + <corners + android:topLeftRadius="@dimen/main_container_corner_radius_small" + android:topRightRadius="@dimen/main_container_corner_radius_small" + android:bottomLeftRadius="@dimen/main_container_corner_radius_large" + android:bottomRightRadius="@dimen/main_container_corner_radius_large" /> +</shape>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/main_container_middle_section_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/main_container_middle_section_background.xml new file mode 100644 index 000000000..8b0b42bee --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/main_container_middle_section_background.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="?attr/colorSurfaceBright" /> + <corners android:radius="@dimen/main_container_corner_radius_small" /> +</shape>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/main_container_top_section_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/main_container_top_section_background.xml new file mode 100644 index 000000000..b35ed4060 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/main_container_top_section_background.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="?attr/colorSurfaceBright" /> + <corners + android:topLeftRadius="@dimen/main_container_corner_radius_large" + android:topRightRadius="@dimen/main_container_corner_radius_large" + android:bottomLeftRadius="@dimen/main_container_corner_radius_small" + android:bottomRightRadius="@dimen/main_container_corner_radius_small" /> +</shape>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/menu_dropdown_panel.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/menu_dropdown_panel.xml new file mode 100644 index 000000000..43dd62e2c --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/menu_dropdown_panel.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > + <!-- Panel shadow --> + <item> + <shape + xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle" + android:tint="?android:attr/colorBackgroundFloating"> + <stroke android:width="2dp" android:color="#3C4043" /> + <solid android:color="#5F6368" /> + <corners + android:topRightRadius="@dimen/material_round_radius" + android:topLeftRadius="@dimen/material_round_radius" + android:bottomRightRadius="@dimen/material_round_radius" + android:bottomLeftRadius="@dimen/material_round_radius"/> + </shape> + </item> + <!-- Panel surface --> + <item android:bottom="2dp"> + <shape + xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle" + android:tint="?android:attr/colorBackgroundFloating"> + <corners + android:topRightRadius="@dimen/material_round_radius" + android:topLeftRadius="@dimen/material_round_radius" + android:bottomRightRadius="@dimen/material_round_radius" + android:bottomLeftRadius="@dimen/material_round_radius"/> + </shape> + </item> +</layer-list> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_background.xml new file mode 100644 index 000000000..7809766cd --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_background.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- By default the nav rail item has a grey background when it's focused, but we need the + background to be put on the icon inside, so we override the focus background color to be + transparent here. + --> + <item android:state_focused="true" android:drawable="@android:color/transparent" /> +</selector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_icon_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_icon_background.xml new file mode 100644 index 000000000..1c7bc8c0b --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_icon_background.xml @@ -0,0 +1,145 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<ripple + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:color="@color/item_root_ripple_color"> + + <!-- The mask below only works for the ripple itself, doesn't work for other <item>s, we + need to explicitly apply the drawable if the other items also need this mask. --> + <item + android:id="@android:id/mask" + android:drawable="@drawable/nav_rail_item_icon_mask"/> + + <item> + <selector> + <!-- Selected (activated). --> + <!-- Highlight: when dragging files over the item. --> + <item + android:state_activated="true" + app:state_highlighted="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="?attr/colorSecondaryContainer" /> + </shape> + </item> + <item> + <shape android:tint="?attr/colorOnSecondaryContainer"> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + </layer-list> + </item> + <item + android:state_activated="true" + android:state_pressed="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="?attr/colorSecondaryContainer" /> + </shape> + </item> + <item> + <shape android:tint="?attr/colorOnSecondaryContainer"> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + </layer-list> + </item> + <item + android:state_activated="true" + android:state_focused="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="?attr/colorSecondaryContainer" /> + </shape> + </item> + <item> + <shape> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <stroke + android:width="@dimen/focus_ring_width" + android:color="?attr/colorSecondary" /> + </shape> + </item> + </layer-list> + </item> + <item + android:state_activated="true" + android:state_hovered="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="?attr/colorSecondaryContainer" /> + </shape> + </item> + <item> + <shape android:tint="?attr/colorOnSecondaryContainer"> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + </layer-list> + </item> + <item android:state_activated="true"> + <shape> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="?attr/colorSecondaryContainer" /> + </shape> + </item> + + <!-- Unselected. --> + <item app:state_highlighted="true"> + <shape android:tint="?attr/colorOnSurface"> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + <item android:state_pressed="true"> + <shape android:tint="?attr/colorOnSurface"> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + <item android:state_focused="true"> + <shape> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <stroke + android:width="@dimen/focus_ring_width" + android:color="?attr/colorSecondary" /> + </shape> + </item> + <item android:state_hovered="true"> + <shape android:tint="?attr/colorOnSurface"> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + + <!-- Default: use the container background. --> + <item android:drawable="@android:color/transparent" /> + </selector> + </item> +</ripple>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_icon_mask.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_icon_mask.xml new file mode 100644 index 000000000..fd2a14b8d --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_icon_mask.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius"/> + <!-- The color here doesn't matter, it's just being used as a mask. --> + <solid android:color="@android:color/white" /> +</shape>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/profile_tab_mask.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/profile_tab_mask.xml new file mode 100644 index 000000000..3c1e33b0e --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/profile_tab_mask.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <corners android:radius="@dimen/profile_tab_radius"/> + <!-- The color here doesn't matter, it's just being used as a mask in tab_border_rounded. --> + <solid android:color="@android:color/white"/> +</shape> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/progress_indeterminate_horizontal_material_trimmed.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/progress_indeterminate_horizontal_material_trimmed.xml new file mode 100644 index 000000000..68782024b --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/progress_indeterminate_horizontal_material_trimmed.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- TODO(b/379776735): remove this file after M3 uplift --> +<!-- Variant of progress_indeterminate_horizontal_material in frameworks/base/core/res, which + draws the whole height of the progress bar instead having blank space above and below the + bar. --> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/vector_drawable_progress_indeterminate_horizontal_trimmed" > + <target + android:name="rect2_grp" + android:animation="@anim/progress_indeterminate_horizontal_rect2" /> + <target + android:name="rect1_grp" + android:animation="@anim/progress_indeterminate_horizontal_rect1" /> +</animated-vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/root_item_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/root_item_background.xml new file mode 100644 index 000000000..236b92179 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/root_item_background.xml @@ -0,0 +1,129 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<ripple + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:color="@color/item_root_ripple_color"> + + <!-- The mask below only works for the ripple itself, doesn't work for other <item>s, we + need to explicitly apply the drawable if the other items also need this mask. --> + <item + android:id="@android:id/mask" + android:drawable="@drawable/root_list_selector"/> + + <item> + <selector> + <!-- Selected (activated). --> + <!-- Highlight: when dragging files over the item. --> + <item android:state_activated="true" app:state_highlighted="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/drawer_item_height"/> + <solid android:color="?attr/colorSecondaryContainer"/> + </shape> + </item> + <item> + <shape android:tint="?attr/colorOnSecondaryContainer"> + <corners android:radius="@dimen/drawer_item_height"/> + <solid android:color="@color/overlay_hover_color_percentage"/> + </shape> + </item> + </layer-list> + </item> + <item android:state_activated="true" android:state_pressed="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/drawer_item_height"/> + <solid android:color="?attr/colorSecondaryContainer"/> + </shape> + </item> + <item> + <shape android:tint="?attr/colorOnSecondaryContainer"> + <corners android:radius="@dimen/drawer_item_height"/> + <solid android:color="@color/overlay_hover_color_percentage"/> + </shape> + </item> + </layer-list> + </item> + <item android:state_activated="true" android:state_focused="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/drawer_item_height"/> + <solid android:color="?attr/colorSecondaryContainer"/> + </shape> + </item> + <item> + <shape> + <corners android:radius="@dimen/drawer_item_height"/> + <stroke android:width="@dimen/focus_ring_width" android:color="?attr/colorSecondary"/> + </shape> + </item> + </layer-list> + </item> + <item android:state_activated="true" android:state_hovered="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/drawer_item_height"/> + <solid android:color="?attr/colorSecondaryContainer"/> + </shape> + </item> + <item> + <shape android:tint="?attr/colorOnSecondaryContainer"> + <corners android:radius="@dimen/drawer_item_height"/> + <solid android:color="@color/overlay_hover_color_percentage"/> + </shape> + </item> + </layer-list> + </item> + <item android:state_activated="true" android:drawable="@drawable/root_list_selector"/> + + <!-- Unselected. --> + <item app:state_highlighted="true"> + <shape android:tint="?attr/colorOnSurface"> + <corners android:radius="@dimen/drawer_item_height"/> + <solid android:color="@color/overlay_hover_color_percentage"/> + </shape> + </item> + <item android:state_pressed="true"> + <shape android:tint="?attr/colorOnSurface"> + <corners android:radius="@dimen/drawer_item_height"/> + <solid android:color="@color/overlay_hover_color_percentage"/> + </shape> + </item> + <item android:state_focused="true"> + <shape> + <corners android:radius="@dimen/drawer_item_height"/> + <stroke android:width="@dimen/focus_ring_width" android:color="?attr/colorSecondary"/> + </shape> + </item> + <item android:state_hovered="true"> + <shape android:tint="?attr/colorOnSurface"> + <corners android:radius="@dimen/drawer_item_height"/> + <solid android:color="@color/overlay_hover_color_percentage"/> + </shape> + </item> + + <!-- Default: use the container background. --> + <item + android:drawable="@android:color/transparent"/> + </selector> + </item> +</ripple>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/root_list_selector.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/root_list_selector.xml new file mode 100644 index 000000000..5bb3d6afe --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/root_list_selector.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <corners android:radius="@dimen/drawer_item_height"/> + <!-- The color here is used as activated color in root_item_background.xml. --> + <solid android:color="?attr/colorSecondaryContainer"/> +</shape>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/search_bar_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/search_bar_background.xml new file mode 100644 index 000000000..8ad306c06 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/search_bar_background.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <shape android:shape="rectangle"> + <solid android:color="@android:color/transparent"/> + </shape> + </item> + <item + android:start="@dimen/search_bar_background_margin_start" + android:end="@dimen/search_bar_background_margin_end"> + <shape android:shape="rectangle"> + <solid android:color="?android:attr/colorBackgroundFloating"/> + <corners android:radius="@dimen/search_bar_radius"/> + </shape> + </item> +</layer-list>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/share_off.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/share_off.xml new file mode 100644 index 000000000..e5c0f95ae --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/share_off.xml @@ -0,0 +1,26 @@ +<!-- + ~ 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. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M19.7225,20.9245L21.2011,22.4031L22.4032,21.201L2.8022,1.6L1.6001,2.8021L8.1265,9.3284L7.64,9.612C7.1,9.112 6.39,8.802 5.6,8.802C3.94,8.802 2.6,10.142 2.6,11.802C2.6,13.462 3.94,14.802 5.6,14.802C6.39,14.802 7.1,14.492 7.64,13.992L14.69,18.112C14.64,18.332 14.6,18.562 14.6,18.802C14.6,20.462 15.94,21.802 17.6,21.802C18.43,21.802 19.18,21.467 19.7225,20.9245ZM16.8938,18.0958L18.3063,19.5083C18.125,19.6895 17.875,19.802 17.6,19.802C17.05,19.802 16.6,19.352 16.6,18.802C16.6,18.527 16.7125,18.277 16.8938,18.0958ZM15.1871,16.3891L9.3881,10.5901L8.51,11.102C8.56,11.332 8.6,11.562 8.6,11.802C8.6,12.042 8.56,12.272 8.51,12.502L15.1871,16.3891ZM15.56,6.992L12.4382,8.8119L11.1766,7.5503L14.69,5.502C14.64,5.282 14.6,5.042 14.6,4.802C14.6,3.142 15.94,1.802 17.6,1.802C19.26,1.802 20.6,3.142 20.6,4.802C20.6,6.462 19.26,7.802 17.6,7.802C16.81,7.802 16.09,7.492 15.56,6.992ZM18.6,4.802C18.6,4.252 18.15,3.802 17.6,3.802C17.05,3.802 16.6,4.252 16.6,4.802C16.6,5.352 17.05,5.802 17.6,5.802C18.15,5.802 18.6,5.352 18.6,4.802ZM5.6,12.802C5.05,12.802 4.6,12.352 4.6,11.802C4.6,11.252 5.05,10.802 5.6,10.802C6.15,10.802 6.6,11.252 6.6,11.802C6.6,12.352 6.15,12.802 5.6,12.802Z" + android:fillType="evenOdd" + android:fillColor="@color/error_image_color"/> +</vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/sort_widget_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/sort_widget_background.xml new file mode 100644 index 000000000..5a9022035 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/sort_widget_background.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. + --> + +<!-- TODO(b/379776735): remove this file after M3 uplift --> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:top="-1dp" + android:left="-1dp" + android:right="-1dp" + android:bottom="0dp"> + <shape android:shape="rectangle"> + <stroke + android:width="1dp" + android:color="#1f000000" /> + </shape> + </item> +</layer-list> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/splash_screen.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/splash_screen.xml new file mode 100644 index 000000000..3f0c48b6b --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/splash_screen.xml @@ -0,0 +1,64 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,12m-11,0a11,11 0,1 1,22 0a11,11 0,1 1,-22 0" + android:fillColor="#4285F4"/> + <path + android:pathData="M23,12c0,6.1 -4.9,11 -11,11S1,18.1 1,12c0,0 0,0 0,-0.1c0,6 4.9,10.9 11,10.9S23,18 23,12C23,12 23,12 23,12z" + android:strokeAlpha="0.2" + android:fillColor="#263238" + android:fillAlpha="0.2"/> + <path + android:pathData="M23,12C23,12 23,12 23,12c0,-6 -4.9,-10.9 -11,-10.9S1,6 1,12.1c0,0 0,0 0,-0.1C1,5.9 5.9,1 12,1S23,5.9 23,12z" + android:strokeAlpha="0.2" + android:fillColor="#FFFFFF" + android:fillAlpha="0.2"/> + <path + android:pathData="M22.8,14.2c-1,4.8 -5,8.4 -9.9,8.8l-6.4,-6.4L17.6,9C17.6,9 22.8,14.2 22.8,14.2z" + android:fillColor="#4285F4"/> + <path + android:pathData="M22.8,14.2c-1,4.8 -5,8.4 -9.9,8.8l-6.4,-6.4L17.6,9C17.6,9 22.8,14.2 22.8,14.2z"> + <aapt:attr name="android:fillColor"> + <gradient + android:startY="12.203438" + android:startX="11.452812" + android:endY="20.219812" + android:endX="19.469187" + android:type="linear"> + <item android:offset="0" android:color="#33263238"/> + <item android:offset="1" android:color="#05263238"/> + </gradient> + </aapt:attr> + </path> + <path + android:pathData="M16.5,8.5H12L10.8,7H7.5C6.7,7 6,7.7 6,8.5v7C6,16.3 6.7,17 7.5,17h9c0.8,0 1.5,-0.7 1.5,-1.5V10C18,9.2 17.3,8.5 16.5,8.5z" + android:fillColor="#F5F5F5"/> + <path + android:pathData="M18,10v0.1c0,-0.8 -0.7,-1.5 -1.5,-1.5H12l-1.2,-1.5H7.5C6.7,7.1 6,7.8 6,8.6V8.5C6,7.7 6.7,7 7.5,7h3.2L12,8.5h4.5C17.3,8.5 18,9.2 18,10z" + android:strokeAlpha="0.4" + android:fillColor="#FFFFFF" + android:fillAlpha="0.4"/> + <path + android:pathData="M18,15.5v0.1c0,0.8 -0.7,1.5 -1.5,1.5h-9c-0.8,0 -1.5,-0.7 -1.5,-1.5v-0.1C6,16.3 6.7,17 7.5,17h9C17.3,17 18,16.3 18,15.5z" + android:strokeAlpha="0.2" + android:fillColor="#263238" + android:fillAlpha="0.2"/> + <path + android:pathData="M12,12m-11,0a11,11 0,1 1,22 0a11,11 0,1 1,-22 0" + android:fillAlpha="0.1"> + <aapt:attr name="android:fillColor"> + <gradient + android:gradientRadius="22.333876" + android:centerX="3.238875" + android:centerY="5.0445" + android:type="radial"> + <item android:offset="0" android:color="#FFFFFFFF"/> + <item android:offset="1" android:color="#00FFFFFF"/> + </gradient> + </aapt:attr> + </path> +</vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/tab_border_rounded.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/tab_border_rounded.xml new file mode 100644 index 000000000..08d515301 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/tab_border_rounded.xml @@ -0,0 +1,148 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- 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. +--> + +<ripple + xmlns:android="http://schemas.android.com/apk/res/android" + android:color="@color/profile_tab_ripple_color"> + + <!-- The mask below only works for the ripple itself, doesn't work for other <item>s, we + need to explicitly apply the drawable if the other items also need this mask. --> + <item + android:id="@android:id/mask" + android:drawable="@drawable/profile_tab_mask"/> + + <item> + <selector> + <!-- Selected (activated). --> + <item android:state_activated="true" android:state_pressed="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/profile_tab_radius" /> + <solid android:color="?attr/colorPrimaryContainer" /> + </shape> + </item> + <item> + <shape android:tint="?attr/colorOnPrimaryContainer"> + <corners android:radius="@dimen/profile_tab_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + </layer-list> + </item> + <item android:state_activated="true" android:state_focused="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/profile_tab_radius" /> + <solid android:color="?attr/colorPrimaryContainer" /> + </shape> + </item> + <item> + <shape> + <corners android:radius="@dimen/profile_tab_radius" /> + <stroke + android:width="@dimen/focus_ring_width" + android:color="?attr/colorSecondary" /> + </shape> + </item> + </layer-list> + </item> + <item android:state_activated="true" android:state_hovered="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/profile_tab_radius" /> + <solid android:color="?attr/colorPrimaryContainer" /> + </shape> + </item> + <item> + <shape android:tint="?attr/colorOnPrimaryContainer"> + <corners android:radius="@dimen/profile_tab_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + </layer-list> + </item> + <item android:state_activated="true"> + <shape> + <corners android:radius="@dimen/profile_tab_radius" /> + <solid android:color="?attr/colorPrimaryContainer" /> + </shape> + </item> + + <!-- Unselected. --> + <item android:state_pressed="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/profile_tab_radius" /> + <solid android:color="?attr/colorSurfaceContainerHighest" /> + </shape> + </item> + <item> + <shape android:tint="?attr/colorOnSurface"> + <corners android:radius="@dimen/profile_tab_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + </layer-list> + </item> + <item android:state_focused="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/profile_tab_radius" /> + <solid android:color="?attr/colorSurfaceContainerHighest" /> + </shape> + </item> + <item> + <shape> + <corners android:radius="@dimen/profile_tab_radius" /> + <stroke + android:width="@dimen/focus_ring_width" + android:color="?attr/colorSecondary" /> + </shape> + </item> + </layer-list> + </item> + <item android:state_hovered="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/profile_tab_radius" /> + <solid android:color="?attr/colorSurfaceContainerHighest" /> + </shape> + </item> + <item> + <shape android:tint="?attr/colorOnSurface"> + <corners android:radius="@dimen/profile_tab_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + </layer-list> + </item> + + <!-- Default --> + <item> + <shape> + <corners android:radius="@dimen/profile_tab_radius" /> + <solid android:color="?attr/colorSurfaceContainerHighest" /> + </shape> + </item> + </selector> + </item> +</ripple> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml new file mode 100644 index 000000000..c8d899ff7 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- Variant of vector_drawable_progress_indeterminate_horizontal in frameworks/base/core/res, which + draws the whole height of the progress bar instead having blank space above and below the + bar. --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="10dp" + android:width="360dp" + android:viewportHeight="10" + android:viewportWidth="360" > + <group + android:name="progress_group" + android:translateX="180" + android:translateY="5" > + <path + android:name="background_track" + android:pathData="M -180.0,-5.0 l 360.0,0 l 0,10.0 l -360.0,0 Z" + android:fillColor="?android:attr/colorControlActivated" + android:fillAlpha="?android:attr/disabledAlpha"/> + <group + android:name="rect2_grp" + android:translateX="-197.60001" + android:scaleX="0.1" > + <path + android:name="rect2" + android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z" + android:fillColor="?android:attr/colorControlActivated" /> + </group> + <group + android:name="rect1_grp" + android:translateX="-522.59998" + android:scaleX="0.1" > + <path + android:name="rect1" + android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z" + android:fillColor="?android:attr/colorControlActivated" /> + </group> + </group> +</vector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/work_off.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/work_off.xml new file mode 100644 index 000000000..500a62fbd --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/work_off.xml @@ -0,0 +1,26 @@ +<!-- + ~ 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. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="@color/error_image_color" + android:pathData="M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v1.17L10.83,8L20,8v9.17l1.98,1.98c0,-0.05 0.02,-0.1 0.02,-0.16L22,8c0,-1.11 -0.89,-2 -2,-2zM14,6h-4L10,4h4v2zM19,19L8,8 6,6 2.81,2.81 1.39,4.22 3.3,6.13C2.54,6.41 2.01,7.14 2.01,8L2,19c0,1.11 0.89,2 2,2h14.17l1.61,1.61 1.41,-1.41 -0.37,-0.37L19,19zM4,19L4,8h1.17l11,11L4,19z"/> +</vector> + diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout-w900dp/column_headers.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout-w900dp/column_headers.xml new file mode 100644 index 000000000..e0b3ff430 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout-w900dp/column_headers.xml @@ -0,0 +1,126 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/table_header" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="@dimen/doc_header_height" + android:visibility="gone"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:baselineAligned="false" + android:gravity="center_vertical" + android:minHeight="@dimen/list_item_height" + android:paddingStart="@dimen/list_item_padding_start" + android:paddingEnd="@dimen/list_item_padding_end" + android:orientation="horizontal"> + <!-- Placeholder for icon --> + <View + android:layout_width="@dimen/list_item_thumbnail_size" + android:layout_height="@dimen/list_item_thumbnail_size" + android:layout_gravity="center_vertical" + android:layout_marginEnd="16dp" + android:layout_marginStart="0dp"/> + + <!-- Column headers --> + <LinearLayout + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:orientation="horizontal"> + + <com.android.documentsui.sorting.HeaderCell + android:id="@android:id/title" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="0.4" + android:layout_marginEnd="12dp" + android:clickable="true" + android:focusable="false" + android:gravity="center_vertical" + android:orientation="horizontal" + android:animateLayoutChanges="true"> + + <include layout="@layout/shared_cell_content" /> + </com.android.documentsui.sorting.HeaderCell> + + <com.android.documentsui.sorting.HeaderCell + android:id="@android:id/summary" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="0" + android:layout_marginEnd="0dp" + android:clickable="true" + android:focusable="false" + android:gravity="center_vertical" + android:orientation="horizontal" + android:animateLayoutChanges="true"> + + <include layout="@layout/shared_cell_content" /> + </com.android.documentsui.sorting.HeaderCell> + + <com.android.documentsui.sorting.HeaderCell + android:id="@+id/file_type" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="0.2" + android:layout_marginEnd="12dp" + android:clickable="true" + android:focusable="false" + android:gravity="center_vertical" + android:orientation="horizontal" + android:animateLayoutChanges="true"> + + <include layout="@layout/shared_cell_content" /> + </com.android.documentsui.sorting.HeaderCell> + + <com.android.documentsui.sorting.HeaderCell + android:id="@+id/size" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="0.2" + android:layout_marginEnd="12dp" + android:clickable="true" + android:focusable="false" + android:gravity="center_vertical" + android:orientation="horizontal" + android:animateLayoutChanges="true"> + + <include layout="@layout/shared_cell_content" /> + </com.android.documentsui.sorting.HeaderCell> + + <com.android.documentsui.sorting.HeaderCell + android:id="@+id/date" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="0.2" + android:layout_marginEnd="12dp" + android:clickable="true" + android:focusable="false" + android:gravity="center_vertical" + android:orientation="horizontal" + android:animateLayoutChanges="true"> + + <include layout="@layout/shared_cell_content" /> + </com.android.documentsui.sorting.HeaderCell> + </LinearLayout> + </LinearLayout> +</LinearLayout>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout-w900dp/item_doc_list.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout-w900dp/item_doc_list.xml new file mode 100644 index 000000000..5e1ca3438 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout-w900dp/item_doc_list.xml @@ -0,0 +1,161 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@drawable/list_item_background" + android:clickable="true" + android:focusable="true" + android:orientation="horizontal" > + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:baselineAligned="false" + android:gravity="center_vertical" + android:minHeight="@dimen/list_item_height" + android:orientation="horizontal" + android:paddingStart="@dimen/list_item_padding_start" + android:paddingEnd="@dimen/list_item_padding_end" + android:paddingVertical="@dimen/list_item_padding_vertical"> + + <FrameLayout + android:id="@+id/icon" + android:pointerIcon="hand" + android:layout_width="@dimen/list_item_icon_size" + android:layout_height="@dimen/list_item_icon_size" + android:layout_marginEnd="@dimen/list_item_icon_margin_end"> + + <com.google.android.material.card.MaterialCardView + app:cardElevation="0dp" + app:cardBackgroundColor="@android:color/transparent" + android:layout_width="match_parent" + android:layout_height="match_parent" + app:strokeWidth="0dp"> + + <ImageView + android:id="@+id/icon_mime" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:contentDescription="@null" + android:scaleType="centerInside" /> + + <ImageView + android:id="@+id/icon_thumb" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="center" + android:contentDescription="@null" + android:scaleType="centerCrop" /> + + <ImageView + android:id="@+id/icon_check" + android:layout_width="@dimen/check_icon_size" + android:layout_height="@dimen/check_icon_size" + android:layout_gravity="center" + android:alpha="0" + android:contentDescription="@null" + android:scaleType="fitCenter" + android:src="@drawable/ic_check_circle" /> + + </com.google.android.material.card.MaterialCardView> + + </FrameLayout> + + <!-- This is the one special case where we want baseline alignment! --> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:orientation="horizontal" > + + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="0.4" + android:layout_marginEnd="12dp" + android:orientation="horizontal"> + + <ImageView + android:id="@+id/icon_profile_badge" + android:layout_height="@dimen/briefcase_icon_size" + android:layout_width="@dimen/briefcase_icon_size" + android:layout_marginEnd="@dimen/briefcase_icon_margin" + android:layout_gravity="center_vertical" + android:src="@drawable/ic_briefcase" + android:tint="@color/doc_list_item_badge_icon_color" + android:contentDescription="@string/a11y_work"/> + + <TextView + android:id="@android:id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ellipsize="end" + android:singleLine="true" + android:textAlignment="viewStart" + android:textAppearance="@style/FileItemLabelText"/> + </LinearLayout> + + <TextView + android:id="@+id/file_type" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="0.2" + android:textAlignment="viewStart" + style="@style/FileItemLabelStyle"/> + + <TextView + android:id="@+id/size" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="0.2" + android:textAlignment="viewEnd" + style="@style/FileItemLabelStyle"/> + + <TextView + android:id="@+id/date" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="0.2" + android:textAlignment="viewEnd" + style="@style/FileItemLabelStyle"/> + </LinearLayout> + + <FrameLayout + android:id="@+id/preview_icon" + android:layout_width="@dimen/list_item_icon_size" + android:layout_height="@dimen/list_item_icon_size" + android:layout_marginEnd="@dimen/list_item_icon_margin_end" + android:focusable="true"> + + <ImageView + android:layout_width="@dimen/check_icon_size" + android:layout_height="@dimen/check_icon_size" + android:layout_gravity="center" + android:scaleType="fitCenter" + android:tint="@color/doc_list_item_badge_icon_color" + android:src="@drawable/ic_zoom_out"/> + + </FrameLayout> + + </LinearLayout> + +</LinearLayout>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout-w900dp/shared_cell_content.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout-w900dp/shared_cell_content.xml new file mode 100644 index 000000000..2cbd341ed --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout-w900dp/shared_cell_content.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. + --> + +<merge xmlns:android="http://schemas.android.com/apk/res/android"> + <TextView + android:id="@+id/label" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:ellipsize="end" + android:singleLine="true" + android:textAlignment="viewStart" + android:textAppearance="@style/Subhead" + android:textColor="?android:attr/textColorSecondary"/> + + <ImageView + android:id="@+id/sort_arrow" + android:layout_height="@dimen/doc_header_sort_icon_size" + android:layout_width="@dimen/doc_header_sort_icon_size" + android:layout_marginStart="3dp" + android:visibility="gone" + android:focusable="true" + android:clickable="true" + android:background="?attr/colorSurfaceBright" + android:src="@drawable/ic_sort_arrow" + android:contentDescription="@null"/> +</merge>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/apps_item.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/apps_item.xml new file mode 100644 index 000000000..6477adedd --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/apps_item.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:minWidth="@dimen/apps_row_item_width" + android:paddingBottom="@dimen/apps_row_exit_icon_margin_bottom" + android:orientation="vertical" + android:background="@drawable/generic_ripple_background" + android:gravity="center_horizontal"> + + <ImageView + android:id="@+id/app_icon" + android:layout_width="@dimen/apps_row_app_icon_size" + android:layout_height="@dimen/apps_row_app_icon_size" + android:layout_marginTop="@dimen/apps_row_app_icon_margin_top" + android:layout_marginBottom="@dimen/apps_row_app_icon_margin_bottom" + android:layout_marginStart="@dimen/apps_row_app_icon_margin_horizontal" + android:layout_marginEnd="@dimen/apps_row_app_icon_margin_horizontal"/> + + <TextView + android:id="@android:id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/apps_row_item_text_margin_horizontal" + android:layout_marginEnd="@dimen/apps_row_item_text_margin_horizontal" + android:textAppearance="@style/AppsItemText" + android:maxLines="1" + android:ellipsize="end" + android:gravity="center"/> + + <TextView + android:id="@+id/summary" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/apps_row_item_text_margin_horizontal" + android:layout_marginEnd="@dimen/apps_row_item_text_margin_horizontal" + android:textAppearance="@style/AppsItemSubText" + android:maxLines="1" + android:ellipsize="end" + android:gravity="center"/> + +</LinearLayout>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/apps_row.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/apps_row.xml new file mode 100644 index 000000000..3a69d9f61 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/apps_row.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- TODO(b/379776735): Remove this after M3 uplift. + Currently it's being referenced in AppsRowManager. +--> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/apps_row" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minHeight="@dimen/apps_row_title_height" + android:paddingStart="@dimen/apps_row_title_padding_start" + android:textAppearance="@style/SortTitle" + android:text="@string/apps_row_title" + android:textAllCaps="true" + android:gravity="center"/> + + <HorizontalScrollView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:fillViewport="true" + android:scrollbars="none"> + <LinearLayout + android:id="@+id/apps_group" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"/> + </HorizontalScrollView> + +</LinearLayout>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/column_headers.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/column_headers.xml new file mode 100644 index 000000000..fde349b88 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/column_headers.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> + +<!-- A placeholder of table header on small screens. This won't inflate any view when it's included + into other layouts. --> +<merge /> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/dialog_delete_confirmation.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/dialog_delete_confirmation.xml new file mode 100644 index 000000000..fb3ff29cf --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/dialog_delete_confirmation.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<TextView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingTop="24dp" + android:paddingStart="24dp" + android:paddingEnd="24dp" + android:textAppearance="@style/Subhead"> +</TextView> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/dialog_file_name.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/dialog_file_name.xml new file mode 100644 index 000000000..8cae6ac03 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/dialog_file_name.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:fitsSystemWindows="true"> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/input_wrapper" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="?android:attr/listPreferredItemPaddingStart" + android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd" + android:layout_marginTop="@dimen/dialog_content_padding_top" + android:layout_marginBottom="@dimen/dialog_content_padding_bottom"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@android:id/text1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:maxLength="255" + android:inputType="textCapSentences"/> + + </com.google.android.material.textfield.TextInputLayout> +</FrameLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/dialog_sorting.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/dialog_sorting.xml new file mode 100644 index 000000000..9ddbfaee4 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/dialog_sorting.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingStart="?android:attr/listPreferredItemPaddingStart" + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" + android:paddingTop="?android:attr/listPreferredItemPaddingStart" + android:paddingBottom="?android:attr/listPreferredItemPaddingStart" + android:textAllCaps="true" + android:text="@string/sort_dimension_dialog_title" + android:textAppearance="@style/SortTitle"/> + + <ListView + android:id="@+id/sorting_dialog_list" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> + +</LinearLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/directory_app_bar.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/directory_app_bar.xml new file mode 100644 index 000000000..54a6a7cb2 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/directory_app_bar.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- This is only used in DrawerLayout (compact screen) right now. --> +<com.google.android.material.appbar.AppBarLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/app_bar" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:touchscreenBlocksFocus="false"> + + <com.google.android.material.appbar.CollapsingToolbarLayout + android:id="@+id/collapsing_toolbar" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:titleEnabled="false" + app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"> + + <androidx.core.widget.NestedScrollView + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <include layout="@layout/directory_header" /> + + <!-- column headers are empty on small screens, in portrait or in grid mode. --> + <include layout="@layout/column_headers"/> + + </androidx.core.widget.NestedScrollView> + + <com.google.android.material.appbar.MaterialToolbar + android:id="@+id/toolbar" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + app:layout_collapseMode="pin" + android:touchscreenBlocksFocus="false"> + + <TextView + android:id="@+id/searchbar_title" + android:layout_width="match_parent" + android:layout_height="?android:attr/actionBarSize" + android:gravity="center_vertical" + android:text="@string/search_bar_hint" + android:textAppearance="@style/SearchBarTitle" /> + + </com.google.android.material.appbar.MaterialToolbar> + + </com.google.android.material.appbar.CollapsingToolbarLayout> + +</com.google.android.material.appbar.AppBarLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/directory_header.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/directory_header.xml new file mode 100644 index 000000000..171c5882a --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/directory_header.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/directory_header" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <!-- used for search chip. --> + <include layout="@layout/search_chip_row"/> + + <LinearLayout + android:id="@+id/tabs_container" + android:clipToPadding="true" + android:clipChildren="true" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingStart="@dimen/main_container_padding_start" + android:paddingEnd="@dimen/main_container_padding_end" + android:paddingBottom="@dimen/space_extra_small_6" + android:orientation="vertical"> + + <com.google.android.material.tabs.TabLayout + android:id="@+id/tabs" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:tabMaxWidth="0dp" + app:tabGravity="fill" + app:tabMode="fixed" + style="@style/ProfileTabStyle"/> + <View + android:id="@+id/tab_separator" + android:layout_width="match_parent" + android:layout_height="1dp" + android:background="?attr/colorOutlineVariant"/> + </LinearLayout> + + <!-- used for apps row. --> + <include layout="@layout/apps_row"/> + +</LinearLayout>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/drag_shadow_layout.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/drag_shadow_layout.xml new file mode 100644 index 000000000..c3de2399c --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/drag_shadow_layout.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- Transparent container so shadow layer can be drawn --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:padding="8dp" + android:background="@color/item_drag_shadow_container_background"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingStart="12dp" + android:paddingEnd="12dp" + android:orientation="horizontal" + android:gravity="center_vertical" + android:background="@drawable/drag_shadow_background"> + + <include layout="@layout/drop_badge"/> + + <TextView + android:id="@android:id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:maxLines="1" + android:ellipsize="end" + android:textAlignment="viewStart" + android:textAppearance="@style/Subhead" + android:paddingStart="6dp" + android:paddingBottom="1dp"/> + + </LinearLayout> +</LinearLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/drawer_layout.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/drawer_layout.xml new file mode 100644 index 000000000..e86e0ec5a --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/drawer_layout.xml @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- CoordinatorLayout is necessary for various components (e.g. Snackbars, and + floating action buttons) to operate correctly. --> +<androidx.coordinatorlayout.widget.CoordinatorLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:id="@+id/coordinator_layout"> + + <androidx.drawerlayout.widget.DrawerLayout + android:id="@+id/drawer_layout" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <!-- Main container --> + <androidx.coordinatorlayout.widget.CoordinatorLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:paddingTop="@dimen/main_container_padding_top" + android:background="?attr/colorSurfaceBright"> + + <!-- Main list area (file list/grid or search results), full height --> + <FrameLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + app:layout_behavior="@string/scrolling_behavior"> + + <FrameLayout + android:id="@+id/container_directory" + android:clipToPadding="false" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_weight="1" /> + + <FrameLayout + android:id="@+id/container_search_fragment" + android:clipToPadding="false" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + <!-- Drawer edge is a placeholder view used to capture hovering + event on view edge to open the drawer. (b/28345294) --> + <View + android:id="@+id/drawer_edge" + android:background="@android:color/transparent" + android:layout_width="@dimen/drawer_edge_width" + android:layout_height="match_parent"/> + </FrameLayout> + + <!-- Footer of right hand side: Breadcrumbs and Picker footer. --> + <com.android.documentsui.HorizontalBreadcrumb + android:id="@+id/horizontal_breadcrumb" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" + android:background="?attr/colorSurfaceBright" + /> + + <androidx.coordinatorlayout.widget.CoordinatorLayout + android:id="@+id/container_save" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom|center_horizontal" + android:background="?android:attr/colorBackgroundFloating" + /> + + <!-- Top section: toolbar, search chips, profile tab --> + <include layout="@layout/directory_app_bar"/> + + </androidx.coordinatorlayout.widget.CoordinatorLayout> + + <!-- Drawer section --> + <LinearLayout + android:id="@+id/drawer_roots" + android:layout_width="256dp" + android:layout_height="match_parent" + android:layout_gravity="start" + android:orientation="vertical"> + + <FrameLayout + android:id="@+id/container_roots" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" /> + + </LinearLayout> + + </androidx.drawerlayout.widget.DrawerLayout> +</androidx.coordinatorlayout.widget.CoordinatorLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/drop_badge.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/drop_badge.xml new file mode 100644 index 000000000..e2f0d35cd --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/drop_badge.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<com.android.documentsui.DropBadgeView + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@android:id/icon" + android:layout_width="26dp" + android:layout_height="26dp" + android:scaleType="centerInside" + android:contentDescription="@null" + android:duplicateParentState="true"/>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/fixed_layout.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/fixed_layout.xml new file mode 100644 index 000000000..feaa34e6d --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/fixed_layout.xml @@ -0,0 +1,134 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- CoordinatorLayout is necessary for various components (e.g. Snackbars, and + floating action buttons) to operate correctly. --> +<androidx.coordinatorlayout.widget.CoordinatorLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:id="@+id/coordinator_layout" + android:focusable="true"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="horizontal" + android:baselineAligned="false" + android:background="?attr/colorSurfaceContainer" + android:paddingTop="@dimen/layout_padding_top" + android:paddingBottom="@dimen/layout_padding_bottom" + android:paddingEnd="@dimen/layout_padding_end"> + + <!-- Navigation: left hand side. --> + <FrameLayout + android:id="@+id/container_roots" + android:layout_width="256dp" + android:layout_height="match_parent" + /> + + <!-- Main container for the right hand side. --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <!-- Top section: toolbar, search chips, profile tab --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingTop="@dimen/main_container_padding_top" + android:background="@drawable/main_container_top_section_background"> + + <com.google.android.material.appbar.MaterialToolbar + android:id="@+id/toolbar" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + android:layout_marginTop="@dimen/action_bar_margin" + android:touchscreenBlocksFocus="false"> + + <TextView + android:id="@+id/searchbar_title" + android:layout_width="match_parent" + android:layout_height="?android:attr/actionBarSize" + android:gravity="center_vertical" + android:text="@string/search_bar_hint" + android:textAppearance="@style/SearchBarTitle" /> + + </com.google.android.material.appbar.MaterialToolbar> + + <include layout="@layout/directory_header" /> + + </LinearLayout> + + <!-- Main list area (file list/grid or search results). --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:orientation="vertical" + android:layout_marginTop="@dimen/main_container_section_gap" + android:background="@drawable/main_container_middle_section_background"> + + <include layout="@layout/column_headers"/> + + <FrameLayout + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1"> + + <FrameLayout + android:id="@+id/container_directory" + android:clipToPadding="false" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + <FrameLayout + android:id="@+id/container_search_fragment" + android:clipToPadding="false" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + </FrameLayout> + </LinearLayout> + + <!-- Footer of right hand side: Breadcrumbs and Picker footer. --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/main_container_section_gap" + android:background="@drawable/main_container_bottom_section_background"> + + <com.android.documentsui.HorizontalBreadcrumb + android:id="@+id/horizontal_breadcrumb" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + </LinearLayout> + + <androidx.coordinatorlayout.widget.CoordinatorLayout + android:id="@+id/container_save" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?android:attr/colorBackgroundFloating" + android:elevation="8dp" /> + + </LinearLayout> + + </LinearLayout> + +</androidx.coordinatorlayout.widget.CoordinatorLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_directory.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_directory.xml new file mode 100644 index 000000000..a7ee033f1 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_directory.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<com.android.documentsui.dirlist.AnimationView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <com.google.android.material.progressindicator.LinearProgressIndicator + android:id="@+id/progressbar" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:indeterminate="true" + app:trackColor="?attr/colorSecondaryContainer" + android:visibility="gone" /> + + <com.android.documentsui.dirlist.DocumentsSwipeRefreshLayout + android:id="@+id/refresh_layout" + android:background="@android:color/transparent" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/dir_list" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingStart="0dp" + android:paddingEnd="0dp" + android:paddingTop="0dp" + android:paddingBottom="0dp" + android:clipToPadding="false" + android:scrollbars="none" + android:drawSelectorOnTop="true" + app:fastScrollEnabled="false"/> + + </com.android.documentsui.dirlist.DocumentsSwipeRefreshLayout> + +</com.android.documentsui.dirlist.AnimationView> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_nav_rail_roots.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_nav_rail_roots.xml new file mode 100644 index 000000000..7848dea0b --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_nav_rail_roots.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<com.android.documentsui.sidebar.RootsList xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/roots_list" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:keyboardNavigationCluster="true" + android:divider="@null" + android:focusable="false" + android:descendantFocusability="afterDescendants" + style="@style/NavRailStyle"/> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_pick.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_pick.xml new file mode 100644 index 000000000..742861a3e --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_pick.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?><!-- 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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:baselineAligned="false" + android:gravity="center_vertical|end" + android:paddingStart="@dimen/bottom_bar_padding" + android:paddingEnd="@dimen/bottom_bar_padding"> + + <com.google.android.material.button.MaterialButton + android:id="@android:id/button2" + style="?attr/materialButtonOutlinedStyle" + app:cornerRadius="@dimen/button_corner_radius" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="4dp" + android:layout_marginEnd="4dp" + android:text="@android:string/cancel" /> + + <FrameLayout + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <com.google.android.material.button.MaterialButton + android:id="@android:id/button1" + style="?attr/materialButtonStyle" + app:cornerRadius="@dimen/button_corner_radius" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="4dp" + android:backgroundTint="@color/fragment_pick_button_background_color" + android:textColor="@color/fragment_pick_button_text_color" + android:layout_marginEnd="4dp" /> + + <!-- Handles touch events when button1 is disabled. --> + <FrameLayout + android:id="@+id/pick_button_overlay" + android:importantForAccessibility="no" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + </FrameLayout> + +</LinearLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_roots.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_roots.xml new file mode 100644 index 000000000..0728c6279 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_roots.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<com.android.documentsui.sidebar.RootsList xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/roots_list" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:keyboardNavigationCluster="true" + android:divider="@null" + android:focusable="false" + android:descendantFocusability="afterDescendants" + style="@style/DrawerStyle"/> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_save.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_save.xml new file mode 100644 index 000000000..401eaec88 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_save.xml @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingStart="@dimen/list_item_padding" + android:paddingEnd="@dimen/bottom_bar_padding" + android:orientation="horizontal" + android:baselineAligned="false" + android:gravity="center_vertical" + android:minHeight="?android:attr/listPreferredItemHeightSmall"> + + <FrameLayout + android:layout_width="@dimen/icon_size" + android:layout_height="@dimen/icon_size" + android:layout_marginEnd="16dp"> + + <ImageView + android:id="@android:id/icon" + android:layout_width="@dimen/root_icon_size" + android:layout_height="match_parent" + android:scaleType="centerInside" + android:contentDescription="@null" /> + + </FrameLayout> + + <EditText + android:id="@android:id/title" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:singleLine="true" + android:selectAllOnFocus="true" /> + + <FrameLayout + android:layout_width="wrap_content" + android:layout_height="match_parent"> + + <com.google.android.material.button.MaterialButton + android:id="@android:id/button1" + style="@style/Widget.Material3.Button.UnelevatedButton" + app:cornerRadius="@dimen/button_corner_radius" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="4dp" + android:layout_marginEnd="4dp" + android:text="@string/menu_save"/> + + <ProgressBar + android:id="@android:id/progress" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:visibility="gone" + android:indeterminate="true" + android:padding="8dp" + style="?android:attr/progressBarStyle" /> + + </FrameLayout> + +</LinearLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_search.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_search.xml new file mode 100644 index 000000000..75608a888 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_search.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="?android:attr/colorBackground"> + + <!-- used for search chip. --> + <include layout="@layout/search_chip_row"/> + + <ListView + android:id="@+id/history_list" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:divider="@null"/> + +</LinearLayout>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/inspector_action_view.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/inspector_action_view.xml new file mode 100644 index 000000000..c67233e1f --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/inspector_action_view.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <include + layout="@layout/inspector_section_title" + android:id="@+id/action_header" /> + + <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/default_app_info" + android:paddingLeft="16dp" + android:paddingRight="16dp" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingBottom="10dp" + android:layout_below="@id/action_header"> + + <ImageView + android:id="@+id/app_icon" + android:paddingLeft="5dp" + android:layout_width="50dp" + android:layout_height="50dp" /> + + <TextView + android:id="@+id/app_name" + android:paddingLeft="16dp" + android:paddingBottom="10dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toRightOf="@id/app_icon" + android:layout_centerVertical="true"/> + + <ImageButton + android:id="@+id/inspector_action_button" + android:layout_width="50dp" + android:layout_height="50dp" + android:layout_alignParentRight="true" + android:layout_centerVertical="true" + android:background="@null"/> + + </RelativeLayout> + +</RelativeLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/inspector_activity.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/inspector_activity.xml new file mode 100644 index 000000000..c7a34a1e6 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/inspector_activity.xml @@ -0,0 +1,119 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> +<androidx.coordinatorlayout.widget.CoordinatorLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/inspector_root" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <com.google.android.material.appbar.AppBarLayout + android:id="@+id/app_bar" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?android:colorBackground"> + + <com.google.android.material.appbar.CollapsingToolbarLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="?android:attr/actionBarSize" + app:titleEnabled="false" + app:statusBarScrim="@android:color/transparent" + app:layout_scrollFlags="scroll|exitUntilCollapsed"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <android.widget.Space + android:layout_width="match_parent" + android:layout_height="?android:attr/actionBarSize"/> + + <com.android.documentsui.inspector.HeaderView + android:id="@+id/inspector_header_view" + android:layout_width="match_parent" + android:layout_height="@dimen/inspector_header_height" + app:layout_collapseMode="parallax"/> + </LinearLayout> + + <androidx.appcompat.widget.Toolbar + android:id="@+id/toolbar" + android:layout_width="match_parent" + android:layout_height="?android:attr/actionBarSize" + android:background="?android:attr/colorBackground" + android:theme="?actionBarTheme" + app:title="@string/inspector_title" + app:titleTextAppearance="@style/ToolbarTitle" + app:layout_collapseMode="pin"> + </androidx.appcompat.widget.Toolbar> + </com.google.android.material.appbar.CollapsingToolbarLayout> + </com.google.android.material.appbar.AppBarLayout> + + <androidx.core.widget.NestedScrollView + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + app:behavior_overlapTop="10dp" + app:layout_behavior="@string/appbar_scrolling_view_behavior"> + + <LinearLayout + android:id="@+id/inspector_container" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@drawable/bottom_sheet_dialog_background" + android:paddingBottom="5dp"> + + <com.android.documentsui.inspector.DetailsView + android:id="@+id/inspector_details_view" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> + + <com.android.documentsui.inspector.MediaView + android:id="@+id/inspector_media_view" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> + + <com.android.documentsui.inspector.actions.ActionView + android:id="@+id/inspector_show_in_provider_view" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:visibility="gone"/> + + <com.android.documentsui.inspector.actions.ActionView + android:id="@+id/inspector_app_defaults_view" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:visibility="gone"/> + + <com.android.documentsui.inspector.DebugView + android:id="@+id/inspector_debug_view" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="20dp" + android:visibility="gone" /> + + </LinearLayout> + </androidx.core.widget.NestedScrollView> + +</androidx.coordinatorlayout.widget.CoordinatorLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/inspector_header.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/inspector_header.xml new file mode 100644 index 000000000..a44ed0b76 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/inspector_header.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <ImageView + android:id="@+id/inspector_thumbnail" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:scaleType="fitCenter" + android:alpha="0.0" + android:background="?android:colorBackgroundFloating" /> + +</RelativeLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/inspector_section_title.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/inspector_section_title.xml new file mode 100644 index 000000000..d98fa143a --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/inspector_section_title.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:orientation="vertical" + android:divider="@drawable/inspector_separator" + android:showDividers="beginning" + android:paddingStart="10dp" + android:paddingEnd="10dp"> + + <!--Empty view for keeping divider when title is gone--> + <android.widget.Space + android:layout_height="wrap_content" + android:layout_width="wrap_content"> + </android.widget.Space > + + <TextView + android:layout_height="match_parent" + android:layout_width="match_parent" + android:id="@+id/inspector_header_title" + android:paddingStart="16dp" + android:paddingEnd="16dp" + android:paddingTop="25dp" + android:paddingBottom="25dp" + android:layout_gravity="center_vertical" + android:clickable="false" + android:textAppearance="@style/ToolbarTitle" + android:textAlignment="viewStart" + android:textIsSelectable="true"/> +</LinearLayout>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/item_dir_grid.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_dir_grid.xml new file mode 100644 index 000000000..44a53325d --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_dir_grid.xml @@ -0,0 +1,116 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> + +<!-- FYI: This layout has an extra top level container view that was previously used + to allow for the insertion of debug info. The debug info is now gone, but the + container remains because there is a high likelihood of UI regression relating + to focus and selection states, some of which are specific to keyboard + when touch mode is not enable. So, if you, heroic engineer of the future, + decide to rip these out, please be sure to check out focus and keyboards. --> +<com.google.android.material.card.MaterialCardView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/item_root" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:foreground="?android:attr/selectableItemBackground" + android:clickable="true" + android:focusable="true" + app:cardElevation="0dp"> + + <com.google.android.material.card.MaterialCardView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:elevation="0dp" + android:duplicateParentState="true" + app:cardElevation="0dp" + app:strokeWidth="1dp" + app:strokeColor="?android:strokeColor"> + + <!-- The height is 48px. + paddingTop (9dp) + @dimen/check_icon_size (30dp) + paddingBottom (9dp) --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="horizontal" + android:background="?android:attr/colorBackground" + android:gravity="center_vertical"> + + <FrameLayout + android:id="@+id/icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:pointerIcon="hand" + android:paddingBottom="9dp" + android:paddingStart="9dp" + android:paddingEnd="8dp" + android:paddingTop="9dp"> + + <ImageView + android:id="@+id/icon_mime_sm" + android:layout_width="@dimen/grid_item_icon_size" + android:layout_height="@dimen/grid_item_icon_size" + android:layout_gravity="center" + android:contentDescription="@null" + android:scaleType="centerInside"/> + + <ImageView + android:id="@+id/icon_check" + android:layout_width="@dimen/check_icon_size" + android:layout_height="@dimen/check_icon_size" + android:alpha="0" + android:contentDescription="@null" + android:scaleType="fitCenter" + android:src="@drawable/ic_check_circle"/> + + </FrameLayout> + + <ImageView + android:id="@+id/icon_profile_badge" + android:layout_height="@dimen/briefcase_icon_size" + android:layout_width="@dimen/briefcase_icon_size" + android:layout_marginEnd="@dimen/briefcase_icon_margin" + android:src="@drawable/ic_briefcase" + android:tint="?android:attr/colorAccent" + android:contentDescription="@string/a11y_work"/> + + <TextView + android:id="@android:id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ellipsize="end" + android:singleLine="true" + android:textAlignment="viewStart" + android:textAppearance="@style/CardPrimaryText" + android:layout_marginBottom="9dp" + android:layout_marginEnd="12dp" + android:layout_marginTop="9dp"/> + + </LinearLayout> + + </com.google.android.material.card.MaterialCardView> + + <!-- An overlay that draws the item border when it is focused. --> + <View + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@drawable/item_doc_grid_border_rounded" + android:contentDescription="@null" + android:duplicateParentState="true"/> + +</com.google.android.material.card.MaterialCardView>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_grid.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_grid.xml new file mode 100644 index 000000000..32596f2f4 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_grid.xml @@ -0,0 +1,209 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- FYI: This layout has an extra top level container view that was previously used + to allow for the insertion of debug info. The debug info is now gone, but the + container remains because there is a high likelihood of UI regression relating + to focus and selection states, some of which are specific to keyboard + when touch mode is not enable. So, if you, heroic engineer of the future, + decide to rip these out, please be sure to check out focus and keyboards. --> +<com.google.android.material.card.MaterialCardView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/item_root" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:foreground="?android:attr/selectableItemBackground" + android:clickable="true" + android:focusable="true" + app:cardElevation="0dp"> + + <com.google.android.material.card.MaterialCardView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:elevation="0dp" + android:duplicateParentState="true" + app:cardElevation="0dp" + app:strokeWidth="1dp" + app:strokeColor="?android:strokeColor"> + + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:duplicateParentState="true"> + + <!-- Main item thumbnail. Comprised of two overlapping images, the + visibility of which is controlled by code in + DirectoryFragment.java. --> + + <FrameLayout + android:id="@+id/thumbnail" + android:background="?attr/gridItemTint" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <com.android.documentsui.GridItemThumbnail + android:id="@+id/icon_thumb" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:scaleType="centerCrop" + android:contentDescription="@null" + android:tint="?attr/gridItemTint" + android:tintMode="src_over"/> + + <com.android.documentsui.GridItemThumbnail + android:id="@+id/icon_mime_lg" + android:layout_width="@dimen/icon_size" + android:layout_height="@dimen/icon_size" + android:layout_gravity="center" + android:scaleType="fitCenter" + android:contentDescription="@null"/> + + </FrameLayout> + + <FrameLayout + android:id="@+id/preview_icon" + android:layout_width="@dimen/button_touch_size" + android:layout_height="@dimen/button_touch_size" + android:layout_alignParentTop="true" + android:layout_alignParentEnd="true" + android:pointerIcon="hand" + android:focusable="true" + android:clickable="true"> + + <ImageView + android:layout_width="@dimen/zoom_icon_size" + android:layout_height="@dimen/zoom_icon_size" + android:padding="2dp" + android:layout_gravity="center" + android:background="@drawable/circle_button_background" + android:scaleType="fitCenter" + android:src="@drawable/ic_zoom_out"/> + + </FrameLayout> + + <!-- Item nameplate. Has a mime-type icon and some text fields (title, + size, mod-time, etc). --> + + <LinearLayout + android:id="@+id/nameplate" + android:background="?android:attr/colorBackground" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/thumbnail"> + + <FrameLayout + android:id="@+id/icon" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_centerVertical="true" + android:pointerIcon="hand" + android:paddingTop="8dp" + android:paddingBottom="8dp" + android:paddingStart="12dp" + android:paddingEnd="8dp"> + + <ImageView + android:id="@+id/icon_mime_sm" + android:layout_width="@dimen/grid_item_icon_size" + android:layout_height="@dimen/grid_item_icon_size" + android:layout_gravity="center" + android:scaleType="center" + android:contentDescription="@null"/> + + <ImageView + android:id="@+id/icon_check" + android:src="@drawable/ic_check_circle" + android:alpha="0" + android:layout_width="@dimen/check_icon_size" + android:layout_height="@dimen/check_icon_size" + android:layout_gravity="center" + android:scaleType="fitCenter" + android:contentDescription="@null"/> + + </FrameLayout> + + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingBottom="8dp" + android:paddingTop="8dp" + android:paddingEnd="12dp"> + + <ImageView + android:id="@+id/icon_profile_badge" + android:layout_height="@dimen/briefcase_icon_size" + android:layout_width="@dimen/briefcase_icon_size" + android:layout_marginEnd="@dimen/briefcase_icon_margin" + android:layout_alignTop="@android:id/title" + android:layout_alignBottom="@android:id/title" + android:gravity="center_vertical" + android:src="@drawable/ic_briefcase" + android:tint="?android:attr/colorAccent" + android:contentDescription="@string/a11y_work"/> + + <TextView + android:id="@android:id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:layout_toEndOf="@+id/icon_profile_badge" + android:singleLine="true" + android:ellipsize="end" + android:textAlignment="viewStart" + android:textAppearance="@style/CardPrimaryText"/> + + <TextView + android:id="@+id/details" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@android:id/title" + android:layout_marginEnd="4dp" + android:singleLine="true" + android:ellipsize="end" + android:textAlignment="viewStart" + android:textAppearance="@style/ItemCaptionText" /> + + <TextView + android:id="@+id/date" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@android:id/title" + android:layout_toEndOf="@id/details" + android:singleLine="true" + android:ellipsize="end" + android:textAlignment="viewStart" + android:textAppearance="@style/ItemCaptionText" /> + + </RelativeLayout> + + </LinearLayout> + + </RelativeLayout> + + </com.google.android.material.card.MaterialCardView> + + <!-- An overlay that draws the item border when it is focused. --> + <View + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@drawable/item_doc_grid_border_rounded" + android:contentDescription="@null" + android:duplicateParentState="true"/> + +</com.google.android.material.card.MaterialCardView> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_header_message.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_header_message.xml new file mode 100644 index 000000000..86fa60ccc --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_header_message.xml @@ -0,0 +1,116 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/item_root" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <com.google.android.material.card.MaterialCardView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:elevation="0dp" + android:duplicateParentState="true" + app:cardElevation="0dp" + app:strokeWidth="1dp" + app:strokeColor="?android:strokeColor"> + + <LinearLayout + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:background="?android:attr/colorBackground" + android:orientation="vertical"> + + <LinearLayout + android:animateLayoutChanges="true" + android:id="@+id/message_container" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:minHeight="60dp" + android:orientation="horizontal"> + + <ImageView + android:contentDescription="@null" + android:id="@+id/message_icon" + android:layout_height="@dimen/icon_size" + android:layout_width="@dimen/icon_size" + android:layout_margin="8dp" + android:layout_gravity="center" + android:scaleType="centerInside"/> + + <LinearLayout + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:minHeight="48dp" + android:paddingTop="12dp" + android:paddingEnd="12dp" + android:gravity="center_vertical" + android:orientation="vertical"> + + <TextView + android:id="@+id/message_title" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:textSize="16sp" + android:textAppearance="@style/DrawerMenuPrimary"/> + + <TextView + android:id="@+id/message_subtitle" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:selectAllOnFocus="true" + android:textSize="12sp"/> + + <TextView + android:id="@+id/message_textview" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:selectAllOnFocus="true"/> + + <Button + android:id="@+id/dismiss_button" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_gravity="end" + android:text="@android:string/ok" + style="@style/DialogTextButton"/> + + </LinearLayout> + </LinearLayout> + + <LinearLayout + android:id="@+id/action_view" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:orientation="vertical"> + + <Button + android:id="@+id/action_button" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_marginEnd="16dp" + android:layout_gravity="end" + style="@style/DialogTextButton"/> + + </LinearLayout> + + </LinearLayout> + + </com.google.android.material.card.MaterialCardView> +</FrameLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_inflated_message.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_inflated_message.xml new file mode 100644 index 000000000..26f5a8ee7 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_inflated_message.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@android:id/empty" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?android:attr/colorBackground" + android:focusable="true"> + + <include android:id="@+id/content" layout="@layout/item_doc_inflated_message_content"/> + <include android:id="@+id/cross_profile" + layout="@layout/item_doc_inflated_message_cross_profile"/> +</FrameLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_inflated_message_content.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_inflated_message_content.xml new file mode 100644 index 000000000..7645b6cd5 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_inflated_message_content.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/content" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <ImageView + android:id="@+id/artwork" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="25dp" + android:layout_marginBottom="25dp" + android:scaleType="fitCenter" + android:maxHeight="250dp" + android:adjustViewBounds="true" + android:gravity="bottom|center_horizontal" + android:contentDescription="@null"/> + + <TextView + android:id="@+id/message" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="25dp" + android:gravity="center_horizontal" + style="?android:attr/textAppearanceListItem"/> + +</LinearLayout>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_inflated_message_cross_profile.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_inflated_message_cross_profile.xml new file mode 100644 index 000000000..4a77c702e --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_inflated_message_cross_profile.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:gravity="center_horizontal" + android:paddingTop="@dimen/item_doc_inflated_message_padding_top" + android:paddingStart="72dp" + android:paddingEnd="72dp"> + + <ProgressBar + android:id="@+id/cross_profile_progress" + style="@android:style/Widget.Material.Light.ProgressBar" + android:visibility="gone" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:indeterminate="true" + android:indeterminateTint="?attr/colorAccent"/> + + <LinearLayout + android:id="@+id/cross_profile_content" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + android:gravity="center_horizontal"> + + <ImageView + android:id="@+id/artwork" + android:layout_width="24dp" + android:layout_height="24dp"/> + <TextView + android:id="@+id/title" + android:layout_marginTop="8dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:textAppearance="@style/EmptyStateTitleText"/> + <TextView + android:id="@+id/message" + android:layout_marginTop="@dimen/cross_profile_button_message_margin_top" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:textAppearance="@style/EmptyStateMessageText"/> + <Button + android:id="@+id/button" + android:layout_marginTop="16dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:cornerRadius="@dimen/cross_profile_button_corner_radius" + app:strokeWidth="@dimen/cross_profile_button_stroke_width" + app:strokeColor="@color/work_profile_button_stroke_color" + style="@style/EmptyStateButton"/> + </LinearLayout> +</LinearLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_list.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_list.xml new file mode 100644 index 000000000..63b792c59 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_list.xml @@ -0,0 +1,154 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + 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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/item_root" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@drawable/list_item_background" + android:clickable="true" + android:focusable="true" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:baselineAligned="false" + android:gravity="center_vertical" + android:minHeight="@dimen/list_item_height" + android:orientation="horizontal" + android:paddingStart="@dimen/list_item_padding_start" + android:paddingEnd="@dimen/list_item_padding_end" + android:paddingVertical="@dimen/list_item_padding_vertical"> + + <FrameLayout + android:id="@+id/icon" + android:pointerIcon="hand" + android:layout_width="@dimen/list_item_icon_size" + android:layout_height="@dimen/list_item_icon_size" + android:layout_marginEnd="@dimen/list_item_icon_margin_end"> + + <com.google.android.material.card.MaterialCardView + android:layout_width="match_parent" + android:layout_height="match_parent" + app:cardBackgroundColor="@android:color/transparent" + app:cardElevation="0dp" + app:strokeWidth="0dp"> + + <ImageView + android:id="@+id/icon_mime" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:contentDescription="@null" + android:scaleType="centerInside" /> + + <ImageView + android:id="@+id/icon_thumb" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:contentDescription="@null" + android:scaleType="centerCrop" /> + + <ImageView + android:id="@+id/icon_check" + android:layout_width="@dimen/check_icon_size" + android:layout_height="@dimen/check_icon_size" + android:layout_gravity="center" + android:alpha="0" + android:contentDescription="@null" + android:scaleType="fitCenter" + android:src="@drawable/ic_check_circle" /> + + </com.google.android.material.card.MaterialCardView> + + </FrameLayout> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:orientation="vertical" + android:layout_gravity="center_vertical" + android:layout_marginEnd="@dimen/list_item_icon_size"> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="0dp" + android:layout_weight="1"> + + <ImageView + android:id="@+id/icon_profile_badge" + android:layout_height="@dimen/briefcase_icon_size" + android:layout_width="@dimen/briefcase_icon_size" + android:layout_marginEnd="@dimen/briefcase_icon_margin" + android:layout_gravity="center_vertical" + android:src="@drawable/ic_briefcase" + android:tint="@color/doc_list_item_badge_icon_color" + android:contentDescription="@string/a11y_work" /> + + <TextView + android:id="@android:id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ellipsize="end" + android:singleLine="true" + android:textAlignment="viewStart" + android:textAppearance="@style/FileItemLabelText" /> + + </LinearLayout> + + <LinearLayout + android:id="@+id/line2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:baselineAligned="false" + android:gravity="center_vertical" + android:orientation="horizontal"> + + <TextView + android:id="@+id/metadata" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ellipsize="end" + android:singleLine="true" + android:textAppearance="@style/ItemCaptionText" /> + + </LinearLayout> + + </LinearLayout> + + <FrameLayout + android:id="@+id/preview_icon" + android:layout_width="@dimen/list_item_icon_size" + android:layout_height="@dimen/list_item_icon_size" + android:focusable="true" + android:clickable="true"> + + <ImageView + android:layout_width="@dimen/check_icon_size" + android:layout_height="@dimen/check_icon_size" + android:layout_gravity="center" + android:scaleType="fitCenter" + android:tint="@color/doc_list_item_badge_icon_color" + android:src="@drawable/ic_zoom_out" /> + + </FrameLayout> + + </LinearLayout> + +</LinearLayout>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/item_history.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_history.xml new file mode 100644 index 000000000..2936741e5 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_history.xml @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeight" + android:paddingStart="?android:attr/listPreferredItemPaddingStart" + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" + android:gravity="center_vertical"> + + <ImageView + android:layout_width="@dimen/button_touch_size" + android:layout_height="@dimen/button_touch_size" + android:src="@drawable/ic_history" + android:scaleType="centerInside"/> + + <TextView + android:id="@android:id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="1" + android:paddingStart="?android:attr/listPreferredItemPaddingStart" + android:textAppearance="?android:attr/textAppearanceListItem" + android:ellipsize="end" + android:singleLine="true" + android:gravity="center_vertical"/> + + <ImageView + android:id="@android:id/icon" + android:layout_width="@dimen/button_touch_size" + android:layout_height="@dimen/button_touch_size" + android:background="@drawable/generic_ripple_background" + android:src="@drawable/ic_action_clear" + android:scaleType="centerInside"/> + +</LinearLayout>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/item_photo_grid.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_photo_grid.xml new file mode 100644 index 000000000..cd7e8f945 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_photo_grid.xml @@ -0,0 +1,141 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- FYI: This layout has an extra top level container view that was previously used + to allow for the insertion of debug info. The debug info is now gone, but the + container remains because there is a high likelihood of UI regression relating + to focus and selection states, some of which are specific to keyboard + when touch mode is not enable. So, if you, heroic engineer of the future, + decide to rip these out, please be sure to check out focus and keyboards. --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:layout_margin="4dp" + android:background="@drawable/grid_item_background" + android:elevation="@dimen/grid_item_elevation" + android:focusable="true"> + + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:duplicateParentState="true"> + + <!-- Main item thumbnail. Comprised of two overlapping images, the + visibility of which is controlled by code in + DirectoryFragment.java. --> + + <FrameLayout + android:id="@+id/thumbnail" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <com.android.documentsui.GridItemThumbnail + android:id="@+id/icon_thumb" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:scaleType="centerCrop" + android:contentDescription="@null" + android:tint="?attr/gridItemTint" + android:tintMode="src_over"/> + + <com.android.documentsui.GridItemThumbnail + android:id="@+id/icon_mime_lg" + android:layout_width="@dimen/icon_size" + android:layout_height="@dimen/icon_size" + android:layout_gravity="center" + android:scaleType="fitCenter" + android:contentDescription="@null"/> + + </FrameLayout> + + <FrameLayout + android:layout_width="@dimen/button_touch_size" + android:layout_height="@dimen/button_touch_size" + android:layout_alignParentTop="true" + android:layout_alignParentStart="true" + android:pointerIcon="hand"> + + <ImageView + android:id="@+id/icon_check" + android:src="@drawable/ic_check_circle" + android:alpha="0" + android:layout_width="@dimen/check_icon_size" + android:layout_height="@dimen/check_icon_size" + android:layout_gravity="center" + android:scaleType="fitCenter" + android:contentDescription="@null"/> + + </FrameLayout> + + <FrameLayout + android:id="@+id/preview_icon" + android:layout_width="@dimen/button_touch_size" + android:layout_height="@dimen/button_touch_size" + android:layout_alignParentTop="true" + android:layout_alignParentEnd="true" + android:pointerIcon="hand" + android:focusable="true" + android:clickable="true"> + + <ImageView + android:layout_width="@dimen/zoom_icon_size" + android:layout_height="@dimen/zoom_icon_size" + android:padding="2dp" + android:layout_gravity="center" + android:background="@drawable/circle_button_background" + android:scaleType="fitCenter" + android:src="@drawable/ic_zoom_out"/> + + </FrameLayout> + + <FrameLayout + android:id="@+id/icon_profile_badge" + android:layout_width="@dimen/button_touch_size" + android:layout_height="@dimen/button_touch_size" + android:layout_alignParentBottom="true" + android:layout_alignParentEnd="true" + android:pointerIcon="hand"> + + <ImageView + android:id="@+id/icon_id" + android:layout_height="@dimen/briefcase_icon_size_photo" + android:layout_width="@dimen/briefcase_icon_size_photo" + android:src="@drawable/ic_briefcase_white" + android:tint="?android:attr/colorAccent" + android:padding="5dp" + android:background="@drawable/circle_button_background" + android:layout_gravity="center" + android:scaleType="fitCenter" + android:contentDescription="@string/a11y_work"/> + </FrameLayout> + + <!-- An overlay that draws the item border when it is focused. --> + <View + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignBottom="@id/thumbnail" + android:layout_alignTop="@id/thumbnail" + android:layout_alignLeft="@id/thumbnail" + android:layout_alignRight="@id/thumbnail" + android:contentDescription="@null" + android:background="@drawable/item_doc_grid_border" + android:duplicateParentState="true"/> + + </RelativeLayout> + +</LinearLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/item_root.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_root.xml new file mode 100644 index 000000000..599fab108 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_root.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<com.android.documentsui.sidebar.RootItemView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="@dimen/drawer_item_height" + android:gravity="center_vertical" + android:orientation="horizontal" + android:baselineAligned="false" + android:clickable="true" + android:focusable="true" + style="@style/DrawerItemStyle"> + + <FrameLayout + android:layout_width="wrap_content" + android:layout_height="@dimen/icon_size" + android:duplicateParentState="true"> + + <ImageView + android:id="@android:id/icon" + android:layout_width="@dimen/root_icon_size" + android:layout_height="match_parent" + android:scaleType="centerInside" + android:contentDescription="@null" + android:duplicateParentState="true" /> + + </FrameLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/drawer_item_text_margin_start" + android:orientation="vertical" + android:layout_weight="1"> + + <TextView + android:id="@android:id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:singleLine="true" + android:ellipsize="end" + android:textAlignment="viewStart" + android:textAppearance="@style/DrawerMenuPrimary" /> + + <TextView + android:id="@android:id/summary" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:singleLine="true" + android:ellipsize="end" + android:textAlignment="viewStart" + android:textAppearance="@style/DrawerMenuSecondary" /> + + </LinearLayout> + + <com.google.android.material.button.MaterialButton + android:id="@+id/action_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/DrawerItemActionIconStyle" + android:visibility="gone"/> + +</com.android.documentsui.sidebar.RootItemView> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/item_root_header.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_root_header.xml new file mode 100644 index 000000000..041164ae6 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_root_header.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="8dp" + android:paddingBottom="8dp" + android:gravity="center_vertical"> + + <TextView + android:id="@android:id/title" + android:paddingStart="64dp" + android:layout_width="wrap_content" + android:layout_height="44dp" + android:gravity="center_vertical" + style="@style/DrawerMenuHeader"/> + +</LinearLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/item_root_spacer.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_root_spacer.xml new file mode 100644 index 000000000..dab92dbf0 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_root_spacer.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:focusable="false" + android:paddingHorizontal="@dimen/drawer_divider_padding_horizontal"> + + <View + android:layout_width="match_parent" + android:layout_height="1dp" + android:background="?attr/colorOutlineVariant" /> + +</FrameLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/nav_rail_item_root.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/nav_rail_item_root.xml new file mode 100644 index 000000000..461027c73 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/nav_rail_item_root.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<com.android.documentsui.sidebar.RootItemView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="@dimen/nav_rail_item_height" + android:gravity="center_horizontal" + android:orientation="vertical" + android:baselineAligned="false" + android:clickable="true" + android:focusable="true" + style="@style/NavRailItemStyle"> + + <LinearLayout + android:layout_width="@dimen/nav_rail_item_icon_bg_width" + android:layout_height="@dimen/nav_rail_item_icon_bg_height" + android:gravity="center" + android:duplicateParentState="true" + android:background="@drawable/nav_rail_item_icon_background"> + + <ImageView + android:id="@android:id/icon" + android:layout_width="@dimen/root_icon_size" + android:layout_height="@dimen/root_icon_size" + android:scaleType="centerInside" + android:contentDescription="@null" /> + + </LinearLayout> + + <TextView + android:id="@android:id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:singleLine="true" + android:ellipsize="end" + android:textAlignment="center" + android:duplicateParentState="true" + style="@style/NavRailItemTextStyle" /> + +</com.android.documentsui.sidebar.RootItemView> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/nav_rail_layout.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/nav_rail_layout.xml new file mode 100644 index 000000000..618aa7f14 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/nav_rail_layout.xml @@ -0,0 +1,156 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- CoordinatorLayout is necessary for various components (e.g. Snackbars, and + floating action buttons) to operate correctly. --> +<androidx.coordinatorlayout.widget.CoordinatorLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:id="@+id/coordinator_layout"> + + <androidx.drawerlayout.widget.DrawerLayout + android:id="@+id/drawer_layout" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <!-- Main section --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="horizontal" + android:baselineAligned="false" + android:paddingTop="@dimen/layout_padding_top" + android:paddingBottom="@dimen/layout_padding_bottom" + android:paddingEnd="@dimen/layout_padding_end" + android:background="?attr/colorSurfaceContainer"> + + <!-- Navigation rail: left hand side. --> + <FrameLayout + android:id="@+id/nav_rail_container_roots" + android:layout_width="144dp" + android:layout_height="match_parent" + /> + + <!-- Main container for the right hand side. --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <!-- Top section: toolbar, search chips, profile tab --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingTop="@dimen/main_container_padding_top" + android:background="@drawable/main_container_top_section_background"> + + <com.google.android.material.appbar.MaterialToolbar + android:id="@+id/toolbar" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + android:layout_marginTop="@dimen/action_bar_margin" + android:touchscreenBlocksFocus="false"> + + <TextView + android:id="@+id/searchbar_title" + android:layout_width="match_parent" + android:layout_height="?android:attr/actionBarSize" + android:gravity="center_vertical" + android:text="@string/search_bar_hint" + android:textAppearance="@style/SearchBarTitle" /> + + </com.google.android.material.appbar.MaterialToolbar> + + <include layout="@layout/directory_header" /> + + </LinearLayout> + + <!-- Main list area (file list/grid or search results). --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:orientation="vertical" + android:layout_marginTop="@dimen/main_container_section_gap" + android:background="@drawable/main_container_middle_section_background"> + + <include layout="@layout/column_headers"/> + + <FrameLayout + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1"> + + <FrameLayout + android:id="@+id/container_directory" + android:clipToPadding="false" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + <FrameLayout + android:id="@+id/container_search_fragment" + android:clipToPadding="false" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + </FrameLayout> + + </LinearLayout> + + <!-- Footer of right hand side: Breadcrumbs and Picker footer. --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/main_container_section_gap" + android:background="@drawable/main_container_bottom_section_background"> + + <com.android.documentsui.HorizontalBreadcrumb + android:id="@+id/horizontal_breadcrumb" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + </LinearLayout> + + <androidx.coordinatorlayout.widget.CoordinatorLayout + android:id="@+id/container_save" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?android:attr/colorBackgroundFloating" + android:elevation="8dp" /> + + </LinearLayout> + + </LinearLayout> + + <!-- Drawer section --> + <LinearLayout + android:id="@+id/drawer_roots" + android:layout_width="256dp" + android:layout_height="match_parent" + android:layout_gravity="start" + android:orientation="vertical"> + + <FrameLayout + android:id="@+id/container_roots" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" /> + + </LinearLayout> + + </androidx.drawerlayout.widget.DrawerLayout> +</androidx.coordinatorlayout.widget.CoordinatorLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/navigation_breadcrumb_item.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/navigation_breadcrumb_item.xml new file mode 100644 index 000000000..672343795 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/navigation_breadcrumb_item.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> + + +<!-- + CoordinatorLayout is necessary for various components (e.g. Snackbars, and + floating action buttons) to operate correctly. +--> +<!-- + focusableInTouchMode is set in order to force key events to go to the activity's global key + callback, which is necessary for proper event routing. See BaseActivity.onKeyDown. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minHeight="48dp" + android:focusable="true" + android:gravity="center_vertical" + android:orientation="horizontal"> + + <TextView + android:id="@+id/breadcrumb_text" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:maxWidth="275dp" + android:gravity="center_vertical" + android:maxLines="1" + android:ellipsize="end" + android:textAppearance="@style/BreadcrumbText" + android:background="@drawable/breadcrumb_item_background" /> + + <ImageView + android:id="@+id/breadcrumb_arrow" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_breadcrumb_arrow"/> + +</LinearLayout>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/root_vertical_divider.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/root_vertical_divider.xml new file mode 100644 index 000000000..7795492e4 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/root_vertical_divider.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. + --> + +<!-- TODO(b/379776735): remove this file after M3 uplift --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/vertical_divider" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:gravity="start|center_vertical" + android:orientation="horizontal" + android:paddingTop="@dimen/drawer_edge_width" + android:paddingBottom="@dimen/drawer_edge_width" + android:paddingStart="@dimen/grid_padding_horiz" + android:paddingEnd="@dimen/grid_padding_horiz" + android:visibility="gone"> + <View + android:layout_width="1dp" + android:layout_height="match_parent" + android:background="?android:attr/listDivider"/> +</LinearLayout>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/search_chip_item.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/search_chip_item.xml new file mode 100644 index 000000000..28f69981c --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/search_chip_item.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<com.google.android.material.chip.Chip + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/SearchChipItemStyle" + app:chipIconVisible="true" +/>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/search_chip_row.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/search_chip_row.xml new file mode 100644 index 000000000..559ae3188 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/search_chip_row.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<HorizontalScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:scrollbars="none"> + + <com.google.android.material.chip.ChipGroup + android:id="@+id/search_chip_group" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingHorizontal="@dimen/main_container_padding_start" + android:paddingVertical="@dimen/search_chip_group_padding_vertical" /> +</HorizontalScrollView> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/sort_list_item.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/sort_list_item.xml new file mode 100644 index 000000000..ed25bf809 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/sort_list_item.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@android:id/text1" + android:layout_width="match_parent" + android:layout_height="?android:attr/listPreferredItemHeightSmall" + android:textAppearance="@style/SortList" + android:gravity="center_vertical" + android:checkMark="@drawable/list_checker" + android:paddingStart="?android:attr/listPreferredItemPaddingStart" + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" />
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/table_key_value_row.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/table_key_value_row.xml new file mode 100644 index 000000000..5214133dd --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/table_key_value_row.xml @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> +<com.android.documentsui.inspector.KeyValueRow + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingStart="30dp" + android:paddingEnd="30dp"> + + <TextView + android:id="@+id/table_row_key" + android:layout_height="wrap_content" + android:layout_width="0dp" + android:layout_weight="1" + android:paddingTop="13dp" + android:paddingBottom="13dp" + android:paddingEnd="5dp" + android:textAlignment="viewStart" + android:textAppearance="?attr/textAppearanceSubtitle1"> + </TextView> + + <TextView + android:id="@+id/table_row_value" + android:layout_height="wrap_content" + android:layout_width="0dp" + android:layout_weight="1" + android:paddingTop="13dp" + android:paddingBottom="13dp" + android:clickable="false" + android:textIsSelectable="true" + android:textAlignment="viewStart" + android:textAppearance="@style/InspectorKeySubTitle"> + </TextView> + +</com.android.documentsui.inspector.KeyValueRow> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/menu/action_mode_menu.xml b/res/flag(com.android.documentsui.flags.use_material3)/menu/action_mode_menu.xml new file mode 100644 index 000000000..db4d581c1 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/menu/action_mode_menu.xml @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:id="@+id/action_menu_open_with" + android:title="@string/menu_open_with" + android:showAsAction="never" /> + <item + android:id="@+id/action_menu_share" + android:icon="@drawable/ic_menu_share" + android:title="@string/menu_share" + android:showAsAction="always" /> + <item + android:id="@+id/action_menu_delete" + android:icon="@drawable/ic_menu_delete" + android:title="@string/menu_delete" + android:showAsAction="always" /> + <item + android:id="@+id/action_menu_sort" + android:icon="@drawable/ic_sort" + android:title="@string/menu_sort" + android:showAsAction="never" /> + <item + android:id="@+id/action_menu_select" + android:title="@string/menu_select" + android:showAsAction="always" /> + <item + android:id="@+id/action_menu_select_all" + android:title="@string/menu_select_all" + android:showAsAction="never" /> + <item + android:id="@+id/action_menu_deselect_all" + android:title="@string/menu_deselect_all" + android:showAsAction="never" /> + <item + android:id="@+id/action_menu_copy_to" + android:title="@string/menu_copy" + android:showAsAction="never" + android:visible="false" /> + <item + android:id="@+id/action_menu_extract_to" + android:title="@string/menu_extract" + android:icon="@drawable/ic_menu_extract" + android:showAsAction="always" + android:visible="false" /> + <item + android:id="@+id/action_menu_move_to" + android:title="@string/menu_move" + android:showAsAction="never" + android:visible="false" /> + <item + android:id="@+id/action_menu_compress" + android:title="@string/menu_compress" + android:showAsAction="never" + android:visible="false" /> + <item + android:id="@+id/action_menu_rename" + android:title="@string/menu_rename" + android:showAsAction="never" + android:visible="false" /> + <item + android:id="@+id/action_menu_inspect" + android:title="@string/menu_inspect" + android:showAsAction="never" + android:visible="false" /> + <item + android:id="@+id/action_menu_view_in_owner" + android:title="@string/menu_view_in_owner" + android:showAsAction="never" + android:visible="false" /> +</menu> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/menu/activity.xml b/res/flag(com.android.documentsui.flags.use_material3)/menu/activity.xml new file mode 100644 index 000000000..0e636a18c --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/menu/activity.xml @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<menu + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> +<!-- showAsAction flag impacts the behavior of SearchView. + When set to collapseActionView, collapsing SearchView to icon is the + default behavior. It would fit UX, however after expanding SearchView is + shown on the left site of the toolbar (replacing title). Since no way to + prevent this behavior was found, the flag is set to always. SearchView is + always visible by default and it is being collapse manually by calling + setIconified() method +--> + <item + android:id="@+id/option_menu_search" + android:title="@string/menu_search" + android:icon="@drawable/ic_menu_search" + android:imeOptions="actionSearch" + android:visible="false" + app:showAsAction="always|collapseActionView" + app:actionViewClass="androidx.appcompat.widget.SearchView"/> + <item + android:id="@+id/sub_menu_grid" + android:title="@string/menu_grid" + android:icon="@drawable/ic_menu_view_grid" + app:showAsAction="always" /> + <item + android:id="@+id/sub_menu_list" + android:title="@string/menu_list" + android:icon="@drawable/ic_menu_view_list" + app:showAsAction="always" /> +<!-- This group is being hidden when searching is in full bar mode--> + <group android:id="@+id/group_hide_when_searching"> + <item + android:id="@+id/option_menu_debug" + android:title="Debug" + android:icon="@drawable/ic_debug_menu" + android:visible="false" + app:showAsAction="always"/> + <item + android:id="@+id/option_menu_new_window" + android:title="@string/menu_new_window" + android:alphabeticShortcut="n" + android:visible="false" + app:showAsAction="never"/> + <item + android:id="@+id/option_menu_create_dir" + android:title="@string/menu_create_dir" + android:icon="@drawable/ic_create_new_folder" + android:alphabeticShortcut="e" + android:visible="false" + app:showAsAction="never"/> + <item + android:id="@+id/option_menu_sort" + android:title="@string/menu_sort" + android:icon="@drawable/ic_sort" + android:showAsAction="never" + android:visible="false" /> + <item + android:id="@+id/option_menu_select_all" + android:title="@string/menu_select_all" + android:alphabeticShortcut="a" + android:visible="false" + app:showAsAction="never"/> + <item + android:id="@+id/option_menu_extract_all" + android:title="@string/menu_extract_all" + android:icon="@drawable/ic_menu_extract" + android:enabled="false" + android:visible="false" + app:showAsAction="always"/> + <item + android:id="@+id/option_menu_settings" + android:title="@string/menu_settings" + android:visible="false" + app:showAsAction="never"/> + <item + android:id="@+id/option_menu_inspect" + android:title="@string/menu_inspect" + android:visible="false" + app:showAsAction="never"/> + <item + android:id="@+id/option_menu_show_hidden_files" + android:title="@string/menu_show_hidden_files" + android:visible="false" + app:showAsAction="never"/> + <item + android:id="@+id/option_menu_launcher" + android:visible="false" + app:showAsAction="never"/> + </group> +</menu> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/menu/container_context_menu.xml b/res/flag(com.android.documentsui.flags.use_material3)/menu/container_context_menu.xml new file mode 100644 index 000000000..b004edeb1 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/menu/container_context_menu.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. + --> + +<!-- Context menu used when right clicks on empty area of recycler view or empty view. --> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + + <group + android:id="@+id/menu_clipboard_group"> + <item + android:id="@+id/dir_menu_paste_from_clipboard" + android:title="@string/menu_paste_from_clipboard" /> + </group> + + <group + android:id="@+id/menu_modifier_group"> + <item + android:id="@+id/dir_menu_create_dir" + android:title="@string/menu_create_dir" /> + + <item + android:id="@+id/dir_menu_select_all" + android:title="@string/menu_select_all" /> + + <item + android:id="@+id/dir_menu_deselect_all" + android:title="@string/menu_deselect_all" /> + </group> + <group + android:id="@+id/menu_extras_group"> + <item + android:id="@+id/dir_menu_inspect" + android:title="@string/menu_inspect" /> + </group> +</menu>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/menu/dir_context_menu.xml b/res/flag(com.android.documentsui.flags.use_material3)/menu/dir_context_menu.xml new file mode 100644 index 000000000..1364b9ec7 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/menu/dir_context_menu.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. + --> + +<!-- Context menu used when user right clicks on a folder with a selection that doesn't have files. + Selection may be empty. --> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <group + android:id="@+id/menu_open_group"> + <item + android:id="@+id/dir_menu_open_in_new_window" + android:title="@string/menu_open_in_new_window" /> + </group> + + <group + android:id="@+id/menu_clipboard_group"> + <item + android:id="@+id/dir_menu_cut_to_clipboard" + android:title="@string/menu_cut_to_clipboard" /> + <item + android:id="@+id/dir_menu_copy_to_clipboard" + android:title="@string/menu_copy_to_clipboard" /> + <item + android:id="@+id/dir_menu_compress" + android:title="@string/menu_compress" /> + <item + android:id="@+id/dir_menu_paste_into_folder" + android:title="@string/menu_paste_into_folder" /> + </group> + + <group + android:id="@+id/menu_modifier_group"> + <item + android:id="@+id/dir_menu_rename" + android:title="@string/menu_rename" /> + <item + android:id="@+id/dir_menu_delete" + android:title="@string/menu_delete" /> + </group> + + <group + android:id="@+id/menu_extras_group"> + <item + android:id="@+id/dir_menu_inspect" + android:title="@string/menu_inspect" /> + </group> +</menu> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/menu/file_context_menu.xml b/res/flag(com.android.documentsui.flags.use_material3)/menu/file_context_menu.xml new file mode 100644 index 000000000..dcfa511a6 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/menu/file_context_menu.xml @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- Context menu used when user right clicks on a file with a selection that doesn't have folders. + The selection may be empty. --> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <group + android:id="@+id/menu_open_group"> + <item + android:id="@+id/dir_menu_share" + android:title="@string/menu_share" /> + <item + android:id="@+id/dir_menu_open" + android:title="@string/menu_open" /> + <item + android:id="@+id/dir_menu_open_with" + android:title="@string/menu_open_with" /> + </group> + + <group + android:id="@+id/menu_clipboard_group"> + <item + android:id="@+id/dir_menu_cut_to_clipboard" + android:title="@string/menu_cut_to_clipboard" /> + <item + android:id="@+id/dir_menu_copy_to_clipboard" + android:title="@string/menu_copy_to_clipboard" /> + <item + android:id="@+id/dir_menu_compress" + android:title="@string/menu_compress" /> + </group> + + <group + android:id="@+id/menu_modifier_group"> + <item + android:id="@+id/dir_menu_rename" + android:title="@string/menu_rename" /> + <item + android:id="@+id/dir_menu_delete" + android:title="@string/menu_delete" /> + </group> + + <group + android:id="@+id/menu_extras_group"> + <item + android:id="@+id/dir_menu_inspect" + android:title="@string/menu_inspect" /> + <item + android:id="@+id/dir_menu_view_in_owner" + android:title="@string/menu_view_in_owner" /> + </group> +</menu> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/menu/mixed_context_menu.xml b/res/flag(com.android.documentsui.flags.use_material3)/menu/mixed_context_menu.xml new file mode 100644 index 000000000..076aeda0d --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/menu/mixed_context_menu.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. + --> + +<!-- Context menu used when user right clicks with a selection mixed with both folders and docs. --> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + + <group + android:id="@+id/menu_clipboard_group"> + <item + android:id="@+id/dir_menu_cut_to_clipboard" + android:title="@string/menu_cut_to_clipboard" /> + <item + android:id="@+id/dir_menu_copy_to_clipboard" + android:title="@string/menu_copy_to_clipboard" /> + <item + android:id="@+id/dir_menu_compress" + android:title="@string/menu_compress" /> + </group> + + <group + android:id="@+id/menu_modifier_group"> + <item + android:id="@+id/dir_menu_delete" + android:title="@string/menu_delete" /> + </group> + + <group + android:id="@+id/menu_extras_group"> + <item + android:id="@+id/dir_menu_inspect" + android:title="@string/menu_inspect" /> + </group> +</menu>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/menu/root_context_menu.xml b/res/flag(com.android.documentsui.flags.use_material3)/menu/root_context_menu.xml new file mode 100644 index 000000000..20b8a6914 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/menu/root_context_menu.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:id="@+id/root_menu_eject_root" + android:title="@string/menu_eject_root" /> + <item + android:id="@+id/root_menu_open_in_new_window" + android:title="@string/menu_open_in_new_window" /> + <item + android:id="@+id/root_menu_paste_into_folder" + android:title="@string/menu_paste_into_folder" /> + <item + android:id="@+id/root_menu_settings" + android:title="@string/menu_settings" /> +</menu> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values-night-v31/colors.xml b/res/flag(com.android.documentsui.flags.use_material3)/values-night-v31/colors.xml new file mode 100644 index 000000000..2105936ab --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values-night-v31/colors.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?><!-- 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. +--> + +<resources> + <color name="work_profile_button_stroke_color"> + @*android:color/system_accent1_200 + </color> <!-- accent 200 --> + <color name="empty_state_text_color">@*android:color/system_neutral1_100 + </color> + <!-- neutral 100 --> + <color name="empty_state_message_text_color"> + @*android:color/system_neutral2_200 + </color> + <!-- neutral variant 100 --> + <color name="fragment_pick_inactive_button_color"> + @*android:color/system_neutral1_800 + </color> + <!-- neutral 100 --> + <color name="fragment_pick_inactive_text_color"> + @*android:color/system_neutral1_600 + </color> + <!-- neutral 600 --> + <color name="fragment_pick_active_button_color"> + @*android:color/system_neutral2_100 + </color> + <!-- neutral variant 100 --> + <color name="fragment_pick_active_text_color">@android:color/black</color> +</resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values-night-v31/styles.xml b/res/flag(com.android.documentsui.flags.use_material3)/values-night-v31/styles.xml new file mode 100644 index 000000000..23fcdfaf0 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values-night-v31/styles.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<resources> + <style name="TabTextAppearance" parent="@style/TextAppearance.Material3.TitleMedium"> + <item name="android:textSize">14sp</item> + <item name="fontFamily">@string/config_fontFamilyMedium</item> + <item name="android:textColor">?android:attr/colorAccent</item> + </style> + + <style name="EmptyStateButton" parent="@style/Widget.Material3.Button.OutlinedButton"> + <item name="android:backgroundTint">@android:color/transparent</item> + <item name="android:textColor">@*android:color/system_neutral1_100</item> + <item name="android:textAllCaps">false</item> + <item name="android:textAppearance">@style/EmptyStateButtonTextAppearance</item> + </style> +</resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values-night/colors.xml b/res/flag(com.android.documentsui.flags.use_material3)/values-night/colors.xml new file mode 100644 index 000000000..6ffe52622 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values-night/colors.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<resources> + <color name="app_background_color">#202124</color> + <color name="background_floating">#3C4043</color> + <color name="nav_bar_translucent">#52000000</color> + + <color name="secondary">#3D8AB4F8</color> + <color name="hairline">#5F6368</color> + + <color name="empty_state_text_color">@android:color/white</color> + <color name="error_image_color">@android:color/white</color> + + <color name="edge_effect">@android:color/white</color> + + <color name="list_divider_color">#9aa0a6</color> + + <color name="color_surface_header">@color/m3_ref_palette_dynamic_neutral_variant17</color> + + <color name="fragment_pick_active_text_color">#202124</color> <!-- Grey 900 --> + + <!-- TODO(b/379776735): remove this after M3 uplift --> + <color name="search_chip_text_selected_color">@android:color/black</color> +</resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values-night/themes.xml b/res/flag(com.android.documentsui.flags.use_material3)/values-night/themes.xml new file mode 100644 index 000000000..e8e801793 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values-night/themes.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + <style name="LauncherTheme" parent="DocumentsTheme"> + <item name="android:windowBackground">@drawable/launcher_screen_night</item> + </style> + <style name="DocumentsTheme" parent="@android:style/Theme.DeviceDefault.DocumentsUI"> + + <!-- Toolbar --> + <item name="android:actionModeBackground">?android:attr/colorBackground</item> + + <!-- Color section --> + <item name="android:colorAccent">@color/primary</item> + <item name="android:colorBackground">@color/app_background_color</item> + <item name="android:colorBackgroundFloating">@color/background_floating</item> + <item name="android:colorControlHighlight">@color/ripple_material_dark</item> + <item name="android:colorControlActivated">@color/primary</item> + <item name="android:colorPrimary">@color/primary</item> + <item name="android:colorSecondary">@color/secondary</item> + <item name="android:strokeColor">@color/hairline</item> + + <!-- System | Widget section --> + <item name="android:listDivider">@drawable/list_divider</item> + <item name="android:statusBarColor">?android:attr/colorBackground</item> + <item name="android:windowBackground">?android:attr/colorBackground</item> + <item name="android:windowLightStatusBar">false</item> + <item name="android:windowLightNavigationBar">false</item> + <item name="android:windowNoTitle">true</item> + <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item> + + </style> +</resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values-v31/colors.xml b/res/flag(com.android.documentsui.flags.use_material3)/values-v31/colors.xml new file mode 100644 index 000000000..3096f8a3e --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values-v31/colors.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?><!-- 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. +--> + +<resources> + <!-- neutral variant 700--> + <color name="work_profile_button_stroke_color"> + @*android:color/system_accent1_600 + </color> <!-- primary 600 --> + <color name="empty_state_text_color">@*android:color/system_neutral1_900 + </color> + <!-- neutral 900 --> + <color name="empty_state_message_text_color"> + @*android:color/system_neutral2_700 + </color> + <!-- neutral 10 --> + <color name="fragment_pick_inactive_button_color"> + @*android:color/system_neutral1_100 + </color> + <!-- neutral 100 --> + <color name="fragment_pick_inactive_text_color"> + @*android:color/system_neutral1_400 + </color> + <!-- neutral 400 --> + <color name="fragment_pick_active_button_color">@*android:color/system_accent1_600 + </color> + <!-- accent 600 --> + <color name="fragment_pick_active_text_color">@android:color/white</color> +</resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values-v31/dimens.xml b/res/flag(com.android.documentsui.flags.use_material3)/values-v31/dimens.xml new file mode 100644 index 000000000..07630714f --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values-v31/dimens.xml @@ -0,0 +1,28 @@ +<!-- + ~ 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. + --> +<resources> + <dimen name="action_bar_elevation">0dp</dimen> + <dimen name="action_bar_margin">0dp</dimen> + <dimen name="button_corner_radius">20dp</dimen> + <dimen name="tab_selector_indicator_height">0dp</dimen> + <dimen name="tab_height">36dp</dimen> + <dimen name="tab_container_height">48dp</dimen> + <dimen name="profile_tab_margin_top">0dp</dimen> + <dimen name="profile_tab_margin_side">@dimen/space_extra_small_4</dimen> + <dimen name="cross_profile_button_corner_radius">30dp</dimen> + <dimen name="cross_profile_button_stroke_width">1dp</dimen> + <dimen name="cross_profile_button_message_margin_top">16dp</dimen> +</resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values-v31/styles.xml b/res/flag(com.android.documentsui.flags.use_material3)/values-v31/styles.xml new file mode 100644 index 000000000..4f459253a --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values-v31/styles.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ 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. + --> + +<resources> + + <style name="SectionHeader" parent="@style/TextAppearance.Material3.TitleMedium"> + <item name="android:textColor">?android:attr/textColorPrimary</item> + <item name="fontFamily">@string/config_fontFamilyMedium</item> + <item name="android:textSize">12sp</item> + </style> + + <style name="MaterialButton" parent="@style/Widget.Material3.Button.UnelevatedButton"> + <item name="android:textAppearance">@style/MaterialButtonTextAppearance + </item> + <item name="android:backgroundTint">?android:colorAccent</item> + </style> + + <style name="MaterialOutlinedButton" parent="@style/Widget.Material3.Button.OutlinedButton"> + <item name="android:textAppearance">@style/MaterialButtonTextAppearance + </item> + <item name="android:backgroundTint">@android:color/white</item> + <item name="android:textColor">?android:colorAccent</item> + </style> + + <style name="EmptyStateButton" parent="@style/Widget.Material3.Button.OutlinedButton"> + <item name="android:backgroundTint">@android:color/transparent</item> + <item name="android:textColor">@*android:color/system_neutral1_900</item> + <item name="android:textAllCaps">false</item> + <item name="android:textAppearance">@style/EmptyStateButtonTextAppearance + </item> + </style> +</resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values-v31/styles_text.xml b/res/flag(com.android.documentsui.flags.use_material3)/values-v31/styles_text.xml new file mode 100644 index 000000000..d69d83c93 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values-v31/styles_text.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<resources> + <style name="EmptyStateTitleText"> + <item name="android:textColor">@color/empty_state_text_color</item> + <item name="android:textSize">18sp</item> + <item name="fontFamily">@string/config_headerFontFamily</item> + </style> + + <style name="EmptyStateMessageText"> + <item name="android:textColor">@color/empty_state_message_text_color</item> + <item name="android:textSize">14sp</item> + <item name="fontFamily">@string/config_fontFamily</item> + </style> +</resources>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values-w600dp/dimens.xml b/res/flag(com.android.documentsui.flags.use_material3)/values-w600dp/dimens.xml new file mode 100644 index 000000000..2781026e9 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values-w600dp/dimens.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<!-- Dimensions/sizes for size Medium (>=600dp && <900dp). --> +<resources> + <dimen name="main_container_padding_start">@dimen/space_medium_1</dimen> + <dimen name="main_container_padding_end">@dimen/space_medium_1</dimen> + <dimen name="main_container_padding_top">@dimen/space_extra_small_4</dimen> + <!-- Main margin is set by main_container_padding_start for the menu button, here is for + the space between the button the text/title, but since on this layout we don't have the button, + we zero here, to avoid pushing the title further. --> + <dimen name="search_bar_text_margin_start">0dp</dimen> + + <dimen name="toolbar_padding_start">@dimen/space_small_3</dimen> + + <dimen name="list_container_padding">@dimen/space_extra_small_6</dimen> +</resources> + diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values-w600dp/layouts.xml b/res/flag(com.android.documentsui.flags.use_material3)/values-w600dp/layouts.xml new file mode 100644 index 000000000..4b0634d54 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values-w600dp/layouts.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<resources> + <item name="documents_activity" type="layout">@layout/nav_rail_layout</item> + <item name="files_activity" type="layout">@layout/nav_rail_layout</item> +</resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values-w900dp/colors.xml b/res/flag(com.android.documentsui.flags.use_material3)/values-w900dp/colors.xml new file mode 100644 index 000000000..ec2e1ff1c --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values-w900dp/colors.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<resources> + <color name="menu_search_background">#ff2852ab</color> +</resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values-w900dp/config.xml b/res/flag(com.android.documentsui.flags.use_material3)/values-w900dp/config.xml new file mode 100644 index 000000000..21ce0acff --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values-w900dp/config.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<resources> + <!-- Indicates if search view is taking the whole toolbar space --> + <bool name="full_bar_search_view">false</bool> + + <string name="scrolling_behavior" translatable="false">@string/appbar_scrolling_view_behavior</string> +</resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values-w900dp/dimens.xml b/res/flag(com.android.documentsui.flags.use_material3)/values-w900dp/dimens.xml new file mode 100644 index 000000000..d37f3af68 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values-w900dp/dimens.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<!-- Dimensions/sizes for size Expanded (>=900dp). --> +<resources> + <dimen name="grid_padding_horiz">16dp</dimen> + <dimen name="grid_padding_vert">16dp</dimen> + + <dimen name="list_item_height">48dp</dimen> + <dimen name="list_item_padding_start">20dp</dimen> + <dimen name="list_item_padding_end">0dp</dimen> + <dimen name="list_item_icon_margin_end">@dimen/space_extra_small_4</dimen> + + <dimen name="max_drawer_width">320dp</dimen> + + <dimen name="search_bar_background_margin_start">120dp</dimen> + <dimen name="search_bar_background_margin_end">120dp</dimen> + <dimen name="search_bar_text_margin_end">24dp</dimen> + <dimen name="search_bar_icon_padding">16dp</dimen> + + <dimen name="main_container_padding_top">@dimen/space_extra_small_6</dimen> + + <dimen name="toolbar_padding_start">@dimen/main_container_padding_start</dimen> + <dimen name="toolbar_padding_end">@dimen/space_small_3</dimen> + + <dimen name="drawer_padding_top">@dimen/space_small_1</dimen> +</resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values-w900dp/layouts.xml b/res/flag(com.android.documentsui.flags.use_material3)/values-w900dp/layouts.xml new file mode 100644 index 000000000..9e4109a45 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values-w900dp/layouts.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 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. +--> + +<resources> + <item name="documents_activity" type="layout">@layout/fixed_layout</item> + <item name="files_activity" type="layout">@layout/fixed_layout</item> +</resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values/colors.xml b/res/flag(com.android.documentsui.flags.use_material3)/values/colors.xml new file mode 100644 index 000000000..c7ac0124b --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values/colors.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="utf-8"?><!-- 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. +--> + +<resources> + <!-- This is the window background, but also the background for anything + else that needs to manually declare a background matching the "default" + app background (e.g. the drawer overlay). --> + + <color name="app_background_color">@android:color/white</color> + <color name="background_floating">@android:color/white</color> + <color name="nav_bar_translucent">#99FFFFFF</color> + + <color name="primary">?attr/colorPrimary</color> + <color name="secondary">#E3F2FD</color> <!-- Blue 50 --> + <color name="hairline">#E0E0E0</color> <!-- Gray 300 --> + + <!-- TODO(b/379776735): remove this after M3 uplift --> + <color name="chip_background_disable_color">#fff1f3f4</color> + <color name="menu_search_background">@android:color/transparent</color> + <color name="item_breadcrumb_background_hovered">#1affffff</color> + <color name="item_drag_shadow_background">@android:color/white</color> + <color name="item_drag_shadow_container_background"> + @android:color/transparent + </color> + <color name="tool_bar_gradient_max">#7f000000</color> + + <color name="band_select_background">#88ffffff</color> + <color name="band_select_border">#44000000</color> + + <color name="downloads_icon_background">#ff4688f2</color> + <color name="app_icon_background">#ff4688f2</color> + <color name="shortcut_foreground">#ff3367d6</color> + <color name="shortcut_background">#fff5f5f5</color> + + <color name="empty_state_text_color">#202124</color> + <color name="error_image_color">#757575</color> + + <color name="edge_effect">@android:color/black</color> + + <color name="list_divider_color">#1f000000</color> + <color name="list_item_selected_background_color">?attr/colorPrimary</color> + <!-- This is used when the app bar is in pinned mode inside the CollapsingToolbarLayout. + The code in NavigationViewManager assume the value should be a plain color value so we can't + use the theme attribute "?attr/colorSurfaceContainerHigh" (which is a reference) here, hence + using the mapped system color in both here and dark mode. + --> + <color name="color_surface_header">@color/m3_ref_palette_dynamic_neutral_variant92</color> + + <color name="work_profile_button_stroke_color">@color/primary</color> + + <color name="fragment_pick_inactive_button_color">#E0E0E0</color> + <color name="fragment_pick_inactive_text_color">#5F6368</color> + <color name="fragment_pick_active_button_color">@color/primary</color> + <color name="fragment_pick_active_text_color">@android:color/white</color> + + <!-- TODO(b/379776735): remove this after M3 uplift --> + <color name="search_chip_text_selected_color">@android:color/white</color> + + <!-- Use this when we need to set alpha channel on top of a theme attribute color in the + color selector list, e.g. to set colorOnSecondaryContainer with a hover overlay alpha, use: + + <shape android:tint="?attr/colorOnSecondaryContainer"> + <solid android:color="@color/overlay_hover_color_percentage"/> + </shape> + --> + <color name="overlay_hover_color_percentage">#14000000</color> <!-- 8% --> +</resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values/dimens.xml b/res/flag(com.android.documentsui.flags.use_material3)/values/dimens.xml new file mode 100644 index 000000000..c6a7ba8fd --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values/dimens.xml @@ -0,0 +1,188 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- Dimensions/sizes for size Compact (<=600dp). --> +<resources> + <!-- Material design rounded radius --> + <dimen name="material_round_radius">2dp</dimen> + + <dimen name="tab_selector_indicator_height">2dp</dimen> + <dimen name="profile_tab_padding">0dp</dimen> + <dimen name="grid_container_padding">20dp</dimen> + <dimen name="list_container_padding">@dimen/space_extra_small_4</dimen> + <dimen name="icon_size">40dp</dimen> + <dimen name="button_touch_size">48dp</dimen> + <dimen name="root_icon_size">24dp</dimen> + <!-- TODO(b/379776735): remove this block after M3 uplift --> + <dimen name="root_icon_margin">0dp</dimen> + <dimen name="root_spacer_padding">0dp</dimen> + <!-- block end --> + <dimen name="root_action_icon_size">24dp</dimen> + <!-- TODO(b/379776735): remove this after M3 uplift --> + <dimen name="root_icon_disabled_alpha">?android:attr/disabledAlpha</dimen> + <dimen name="check_icon_size">20dp</dimen> + <dimen name="zoom_icon_size">24dp</dimen> + <dimen name="list_item_thumbnail_size">40dp</dimen> + <dimen name="grid_item_icon_size">30dp</dimen> + <!-- TODO(b/379776735): remove this after M3 uplift --> + <dimen name="progress_bar_height">4dp</dimen> + <fraction name="grid_scale_min">85%</fraction> + <fraction name="grid_scale_max">200%</fraction> + <dimen name="grid_width">152dp</dimen> + <dimen name="grid_section_separator_height">0dp</dimen> + <dimen name="grid_item_margin">6dp</dimen> + <dimen name="grid_padding_horiz">4dp</dimen> + <dimen name="grid_padding_vert">4dp</dimen> + <dimen name="list_item_height">56dp</dimen> + <dimen name="list_item_padding_start">16dp</dimen> + <dimen name="list_item_padding_end">8dp</dimen> + <dimen name="list_item_padding_vertical">4dp</dimen> + <dimen name="list_item_icon_margin_end">16dp</dimen> + <dimen name="list_item_icon_size">32dp</dimen> + <!-- TODO(b/379776735): remove this block after M3 uplift --> + <dimen name="list_item_width">72dp</dimen> + <dimen name="list_item_padding">16dp</dimen> + <dimen name="list_item_icon_padding">16dp</dimen> + <dimen name="list_divider_inset">72dp</dimen> + <!-- block end --> + <dimen name="breadcrumb_item_padding">8dp</dimen> + <dimen name="breadcrumb_item_height">36dp</dimen> + <dimen name="dir_elevation">8dp</dimen> + <dimen name="drag_shadow_size">120dp</dimen> + <dimen name="grid_item_elevation">2dp</dimen> + <dimen name="grid_item_radius">2dp</dimen> + <dimen name="max_drawer_width">280dp</dimen> + <dimen name="briefcase_icon_margin">8dp</dimen> + <dimen name="briefcase_icon_size">14dp</dimen> + <dimen name="briefcase_icon_size_photo">24dp</dimen> + <dimen name="button_corner_radius">2dp</dimen> + + <dimen name="drawer_edge_width">12dp</dimen> + <dimen name="drawer_padding_horizontal">@dimen/space_extra_small_6</dimen> + <dimen name="drawer_padding_top">@dimen/space_small_3</dimen> + <dimen name="drawer_padding_bottom">@dimen/space_small_1</dimen> + <dimen name="drawer_divider_padding_horizontal">16dp</dimen> + <dimen name="drawer_divider_padding_vertical">@dimen/space_extra_small_4</dimen> + <dimen name="drawer_item_height">56dp</dimen> + <dimen name="drawer_item_vertical_margin">10dp</dimen> + <dimen name="drawer_item_text_margin_start">12dp</dimen> + <dimen name="drawer_item_action_icon_margin_start">4dp</dimen> + + <dimen name="nav_rail_item_height">64dp</dimen> + <dimen name="nav_rail_item_icon_bg_radius">16dp</dimen> + <dimen name="nav_rail_item_icon_bg_width">56dp</dimen> + <dimen name="nav_rail_item_icon_bg_height">32dp</dimen> + + <dimen name="drag_shadow_width">176dp</dimen> + <dimen name="drag_shadow_height">64dp</dimen> + <dimen name="drag_shadow_radius">4dp</dimen> + <dimen name="drag_shadow_padding">8dp</dimen> + + <dimen name="doc_header_sort_icon_size">32dp</dimen> + <dimen name="doc_header_height">60dp</dimen> + + <dimen name="dropdown_sort_widget_margin">12dp</dimen> + <dimen name="dropdown_sort_widget_size">54dp</dimen> + <dimen name="dropdown_sort_text_size">18sp</dimen> + + <dimen name="drop_icon_height">14dp</dimen> + <dimen name="drop_icon_width">14dp</dimen> + + <dimen name="header_message_horizontal_padding">8dp</dimen> + + <dimen name="fastscroll_default_thickness">8dp</dimen> + <dimen name="fastscroll_minimum_range">50dp</dimen> + <dimen name="fastscroll_margin">0dp</dimen> + + <dimen name="bottom_bar_height">56dp</dimen> + <dimen name="bottom_bar_padding">10dp</dimen> + <dimen name="bottom_bar_button_height">36dip</dimen> + <dimen name="bottom_bar_button_horizontal_padding">24dp</dimen> + <dimen name="bottom_bar_button_corner_radius">4dp</dimen> + + <dimen name="inspector_header_height">280dp</dimen> + + <dimen name="root_info_header_height">60dp</dimen> + <dimen name="root_info_header_horizontal_padding">24dp</dimen> + + <!-- TODO(b/379776735): remove this block after M3 uplift --> + <dimen name="search_chip_group_margin">20dp</dimen> + <dimen name="search_chip_spacing">8dp</dimen> + <dimen name="search_chip_half_spacing">4dp</dimen> + <dimen name="search_chip_icon_padding">4dp</dimen> + <!-- block end --> + + <dimen name="search_chip_radius">8dp</dimen> + <dimen name="search_chip_group_padding_vertical">@dimen/space_extra_small_4</dimen> + <dimen name="main_container_padding_start">@dimen/space_small_4</dimen> + <dimen name="main_container_padding_end">@dimen/space_small_4</dimen> + <dimen name="main_container_padding_top">0dp</dimen> + <dimen name="main_container_section_gap">2dp</dimen> + <dimen name="main_container_corner_radius_large">16dp</dimen> + <dimen name="main_container_corner_radius_small">4dp</dimen> + <dimen name="layout_padding_top">@dimen/space_small_1</dimen> + <dimen name="layout_padding_bottom">@dimen/space_small_1</dimen> + <dimen name="layout_padding_end">@dimen/space_small_1</dimen> + + <dimen name="dialog_content_padding_top">18dp</dimen> + <dimen name="dialog_content_padding_bottom">24dp</dimen> + + <dimen name="apps_row_title_height">48dp</dimen> + <dimen name="apps_row_title_padding_start">24dp</dimen> + <dimen name="apps_row_item_width">92dp</dimen> + <dimen name="apps_row_item_height">82dp</dimen> + <dimen name="apps_row_app_icon_size">32dp</dimen> + <dimen name="apps_row_app_icon_margin_horizontal">30dp</dimen> + <dimen name="apps_row_app_icon_margin_top">6dp</dimen> + <dimen name="apps_row_app_icon_margin_bottom">10dp</dimen> + <dimen name="apps_row_exit_icon_size">12dp</dimen> + <dimen name="apps_row_exit_icon_margin_top">2dp</dimen> + <dimen name="apps_row_exit_icon_margin_bottom">6dp</dimen> + <dimen name="apps_row_item_text_margin_horizontal">8dp</dimen> + + <dimen name="profile_tab_radius">12dp</dimen> + + <dimen name="search_bar_elevation">0dp</dimen> + <dimen name="search_bar_radius">8dp</dimen> + <dimen name="search_bar_background_margin_start">0dp</dimen> + <dimen name="search_bar_background_margin_end">0dp</dimen> + <dimen name="search_bar_margin">0dp</dimen> + <dimen name="search_bar_text_size">16dp</dimen> + + <!-- Main margin is set by main_container_padding_start for the menu button, here is for + the space between the button the text/title. --> + <dimen name="search_bar_text_margin_start">@dimen/space_extra_small_6</dimen> + <!-- The main margin is controlled above on paddingStart, zeroing toolbar_content_insets to + avoid pushing the title or button further. --> + <dimen name="toolbar_content_inset_start">0dp</dimen> + <dimen name="toolbar_padding_start">@dimen/space_extra_small_6</dimen> + <dimen name="toolbar_padding_end">@dimen/space_extra_small_6</dimen> + <dimen name="action_bar_elevation">0dp</dimen> + <dimen name="action_bar_margin">0dp</dimen> + <dimen name="action_mode_text_size">18sp</dimen> + + <dimen name="refresh_icon_range">64dp</dimen> + + <dimen name="item_doc_inflated_message_padding_top">0dp</dimen> + <dimen name="cross_profile_button_corner_radius">0dp</dimen> + <dimen name="cross_profile_button_stroke_width">0dp</dimen> + <dimen name="cross_profile_button_message_margin_top">4dp</dimen> + + <dimen name="focus_ring_width">3dp</dimen> + <dimen name="focus_ring_gap">5dp</dimen> + <dimen name="hover_overlay_alpha">0.08</dimen> + <dimen name="ripple_overlay_alpha">0.10</dimen> +</resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values/layouts.xml b/res/flag(com.android.documentsui.flags.use_material3)/values/layouts.xml new file mode 100644 index 000000000..d5b4f9da8 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values/layouts.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<resources> + <item name="documents_activity" type="layout">@layout/drawer_layout</item> + <item name="files_activity" type="layout">@layout/drawer_layout</item> +</resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values/spaces.xml b/res/flag(com.android.documentsui.flags.use_material3)/values/spaces.xml new file mode 100644 index 000000000..595c8ddda --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values/spaces.xml @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- Measurement System Tokens, Version: 20241119-dbv3 --> +<resources> + <!-- Space tokens --> + <dimen name="space_none">0</dimen> + <dimen name="space_extra_small_1">2dp</dimen> + <dimen name="space_extra_small_2">4dp</dimen> + <dimen name="space_extra_small_3">6dp</dimen> + <dimen name="space_extra_small_4">8dp</dimen> + <dimen name="space_extra_small_5">10dp</dimen> + <dimen name="space_extra_small_6">12dp</dimen> + <dimen name="space_extra_small_7">14dp</dimen> + <dimen name="space_small_1">16dp</dimen> + <dimen name="space_small_2">18dp</dimen> + <dimen name="space_small_3">20dp</dimen> + <dimen name="space_small_4">24dp</dimen> + <dimen name="space_medium_1">32dp</dimen> + <dimen name="space_medium_2">36dp</dimen> + <dimen name="space_medium_3">40dp</dimen> + <dimen name="space_medium_4">44dp</dimen> + <dimen name="space_medium_5">48dp</dimen> + <dimen name="space_medium_6">52dp</dimen> + <dimen name="space_large_1">60dp</dimen> + <dimen name="space_large_2">64dp</dimen> + <dimen name="space_large_3">72dp</dimen> + <dimen name="space_large_4">80dp</dimen> + <dimen name="space_large_5">96dp</dimen> + + <!-- Icon size tokens --> + <dimen name="icon_size_title_small">16dp</dimen> + <dimen name="icon_size_title_medium">20dp</dimen> + <dimen name="icon_size_title_large">24dp</dimen> + <dimen name="icon_size_headline_small">28dp</dimen> + <dimen name="icon_size_headline_medium">32dp</dimen> + <dimen name="icon_size_headline_large">48dp</dimen> + <dimen name="icon_size_display_small">72dp</dimen> + <dimen name="icon_size_display_medium">96dp</dimen> + <dimen name="icon_size_display_large">120dp</dimen> + <dimen name="icon_size_display_extra_large">280dp</dimen> + + <!-- Size tokens --> + <dimen name="size_extra_small_1">2dp</dimen> + <dimen name="size_extra_small_2">4dp</dimen> + <dimen name="size_extra_small_3">8dp</dimen> + <dimen name="size_small_1">16dp</dimen> + <dimen name="size_small_2">20dp</dimen> + <dimen name="size_small_3">24dp</dimen> + <dimen name="size_small_4">28dp</dimen> + <dimen name="size_medium_1">32dp</dimen> + <dimen name="size_medium_2">36dp</dimen> + <dimen name="size_medium_3">40dp</dimen> + <dimen name="size_medium_4">48dp</dimen> + <dimen name="size_medium_5">52dp</dimen> + <dimen name="size_medium_6">56dp</dimen> + <dimen name="size_large_1">60dp</dimen> + <dimen name="size_large_2">64dp</dimen> + <dimen name="size_large_3">72dp</dimen> + <dimen name="size_large_4">80dp</dimen> + <dimen name="size_large_5">96dp</dimen> + <dimen name="size_large_6">108dp</dimen> +</resources>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values/styles.xml b/res/flag(com.android.documentsui.flags.use_material3)/values/styles.xml new file mode 100644 index 000000000..ce554c427 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values/styles.xml @@ -0,0 +1,188 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + <style name="ActionBarThemeCommon" parent="@style/ThemeOverlay.AppCompat.ActionBar"> + <item name="colorControlNormal">?android:textColorSecondary</item> + <!-- Modern platform themes set actionMenuTextColor to textColorPrimary. For example, + see Theme.Material in frameworks/base/core/res/res/values/themes_material.xml. + However, if the platform theme does not set actionMenuTextColor we are going to + crash, so let's set it here. Additionally, most of our ActionBarTheme themes + override this --> + <item name="android:actionMenuTextColor">?android:textColorPrimary</item> + <item name="android:textAllCaps">false</item> + </style> + + <!-- This gets overridden for specific platform versions and/or configs --> + <style name="ActionBarTheme" parent="@style/ActionBarThemeCommon"/> + + <style name="HamburgerMenuButtonStyle" parent="@style/Widget.Material3.Search.Toolbar.Button.Navigation"> + <item name="android:maxWidth">@dimen/icon_size_headline_large</item> + <item name="android:maxHeight">@dimen/icon_size_headline_large</item> + </style> + + <style name="ToolbarStyles" parent="@style/Widget.Material3.Toolbar"> + <item name="android:paddingStart">@dimen/toolbar_padding_start</item> + <item name="android:paddingEnd">@dimen/toolbar_padding_end</item> + <item name="contentInsetStart">@dimen/toolbar_content_inset_start</item> + <item name="contentInsetStartWithNavigation">@dimen/toolbar_content_inset_start</item> + <item name="titleMarginStart">@dimen/search_bar_text_margin_start</item> + <item name="titleTextAppearance">@style/ToolbarTitle</item> + </style> + + <style name="ActionModeStyle" parent="Widget.AppCompat.ActionMode"> + <item name="titleTextStyle">@style/ActionModeTitle</item> + <item name="android:layout_margin">@dimen/search_bar_margin</item> + </style> + + <style name="CardViewStyle" parent="@style/Widget.Material3.CardView.Outlined"> + <item name="cardBackgroundColor">@color/app_background_color</item> + <item name="cardPreventCornerOverlap">false</item> + <item name="cardCornerRadius">@dimen/grid_item_radius</item> + <item name="cardElevation">@dimen/grid_item_elevation</item> + </style> + + <style name="SnackbarButtonStyle" parent="@style/Widget.AppCompat.Button.Borderless"> + <item name="android:textColor">?android:colorPrimary</item> + </style> + + <style name="AutoCompleteTextViewStyle" parent="@style/Widget.AppCompat.AutoCompleteTextView"> + <item name="android:textColorHint">?android:attr/textColorSecondary</item> + <item name="android:textAppearance">@style/AutoCompleteText</item> + </style> + + <style name="BottomSheetDialogStyle" parent="@style/ThemeOverlay.Material3.BottomSheetDialog"> + <item name="android:windowIsFloating">false</item> + <item name="bottomSheetStyle">@style/BottomSheet</item> + <item name="colorControlHighlight">@color/ripple_material_light</item> + </style> + + <style name="BottomSheet" parent="@style/Widget.Design.BottomSheet.Modal"> + <item name="android:background">@drawable/bottom_sheet_dialog_background</item> + </style> + + <style name="OverflowButtonStyle" parent="@style/Widget.AppCompat.ActionButton.Overflow"> + <item name="android:tint">?android:colorControlNormal</item> + <item name="android:minWidth">@dimen/button_touch_size</item> + </style> + + <style name="OverflowMenuStyle" parent="@style/Widget.AppCompat.PopupMenu.Overflow"> + <item name="android:popupBackground">@drawable/menu_dropdown_panel</item> + <item name="android:dropDownWidth">wrap_content</item> + <item name="android:overlapAnchor">false</item> + </style> + + <style name="MaterialAlertDialogTitleStyle" parent="@style/MaterialAlertDialog.Material3.Title.Text.CenterStacked"> + <item name="fontFamily">@string/config_fontFamilyMedium</item> + </style> + + <style name="MaterialButton" parent="@style/Widget.Material3.Button.UnelevatedButton"> + <item name="android:textAppearance">@style/MaterialButtonTextAppearance</item> + </style> + + <style name="MaterialOutlinedButton" parent="@style/Widget.Material3.Button.OutlinedButton"> + <item name="android:textAppearance">@style/MaterialButtonTextAppearance</item> + </style> + + <style name="DialogTextButton" parent="@style/Widget.Material3.Button.TextButton.Dialog"> + <item name="android:textAppearance">@style/MaterialButtonTextAppearance</item> + </style> + + <style name="EmptyStateButton" parent="@style/Widget.Material3.Button.TextButton"> + <item name="android:textAppearance">@style/EmptyStateButtonTextAppearance</item> + </style> + + <style name="AlertDialogTheme" parent="@style/ThemeOverlay.AppCompat.Dialog.Alert"> + <item name="buttonBarPositiveButtonStyle">@style/DialogTextButton</item> + <item name="buttonBarNegativeButtonStyle">@style/DialogTextButton</item> + </style> + + <style name="MaterialAlertDialogTheme" parent="@style/ThemeOverlay.Material3.MaterialAlertDialog.Centered"> + <item name="buttonBarPositiveButtonStyle">@style/DialogTextButton</item> + <item name="buttonBarNegativeButtonStyle">@style/DialogTextButton</item> + <item name="materialAlertDialogTitleTextStyle">@style/MaterialAlertDialogTitleStyle</item> + </style> + + <style name="SearchChipItemStyle" parent="@style/Widget.Material3.Chip.Filter"> + <item name="android:textAppearance">@style/SearchChipText</item> + <item name="chipBackgroundColor">@color/search_chip_background_color</item> + <item name="chipStrokeColor">@color/search_chip_stroke_color</item> + <item name="chipCornerRadius">@dimen/search_chip_radius</item> + </style> + + <style name="DrawerStyle" parent=""> + <item name="android:background">?attr/colorSurfaceContainer</item> + <!-- Use padding together with the "outsideOverlay" scrollbar style to to make sure the + scrollbar appears on the edge of the container, and scrollbar trigger area doesn't + affect the hover effect of the views (e.g. action icon) on the edge. + --> + <item name="android:paddingHorizontal">@dimen/drawer_padding_horizontal</item> + <item name="android:paddingTop">@dimen/drawer_padding_top</item> + <item name="android:paddingBottom">@dimen/drawer_padding_bottom</item> + <item name="android:dividerHeight">@dimen/drawer_item_vertical_margin</item> + <item name="android:scrollbarStyle">outsideOverlay</item> + <item name="android:clipToPadding">false</item> + </style> + + <style name="DrawerItemStyle" parent=""> + <item name="android:paddingStart">16dp</item> + <item name="android:paddingEnd">4dp</item> + <item name="android:background">@drawable/root_item_background</item> + </style> + + <style name="DrawerItemActionIconStyle" parent="@style/Widget.Material3.Button.IconButton"> + <item name="android:layout_marginStart">@dimen/drawer_item_action_icon_margin_start</item> + <item name="strokeColor">?attr/colorSecondary</item> + </style> + + <style name="ProfileTabStyle" parent="@style/Widget.Material3.TabLayout"> + <!-- Use transparent bg color to hide the underline for tab layout. --> + <item name="android:background">@android:color/transparent</item> + <item name="tabIndicatorColor">?attr/colorPrimary</item> + <item name="tabIndicatorHeight">@dimen/tab_selector_indicator_height</item> + <item name="tabTextColor">?attr/colorOnSurfaceVariant</item> + <item name="tabSelectedTextColor">?attr/colorOnPrimaryContainer</item> + <item name="tabTextAppearance">@style/TabTextAppearance</item> + </style> + + <style name="FileItemLabelStyle" parent=""> + <item name="android:layout_marginStart">32dp</item> + <item name="android:ellipsize">end</item> + <item name="android:minWidth">70dp</item> + <item name="android:singleLine">true</item> + <item name="android:textAppearance">@style/FileItemLabelText</item> + </style> + + <style name="NavRailStyle" parent=""> + <item name="android:background">?attr/colorSurfaceContainer</item> + <item name="android:paddingHorizontal">@dimen/space_small_3</item> + <item name="android:paddingTop">@dimen/space_extra_small_6</item> + <item name="android:paddingBottom">@dimen/space_small_1</item> + <item name="android:scrollbarStyle">outsideOverlay</item> + <item name="android:clipToPadding">false</item> + </style> + + <style name="NavRailItemStyle" parent=""> + <item name="android:background">@drawable/nav_rail_item_background</item> + <item name="android:paddingVertical">6dp</item> + </style> + + <style name="NavRailItemTextStyle" parent=""> + <item name="android:layout_marginTop">4dp</item> + <item name="android:textColor">@color/nav_rail_item_text_color</item> + <item name="android:textAppearance">@style/NavRailItemTextAppearance</item> + </style> +</resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values/styles_text.xml b/res/flag(com.android.documentsui.flags.use_material3)/values/styles_text.xml new file mode 100644 index 000000000..717295315 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values/styles_text.xml @@ -0,0 +1,149 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<resources> + <style name="SortTitle" parent="@style/TextAppearance.Material3.TitleLarge"> + <item name="android:textColor">?android:attr/textColorPrimary</item> + <item name="android:textSize">11sp</item> + </style> + + <style name="SectionHeader" parent="@style/TextAppearance.Material3.TitleMedium"> + <item name="android:textColor">?android:attr/textColorPrimary</item> + <item name="android:textAllCaps">true</item> + <item name="fontFamily">@string/config_fontFamilyMedium</item> + <item name="android:textSize">12sp</item> + </style> + + <style name="SortList" parent="@style/TextAppearance.AppCompat.Subhead"> + <item name="android:textColor">@color/sort_list_text</item> + <item name="fontFamily">@string/config_fontFamilyMedium</item> + </style> + + <style name="SearchBarTitle" parent="@style/TextAppearance.Widget.AppCompat.Toolbar.Subtitle"> + <item name="android:textColor">?android:attr/textColorSecondary</item> + <item name="android:textSize">@dimen/search_bar_text_size</item> + <item name="fontFamily">@string/config_fontFamily</item> + </style> + + <style name="SearchChipText" parent="@style/TextAppearance.Material3.LabelLarge"> + <item name="fontFamily">@string/config_fontFamilyMedium</item> + </style> + + <style name="AppsItemText"> + <item name="android:textColor">?android:attr/textColorPrimary</item> + <item name="android:textSize">12sp</item> + <item name="fontFamily">@string/config_fontFamily</item> + </style> + + <style name="AppsItemSubText"> + <item name="android:textColor">?android:attr/textColorSecondary</item> + <item name="android:textSize">11sp</item> + </style> + + <style name="AutoCompleteText" parent="@style/TextAppearance.AppCompat.Medium"> + <item name="fontFamily">@string/config_fontFamily</item> + </style> + + <style name="CardPrimaryText" parent="@style/TextAppearance.AppCompat.Subhead"> + <item name="android:textColor">?android:attr/textColorPrimary</item> + <item name="android:textSize">14sp</item> + <item name="fontFamily">@string/config_fontFamily</item> + </style> + + <style name="ActionModeTitle" parent="@style/ToolbarTitle"> + <item name="android:textSize">@dimen/action_mode_text_size</item> + </style> + + <style name="ToolbarTitle" parent="@style/TextAppearance.Material3.TitleLarge"> + <item name="fontFamily">@string/config_fontFamilyMedium</item> + </style> + + <style name="DrawerMenuHeader" parent="@style/TextAppearance.Material3.BodyLarge"> + <item name="android:textColor">?android:attr/textColorSecondary</item> + <item name="android:textAllCaps">true</item> + <item name="android:textSize">11sp</item> + <item name="fontFamily">@string/config_fontFamilyMedium</item> + </style> + + <style name="DrawerMenuPrimary" parent="@style/TextAppearance.Material3.LabelLarge"> + <item name="android:textColor">@color/item_root_primary_text</item> + <item name="fontFamily">@string/config_fontFamilyMedium</item> + </style> + + <style name="DrawerMenuSecondary" parent="@style/TextAppearance.Material3.BodySmall"> + <item name="android:textColor">@color/item_root_secondary_text</item> + <item name="fontFamily">@string/config_fontFamily</item> + </style> + + <style name="InspectorKeySubTitle" parent="@style/TextAppearance.Material3.TitleMedium"> + <item name="android:textColor">?android:attr/textColorSecondary</item> + </style> + + <style name="MaterialButtonTextAppearance" parent="@style/TextAppearance.Material3.LabelLarge"> + <item name="android:textAllCaps">@bool/config_button_all_caps</item> + <item name="fontFamily">@string/config_fontFamilyMedium</item> + </style> + + <style name="BreadcrumbText" parent="@style/TextAppearance.Widget.AppCompat.Toolbar.Subtitle"> + <item name="android:textColor">@color/horizontal_breadcrumb_color</item> + <item name="android:textSize">14sp</item> + <item name="fontFamily">@string/config_fontFamilyMedium</item> + </style> + + <style name="EmptyStateTitleText"> + <item name="android:textColor">@color/empty_state_text_color</item> + <item name="android:textSize">14sp</item> + <item name="fontFamily">@string/config_fontFamilyMedium</item> + </style> + + <style name="EmptyStateMessageText"> + <item name="android:textColor">@color/empty_state_text_color</item> + <item name="android:textSize">12sp</item> + </style> + + <style name="EmptyStateButtonTextAppearance"> + <item name="android:textColor">?android:attr/colorAccent</item> + <item name="android:textSize">14sp</item> + <item name="fontFamily">@string/config_fontFamilyMedium</item> + </style> + + <style name="TabTextAppearance" parent="@style/TextAppearance.Material3.TitleSmall"> + <item name="fontFamily">@string/config_fontFamilyMedium</item> + </style> + + <style name="FileItemLabelText" parent="@style/TextAppearance.Material3.TitleSmall"> + <item name="android:textColor">@color/doc_list_item_label_color</item> + <item name="fontFamily">@string/config_fontFamily</item> + </style> + + <style name="ItemCaptionText" parent="@style/TextAppearance.Material3.LabelSmall"> + <item name="android:textColor">@color/doc_list_item_subtitle_color</item> + <item name="fontFamily">@string/config_fontFamily</item> + </style> + + <style name="MenuItemTextAppearance" parent="@style/TextAppearance.Material3.BodyMedium"> + <item name="android:textSize">14sp</item> + <item name="fontFamily">@string/config_fontFamily</item> + </style> + + <style name="Subhead" parent="@style/TextAppearance.Material3.BodyLarge"> + <item name="fontFamily">@string/config_fontFamily</item> + </style> + + <style name="NavRailItemTextAppearance" parent="@style/TextAppearance.Material3.LabelMedium"> + <item name="fontFamily">@string/config_fontFamily</item> + </style> + +</resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values/themes.xml b/res/flag(com.android.documentsui.flags.use_material3)/values/themes.xml new file mode 100644 index 000000000..c486b49c2 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values/themes.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<resources> + <style name="LauncherTheme" parent="DocumentsTheme"> + <item name="android:windowBackground">@drawable/launcher_screen</item> + </style> + <!-- DocumentsTheme is allow customize by run time overlay --> + <style name="DocumentsTheme" parent="@android:style/Theme.DeviceDefault.DocumentsUI"> + + <item name="android:actionModeBackground">?android:attr/colorBackground</item> + + <!-- Color section --> + <item name="android:colorAccent">@color/primary</item> + <item name="android:colorBackground">@android:color/white</item> + <item name="android:colorBackgroundFloating">@color/background_floating</item> + <item name="android:colorControlHighlight">@color/ripple_material_light</item> + <item name="android:colorControlActivated">@color/primary</item> + <item name="android:colorPrimary">@color/primary</item> + <item name="android:colorSecondary">@color/secondary</item> + <item name="android:strokeColor">@color/hairline</item> + + <!-- System | Widget section --> + <item name="android:listDivider">@drawable/list_divider</item> + <item name="android:statusBarColor">?android:colorBackground</item> + <item name="android:navigationBarColor">?android:colorBackground</item> + <item name="android:windowBackground">?android:colorBackground</item> + <item name="android:windowLightStatusBar">true</item> + <item name="android:windowLightNavigationBar">true</item> + <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item> + + <!-- OEM should not overlay this attr --> + <item name="android:windowNoTitle">true</item> + + </style> + + <style name="DocumentsDefaultTheme" parent="@style/Theme.Material3.DayNight.NoActionBar"> + + <!-- This only used by support lib, not allow to overlay --> + <item name="windowActionBar">false</item> + <item name="windowActionModeOverlay">true</item> + + <!-- For material design widget, chips, buttons, not support attr--> + <item name="colorPrimary">@color/primary</item> + <item name="colorAccent">@color/primary</item> + + <!-- TODO need to solve the error handle in GridItemThumbnail --> + <item name="gridItemTint">@color/item_doc_grid_tint</item> + + <item name="actionBarTheme">@style/ActionBarTheme</item> + <item name="toolbarStyle">@style/ToolbarStyles</item> + <item name="toolbarNavigationButtonStyle">@style/HamburgerMenuButtonStyle</item> + <item name="actionModeStyle">@style/ActionModeStyle</item> + <item name="actionOverflowButtonStyle">@style/OverflowButtonStyle</item> + <item name="actionOverflowMenuStyle">@style/OverflowMenuStyle</item> + <item name="alertDialogTheme">@style/AlertDialogTheme</item> + <item name="autoCompleteTextViewStyle">@style/AutoCompleteTextViewStyle</item> + <item name="bottomSheetDialogTheme">@style/BottomSheetDialogStyle</item> + <item name="materialCardViewStyle">@style/CardViewStyle</item> + <item name="materialAlertDialogTheme">@style/MaterialAlertDialogTheme</item> + <item name="queryBackground">@color/menu_search_background</item> + <item name="snackbarButtonStyle">@style/SnackbarButtonStyle</item> + <item name="android:itemTextAppearance">@style/MenuItemTextAppearance</item> + </style> +</resources> diff --git a/res/layout/selection_demo_list_item.xml b/res/layout/selection_demo_list_item.xml deleted file mode 100644 index 0d4b71826..000000000 --- a/res/layout/selection_demo_list_item.xml +++ /dev/null @@ -1,53 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2017 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:paddingStart="10dp" - android:paddingEnd="10dp" - android:paddingTop="5dp" - android:paddingBottom="5dp" - android:layout_height="50dp"> - <LinearLayout - android:id="@+id/container" - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_height="match_parent" - android:layout_width="match_parent" - android:background="@drawable/selection_demo_item_background"> - <TextView - android:id="@+id/selector" - android:textSize="20sp" - android:textStyle="bold" - android:gravity="center" - android:layout_height="match_parent" - android:layout_width="40dp" - android:textColor="@color/selection_demo_item_selector" - android:pointerIcon="hand" - android:text="✕"> - </TextView> - <TextView - android:id="@+id/label" - android:textSize="20sp" - android:textStyle="bold" - android:gravity="center_vertical" - android:paddingStart="10dp" - android:paddingEnd="10dp" - android:layout_height="match_parent" - android:layout_width="match_parent"> - </TextView> - </LinearLayout> -</LinearLayout> diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml index b37f8de80..7ecedcd5d 100644 --- a/res/values-af/strings.xml +++ b/res/values-af/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Skuif na …"</string> <string name="menu_compress" msgid="37539111904724188">"Pers saam"</string> <string name="menu_extract" msgid="8171946945982532262">"Onttrek na …"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Uittreksel van alles …"</string> <string name="menu_rename" msgid="1883113442688817554">"Hernoem"</string> <string name="menu_inspect" msgid="7279855349299446224">"Kry inligting"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Wys versteekte lêers"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Kan op die oomblik nie inhoud laai nie"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Werkapps is onderbreek"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Skakel werkprogramme aan"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> apps word gepouseer"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Skakel <xliff:g id="PROFILE">%1$s</xliff:g> apps aan"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Kan nie werklêers kies nie"</string> - <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Jou IT-administrateur laat jou nie toe om van \'n persoonlike program af by werklêers in te gaan nie"</string> + <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Jou IT-administrateur laat jou nie toe om van \'n persoonlike app af by werklêers in te gaan nie"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Kan nie persoonlike lêers kies nie"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Jou IT-administrateur laat jou nie toe om van \'n werkprogram af by persoonlike lêers in te gaan nie"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Kan nie <xliff:g id="PROFILE">%1$s</xliff:g> lêers kies nie"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Jou IT-admin laat jou nie toe om toegang tot <xliff:g id="PROFILE_0">%1$s</xliff:g> lêers vanaf ’n <xliff:g id="PROFILE_1">%2$s</xliff:g> app te kry nie"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Kan nie in jou werkprofiel stoor nie"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Jou IT-administrateur laat jou nie toe om jou persoonlike lêers in jou werkprofiel te stoor nie"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Kan nie in \'n persoonlike lêer stoor nie"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Jou IT-administrateur laat jou nie toe om werklêers in jou persoonlike lêer te stoor nie"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Kan nie in <xliff:g id="PROFILE">%1$s</xliff:g> profiel stoor nie"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Jou IT-admin laat jou nie toe om <xliff:g id="PROFILE_0">%1$s</xliff:g> lêers in jou <xliff:g id="PROFILE_1">%2$s</xliff:g> profiel te stoor nie"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Hierdie handeling word nie toegelaat nie"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Kontak jou IT-administrateur om meer te wete te kom"</string> <string name="root_recent" msgid="1080156975424341623">"Onlangs"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Nuwe naam"</string> <string name="preview_file" msgid="4056622696305432343">"Voorbeskou die lêer <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Voorbeskou die werklêer <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Voorbeskou <xliff:g id="PROFILE">%1$s</xliff:g> lêer <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Blaai deur lêers in ander programme"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anoniem"</string> <string name="open_tree_button" msgid="6402871398424497776">"Gebruik hierdie vouer"</string> @@ -274,12 +282,12 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Kan nie hierdie vouer gebruik nie"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Kies \'n ander vouer om jou privaatheid te beskerm"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Skep nuwe vouer"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Deursoek hierdie foon"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Deursoek hierdie toestel"</string> <string name="delete_search_history" msgid="2202015025607694515">"Vee soekgeskiedenis uit: <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Persoonlik"</string> <string name="work_tab" msgid="7265359366883747413">"Werk"</string> <string name="a11y_work" msgid="7504431382825242153">"Werk"</string> - <string name="drag_from_another_app" msgid="8310249276199969905">"Jy kan nie lêers uit \'n ander program skuif nie."</string> + <string name="drag_from_another_app" msgid="8310249276199969905">"Jy kan nie lêers uit \'n ander app skuif nie."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Wys tans in roostermodus."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Wys tans in lysmodus."</string> </resources> diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml index e68194b2e..40cda4a01 100644 --- a/res/values-am/strings.xml +++ b/res/values-am/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"ውሰድ ወደ…"</string> <string name="menu_compress" msgid="37539111904724188">"ጭመቅ"</string> <string name="menu_extract" msgid="8171946945982532262">"አውጣ ወደ…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"ሁሉንም አውጣ…"</string> <string name="menu_rename" msgid="1883113442688817554">"ዳግም ሰይም"</string> <string name="menu_inspect" msgid="7279855349299446224">"መረጃ አግኝ"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"የተደበቁ ፋይሎችን አሳይ"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"አሁን ይዘትን መጫን አልተቻለም"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"የስራ መተግበሪያዎች ባሉበት ቆመዋል"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"የሥራ መተግበሪያዎችን አብራ"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> መተግበሪያዎች ባሉበት ቆመዋል"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"የ<xliff:g id="PROFILE">%1$s</xliff:g> መተግበሪያዎችን ያብሩ"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"የሥራ ፋይሎችን መምረጥ አይቻልም"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"የእርስዎ አይቲ አስተዳዳሪ ከግል መተግበሪያ የሥራ ፋይሎችን እንዲደርሱ አይፈቅዱልዎትም"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"የግል ፋይሎችን መምረጥ አይቻልም"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"የእርስዎ አይቲ አስተዳዳሪ ከሥራ መተግበሪያ የግል ፋይሎችን እንዲደርሱባቸው አይፈቅዱልዎትም"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> ፋይሎችን መምረጥ አልተቻለም"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"የአይቲ አስተዳዳሪዎ የ<xliff:g id="PROFILE_0">%1$s</xliff:g> ፋይሎችን ከ<xliff:g id="PROFILE_1">%2$s</xliff:g> መተግበሪያ እንዲደርሱ አይፈቅድም"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"ወደ ሥራ መገለጫ ማስቀመጥ አይቻልም"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"የእርስዎ አይቲ አስተዳዳሪ ወደ የእርስዎ የግል ፋይሎችን ወደ የእርስዎ የሥራ ፋይሎች እንዲያስቀምጡ አይፈቅዱልዎትም"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"ወደ የግል መገለጫ ማስቀመጥ አይቻልም"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"የእርስዎ አይቲ አስተዳዳሪ ወደ የእርስዎ የግል መገለጫ የሥራ ፋይሎችን እርስዎ እንዲያስቀምጡ አይፈቅዱልዎትም"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"ወደ <xliff:g id="PROFILE">%1$s</xliff:g> መግለጫ ማስቀመጥ አይችሉም"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"የአይቲ አስተዳዳሪዎ የ<xliff:g id="PROFILE_0">%1$s</xliff:g> ፋይሎችን ወደ <xliff:g id="PROFILE_1">%2$s</xliff:g> መግለጫዎ እንዲያስቀምጡ አይፈቅድልዎትም"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"ይህ እርምጃ አይፈቀድም"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"የበለጠ ለመረዳት የእርስዎን አይቲ አስተዳዳሪ ያነጋግሩ"</string> <string name="root_recent" msgid="1080156975424341623">"የቅርብ ጊዜ"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"አዲስ ስም"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g> ፋይሉን በቅድመ ዕይታ ይመልከቱ"</string> <string name="preview_work_file" msgid="4495643735563487273">"የሥራ ፋይሉን <xliff:g id="FILENAME">%1$s</xliff:g> በቅድመ ዕይታ አሳይ"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> ፋይሉን <xliff:g id="FILENAME">%2$s</xliff:g> በቅድመ ዕይታ ይመልከቱ"</string> <string name="apps_row_title" msgid="3340490016663092925">"ፋይሎችን በሌሎች መተግበሪያዎች ውስጥ ያስሱ"</string> <string name="anonymous_application" msgid="7633027057951625862">"ስም-አልባ"</string> <string name="open_tree_button" msgid="6402871398424497776">"ይህን አቃፊ ተጠቀም"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"ይህን አቃፊ መጠቀም አይቻልም"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"ግላዊነትዎን ለመጠበቅ ሲባል ሌላ አቃፊ ይምረጡ"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"አዲስ አቃፊ ፍጠር"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"ይህን ስልክ ይፈልጉ"</string> + <string name="search_bar_hint" msgid="146031513183888721">"ይህንን መሣሪያ ይፈልጉ"</string> <string name="delete_search_history" msgid="2202015025607694515">"የፍለጋ ታሪክ ይሰርዙ <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"የግል"</string> <string name="work_tab" msgid="7265359366883747413">"ሥራ"</string> diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml index e13b30853..329b59df4 100644 --- a/res/values-ar/strings.xml +++ b/res/values-ar/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"نقل إلى..."</string> <string name="menu_compress" msgid="37539111904724188">"ضغط"</string> <string name="menu_extract" msgid="8171946945982532262">"الاستخراج إلى…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"استخراج الكل…"</string> <string name="menu_rename" msgid="1883113442688817554">"إعادة تسمية"</string> <string name="menu_inspect" msgid="7279855349299446224">"الحصول على المعلومات"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"إظهار الملفات المخفية"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"يتعذر تحميل المحتوى في الوقت الحالي"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"تطبيقات العمل متوقفة مؤقتًا"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"تفعيل تطبيقات العمل"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"تطبيقات <xliff:g id="PROFILE">%1$s</xliff:g> متوقفة مؤقتًا"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"تفعيل تطبيقات <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"لا يمكن اختيار ملفات العمل"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"لا يسمح لك مشرف تكنولوجيا المعلومات بالوصول إلى ملفات العمل من تطبيق شخصي."</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"لا يمكن اختيار ملفات شخصية"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"لا يسمح لك مشرف تكنولوجيا المعلومات بالوصول إلى الملفات الشخصية من تطبيق عمل."</string> - <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"لا يمكن حفظ الملفات في الملف الشخصي للعمل"</string> - <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"لا يسمح لك مشرف تكنولوجيا المعلومات بحفظ الملفات الشخصية في ملفك الشخصي للعمل."</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"يتعذّر اختيار ملفات <xliff:g id="PROFILE">%1$s</xliff:g>."</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"لا يسمح لك مشرف تكنولوجيا المعلومات في مؤسستك بالوصول إلى ملفات <xliff:g id="PROFILE_0">%1$s</xliff:g> من خلال تطبيق <xliff:g id="PROFILE_1">%2$s</xliff:g>."</string> + <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"لا يمكن حفظ الملفات في ملف العمل"</string> + <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"لا يسمح لك مشرف تكنولوجيا المعلومات بحفظ الملفات الشخصية في ملف العمل الخاص بك."</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"لا يمكن حفظ الملفات في الملف الشخصي"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"لا يسمح لك مشرف تكنولوجيا المعلومات بحفظ ملفات العمل في ملفك الشخصي."</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"يتعذّر الحفظ في ملف <xliff:g id="PROFILE">%1$s</xliff:g>."</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"لا يسمح لك مشرف تكنولوجيا المعلومات في مؤسستك بحفظ ملفات <xliff:g id="PROFILE_0">%1$s</xliff:g> في ملف <xliff:g id="PROFILE_1">%2$s</xliff:g>."</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"هذا الإجراء غير مسموح به."</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"لمعرفة مزيد من المعلومات، يمكنك التواصل مع مشرف تكنولوجيا المعلومات."</string> <string name="root_recent" msgid="1080156975424341623">"المحتوى المستخدَم أو المعدَّل مؤخرًا"</string> @@ -354,6 +361,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"اسم جديد"</string> <string name="preview_file" msgid="4056622696305432343">"معاينة الملف <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"معاينة ملف العمل <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"معاينة الملف \"<xliff:g id="FILENAME">%2$s</xliff:g>\" في <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"تصفّح الملفات في تطبيقات أخرى"</string> <string name="anonymous_application" msgid="7633027057951625862">"مجهول"</string> <string name="open_tree_button" msgid="6402871398424497776">"استخدام هذا المجلد"</string> @@ -362,7 +370,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"لا يمكن استخدام هذا المجلد"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"لحماية خصوصيتك، اختَر مجلدًا آخر"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"إنشاء مجلد جديد"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"البحث في هذا الهاتف"</string> + <string name="search_bar_hint" msgid="146031513183888721">"البحث في هذا الجهاز"</string> <string name="delete_search_history" msgid="2202015025607694515">"حذف سجلّ البحث <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"شخصي"</string> <string name="work_tab" msgid="7265359366883747413">"للعمل"</string> diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml index 2c5c0590b..72d34172e 100644 --- a/res/values-as/strings.xml +++ b/res/values-as/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"ইয়ালৈ স্থানান্তৰ কৰক…"</string> <string name="menu_compress" msgid="37539111904724188">"সংকুচিত কৰক"</string> <string name="menu_extract" msgid="8171946945982532262">"ইয়ালৈ আহৰণ কৰক…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"আটাইবোৰ আহৰণ কৰক…"</string> <string name="menu_rename" msgid="1883113442688817554">"নতুন নাম দিয়ক"</string> <string name="menu_inspect" msgid="7279855349299446224">"তথ্য পাওক"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"লুকুৱাই থোৱা ফাইল দেখুৱাওক"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"এই মুহূৰ্তত সমল ল\'ড কৰিব নোৱাৰি"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"কৰ্মস্থানৰ এপ্সমূহ পজ কৰা আছে"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"কৰ্মস্থানৰ এপ্সমূহ অন কৰক"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> এপ্ পজ কৰা আছে"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> এপ্ অন কৰক"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"কৰ্মস্থানৰ ফাইলসমূহ বাছনি কৰিব নোৱাৰি"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"আপোনাৰ আইটি প্ৰশাসকে আপোনাক কোনো ব্যক্তিগত এপৰ পৰা কর্মস্থানৰ ফাইলসমূহলৈ এক্সেছ কৰিবলৈ অনুমতি নিদিয়ে"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"ব্যক্তিগত ফাইলসমূহ বাছনি কৰিব নোৱাৰি"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"আপোনাৰ আইটি প্ৰশাসকে আপোনাক কোনো কৰ্মস্থানৰ এপৰ পৰা ব্যক্তিগত ফাইলসমূহলৈ এক্সেছ কৰিবলৈ অনুমতি নিদিয়ে"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g>ৰ ফাইলসমূহ বাছনি কৰিব নোৱাৰি"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"আপোনাৰ আইটি প্ৰশাসকে আপোনাক কোনো <xliff:g id="PROFILE_1">%2$s</xliff:g> এপৰ পৰা <xliff:g id="PROFILE_0">%1$s</xliff:g>ৰ ফাইলসমূহ এক্সেছ কৰিবলৈ নিদিয়ে"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"কৰ্মস্থানৰ প্ৰ\'ফাইলত ছেভ কৰিব নোৱাৰি"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"আপোনাৰ আইটি প্ৰশাসকে আপোনাক আপোনাৰ কর্মস্থানৰ প্ৰ\'ফাইলত ব্যক্তিগত ফাইলসমূহ ছেভ কৰিবলৈ অনুমতি নিদিয়ে"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"ব্যক্তিগত প্ৰফাইলত ছেভ কৰিব নোৱাৰি"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"আপোনাৰ আইটি প্ৰশাসকে আপোনাক আপোনাৰ ব্যক্তিগত প্ৰ\'ফাইলত কৰ্মস্থানৰ ফাইলসমূহ ছেভ কৰিবলৈ অনুমতি নিদিয়ে"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> প্ৰ’ফাইলত ছেভ কৰিব নোৱাৰি"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"আপোনাৰ আইটি প্ৰশাসকে আপোনাক আপোনাৰ <xliff:g id="PROFILE_1">%2$s</xliff:g> প্ৰ’ফাইলত <xliff:g id="PROFILE_0">%1$s</xliff:g>ৰ ফাইলসমূহ ছেভ কৰিবলৈ নিদিয়ে"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"এই কাৰ্যটোৰ অনুমতি নাই"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"অধিক জানিবলৈ আপোনাৰ আইটি প্ৰশাসকৰ সৈতে যোগাযোগ কৰক"</string> <string name="root_recent" msgid="1080156975424341623">"শেহতীয়া"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"নতুন নাম"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g> ফাইলটো পূৰ্বদৰ্শন কৰক"</string> <string name="preview_work_file" msgid="4495643735563487273">"কৰ্মস্থানৰ ফাইলটো <xliff:g id="FILENAME">%1$s</xliff:g> পূৰ্বদৰ্শন কৰক"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g>ৰ <xliff:g id="FILENAME">%2$s</xliff:g> ফাইলটো পূৰ্বদৰ্শন কৰক"</string> <string name="apps_row_title" msgid="3340490016663092925">"অন্য এপত ফাইল ব্ৰাউজ কৰক"</string> <string name="anonymous_application" msgid="7633027057951625862">"পৰিচয়বিহীন"</string> <string name="open_tree_button" msgid="6402871398424497776">"এই ফ\'ল্ডাৰটো ব্যৱহাৰ কৰক"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"এই ফ’ল্ডাৰটো ব্যৱহাৰ কৰিব নোৱাৰি"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"আপোনাৰ গোপনীয়তা সুৰক্ষিত কৰিবলৈ অন্য এটা ফ’ল্ডাৰ বাছনি কৰক"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"নতুন ফ\'ল্ডাৰ সৃষ্টি কৰক"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"এই ফ’নটো সন্ধান কৰক"</string> + <string name="search_bar_hint" msgid="146031513183888721">"এই ডিভাইচটো সন্ধান কৰক"</string> <string name="delete_search_history" msgid="2202015025607694515">"সন্ধান ইতিহাস মচক <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"ব্যক্তিগত"</string> <string name="work_tab" msgid="7265359366883747413">"কৰ্মস্থান"</string> diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml index 440a31081..4f26eb52e 100644 --- a/res/values-az/strings.xml +++ b/res/values-az/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Daşıyın..."</string> <string name="menu_compress" msgid="37539111904724188">"Sıxışdırın"</string> <string name="menu_extract" msgid="8171946945982532262">"Çıxarın…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Hamısını çıxarın…"</string> <string name="menu_rename" msgid="1883113442688817554">"Adını dəyişdirin"</string> <string name="menu_inspect" msgid="7279855349299446224">"Məlumat əldə edin"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Gizli faylları göstərin"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Məzmun hazırda yüklənmir"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"İş tətbiqləri durdurulub"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"İş tətbiqlərini aktiv edin"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> tətbiqləri durdurulub"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> tətbiqlərini aktiv edin"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"İş faylları seçmək olmur"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"IT admininiz şəxsi tətbiqdən iş fayllarına giriş icazəsi vermir"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Şəxsi faylları seçmək olmur"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"IT admininiz iş tətbiqindən şəxsi fayllara giriş icazəsi vermir"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> fayllarını seçmək olmur"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"IT admini <xliff:g id="PROFILE_1">%2$s</xliff:g> tətbiqindən <xliff:g id="PROFILE_0">%1$s</xliff:g> fayllarına giriş icazəsi vermir"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"İş profilində saxlamaq olmur"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"IT admininiz şəxsi fayllarınızı iş profilinizdə saxlamağa icazə vermir"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Şəxsi profildə saxlamaq olmur"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"IT admininiz iş fayllarınızı şəxsi profilinizdə saxlamağa icazə vermir"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> profilində yadda saxlamaq olmur"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"IT admini <xliff:g id="PROFILE_0">%1$s</xliff:g> fayllarını <xliff:g id="PROFILE_1">%2$s</xliff:g> profilində yadda saxlamağa icazə vermir"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Bu əməliyyata icazə verilmir"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Ətraflı məlumat üçün IT admininiz ilə əlaqə saxlayın"</string> <string name="root_recent" msgid="1080156975424341623">"Son"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Yeni ad"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g> faylını önizləyin"</string> <string name="preview_work_file" msgid="4495643735563487273">"<xliff:g id="FILENAME">%1$s</xliff:g> adlı iş faylına əvvəlcədən baxın"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> faylını (<xliff:g id="FILENAME">%2$s</xliff:g>) önizləyin"</string> <string name="apps_row_title" msgid="3340490016663092925">"Faylları digər tətbiqlərdə axtarın"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonim"</string> <string name="open_tree_button" msgid="6402871398424497776">"Bu qovluğu istifadə edin"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Bu qovluğu istifadə etmək mümkün deyil"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Məxfiliyinizi qorumaq üçün başqa qovluq seçin"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Yeni qovluq yaradın"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Bu telefonu axtarın"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Bu cihazda axtarın"</string> <string name="delete_search_history" msgid="2202015025607694515">"<xliff:g id="TEXT">%1$s</xliff:g> üçün axtarış tarixçəsini silin"</string> <string name="personal_tab" msgid="3878576287868528503">"Şəxsi"</string> <string name="work_tab" msgid="7265359366883747413">"İş"</string> diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml index d0c07efcc..4399d8353 100644 --- a/res/values-b+sr+Latn/strings.xml +++ b/res/values-b+sr+Latn/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Premesti u…"</string> <string name="menu_compress" msgid="37539111904724188">"Komprimuj"</string> <string name="menu_extract" msgid="8171946945982532262">"Izdvoj u…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Izdvoji sve…"</string> <string name="menu_rename" msgid="1883113442688817554">"Preimenuj"</string> <string name="menu_inspect" msgid="7279855349299446224">"Prikaži informacije"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Prikazuj skrivene datoteke"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Učitavanje sadržaja trenutno nije moguće"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Poslovne aplikacije su pauzirane"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Uključi poslovne aplikacije"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Pauzirane su aplikacije profila: <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Uključi aplikacije profila: <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Ne možete da izaberete poslovne fajlove"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"IT administrator vam ne dozvoljava da pristupate datotekama za posao iz lične aplikacije"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Izbor ličnih datoteka nije uspeo"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"IT administrator vam ne dozvoljava da pristupate ličnim datotekama iz poslovne aplikacije"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Ne možete da izaberete fajlove sa profila: <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"IT administrator ne dozvoljava da fajlovima na profilu: <xliff:g id="PROFILE_0">%1$s</xliff:g> pristupate iz aplikacije profila: <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Ne možete da sačuvate na poslovnom profilu"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"IT administrator vam ne dozvoljava da čuvate lične datoteke na poslovnom profilu"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Ne možete da sačuvate na ličnom profilu"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"IT administrator vam ne dozvoljava da čuvate datoteke za posao na ličnom profilu"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Ne možete da čuvate na profilu: <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"IT administrator ne dozvoljava da fajlove sa profila: <xliff:g id="PROFILE_0">%1$s</xliff:g> čuvate na profilu: <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Ova radnja nije dozvoljena"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Obratite se IT administratoru da biste saznali više"</string> <string name="root_recent" msgid="1080156975424341623">"Nedavno"</string> @@ -280,7 +287,7 @@ <string name="root_info_header_image_app_with_summary" msgid="6404842960923224778">"Slike iz: <xliff:g id="LABEL">%1$s</xliff:g>/<xliff:g id="SUMMARY">%2$s</xliff:g>"</string> <string name="chip_title_images" msgid="7838299046109841015">"Slike"</string> <string name="chip_title_audio" msgid="1032801828748235436">"Zvuk"</string> - <string name="chip_title_videos" msgid="7011260091979776447">"Video snimci"</string> + <string name="chip_title_videos" msgid="7011260091979776447">"Videi"</string> <string name="chip_title_documents" msgid="7432457563000753983">"Dokumenti"</string> <string name="chip_title_large_files" msgid="7740269190493883980">"Velike datoteke"</string> <string name="chip_title_from_this_week" msgid="4961536405220379672">"Ove nedelje"</string> @@ -288,6 +295,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Novi naziv"</string> <string name="preview_file" msgid="4056622696305432343">"Pregledajte datoteku <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Pregledajte datoteku za posao <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Pregledajte fajl <xliff:g id="FILENAME">%2$s</xliff:g> sa profila: <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Pregledajte datoteke u drugim aplikacijama"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonimna"</string> <string name="open_tree_button" msgid="6402871398424497776">"Koristi ovaj folder"</string> @@ -296,7 +304,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Ne možete da koristite ovaj folder"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Da biste zaštitili privatnost, odaberite neki drugi folder"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Napravi novi folder"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Pretražite ovaj telefon"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Pretraži ovaj uređaj"</string> <string name="delete_search_history" msgid="2202015025607694515">"Izbrišite istoriju pretrage <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Lično"</string> <string name="work_tab" msgid="7265359366883747413">"Posao"</string> diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml index 344357279..723a8fbd6 100644 --- a/res/values-be/strings.xml +++ b/res/values-be/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Перамясціць у…"</string> <string name="menu_compress" msgid="37539111904724188">"Сціснуць"</string> <string name="menu_extract" msgid="8171946945982532262">"Выняць у…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Выняць усе…"</string> <string name="menu_rename" msgid="1883113442688817554">"Перайменаваць"</string> <string name="menu_inspect" msgid="7279855349299446224">"Атрымаць інфармацыю"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Паказваць схаваныя файлы"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Зараз немагчыма загрузіць змесціва"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Працоўныя праграмы прыпынены"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Уключыць працоўныя праграмы"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Праграмы тыпу \"<xliff:g id="PROFILE">%1$s</xliff:g>\" прыпынены"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Уключыць праграмы тыпу \"<xliff:g id="PROFILE">%1$s</xliff:g>\""</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Не ўдалося выбраць працоўныя файлы"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Ваш ІТ-адміністратар забараняе мець доступ да працоўных файлаў з асабістай праграмы"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Не ўдалося выбраць асабістыя файлы"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Ваш ІТ-адміністратар забараняе мець доступ да асабістых файлаў з працоўнай праграмы"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Выбіраць файлы тыпу \"<xliff:g id="PROFILE">%1$s</xliff:g>\" нельга"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"IT-адміністратар не дазваляе вам атрымліваць доступ да файлаў тыпу \"<xliff:g id="PROFILE_0">%1$s</xliff:g>\" праз праграму тыпу \"<xliff:g id="PROFILE_1">%2$s</xliff:g>\""</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Не ўдалося захаваць у працоўным профілі"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Ваш ІТ-адміністратар забараняе захоўваць асабістыя файлы ў працоўным профілі"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Не ўдалося захаваць у асабістым профілі"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Ваш ІТ-адміністратар забараняе захоўваць працоўныя файлы ў асабістым профілі"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Захоўваць файлы ў профілі тыпу \"<xliff:g id="PROFILE">%1$s</xliff:g>\" нельга"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"IT-адміністратар не дазваляе вам захоўваць у вашым профілі (тып: <xliff:g id="PROFILE_1">%2$s</xliff:g>) файлы тыпу \"<xliff:g id="PROFILE_0">%1$s</xliff:g>\""</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Недапушчальнае дзеянне"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Каб даведацца больш, звярніцеся да ІT-адміністратара"</string> <string name="root_recent" msgid="1080156975424341623">"Апошнія"</string> @@ -310,6 +317,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Новая назва"</string> <string name="preview_file" msgid="4056622696305432343">"Папярэдні прагляд файла \"<xliff:g id="FILENAME">%1$s</xliff:g>\""</string> <string name="preview_work_file" msgid="4495643735563487273">"Перадпрагляд працоўнага файла \"<xliff:g id="FILENAME">%1$s</xliff:g>\""</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Папярэдні прагляд файла тыпу \"<xliff:g id="PROFILE">%1$s</xliff:g>\", які мае назву \"<xliff:g id="FILENAME">%2$s</xliff:g>\""</string> <string name="apps_row_title" msgid="3340490016663092925">"Пошук файлаў у іншых праграмах"</string> <string name="anonymous_application" msgid="7633027057951625862">"Ананімная"</string> <string name="open_tree_button" msgid="6402871398424497776">"Выкарыстоўваць гэту папку"</string> @@ -318,7 +326,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Не ўдалося скарыстаць гэту папку"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Для аховы вашай прыватнасці выберыце іншую папку"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Стварыць новую папку"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Пошук на гэтым тэлефоне"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Пошук на гэтай прыладзе"</string> <string name="delete_search_history" msgid="2202015025607694515">"Выдаліць гісторыю пошуку <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Асабісты"</string> <string name="work_tab" msgid="7265359366883747413">"Працоўны"</string> diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml index 8f9ae67e8..7a00de0fb 100644 --- a/res/values-bg/strings.xml +++ b/res/values-bg/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Преместване във…"</string> <string name="menu_compress" msgid="37539111904724188">"Компресиране"</string> <string name="menu_extract" msgid="8171946945982532262">"Извличане в/ъв…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Извличане на всички…"</string> <string name="menu_rename" msgid="1883113442688817554">"Преименуване"</string> <string name="menu_inspect" msgid="7279855349299446224">"Получаване на информация"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Показване на скрити файлове"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Понастоящем съдържанието не може да се зареди"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Служебните приложения са поставени на пауза"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Включване на служебните приложения"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Приложенията от „<xliff:g id="PROFILE">%1$s</xliff:g>“ са поставени на пауза"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Включване на <xliff:g id="PROFILE">%1$s</xliff:g> приложения"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Избирането на служебни файлове не е възможно"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Системният ви администратор не разрешава достъпа до служебните ви файлове от лично приложение"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Избирането на лични файлове не е възможно"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Системният ви администратор не разрешава достъпа до личните ви файлове от служебно приложение"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Не можете да избирате <xliff:g id="PROFILE">%1$s</xliff:g> файлове"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Системният ви администратор не разрешава достъп до <xliff:g id="PROFILE_0">%1$s</xliff:g> файлове от <xliff:g id="PROFILE_1">%2$s</xliff:g> приложение"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Запазването в служебния потребителски профил не е възможно"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Системният ви администратор не разрешава да запазвате лични файлове в служебния си потребителски профил"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Запазването в личния потребителски профил не е възможно"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Системният ви администратор не разрешава да запазвате служебни файлове в личния си потребителски профил"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Не можете да запазвате в <xliff:g id="PROFILE">%1$s</xliff:g> потребителски профил"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Системният ви администратор не разрешава да запазвате <xliff:g id="PROFILE_0">%1$s</xliff:g> файлове в <xliff:g id="PROFILE_1">%2$s</xliff:g> потребителски профил"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Това действие не е разрешено"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"За да научите повече, обърнете се към системния си администратор"</string> <string name="root_recent" msgid="1080156975424341623">"Скорошни"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Ново име"</string> <string name="preview_file" msgid="4056622696305432343">"Визуализация на файла <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Визуализация на служебния файл <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Визуализация на <xliff:g id="PROFILE">%1$s</xliff:g> файл <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Преглед на файлове в други приложения"</string> <string name="anonymous_application" msgid="7633027057951625862">"Анонимно"</string> <string name="open_tree_button" msgid="6402871398424497776">"Използване на тази папка"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Тази папка не може да се използва"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Изберете друга папка, за да защитите поверителността си"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Създаване на нова папка"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Търсете в този телефон"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Търсете в това устройство"</string> <string name="delete_search_history" msgid="2202015025607694515">"Изтриване на <xliff:g id="TEXT">%1$s</xliff:g> от историята на търсенията"</string> <string name="personal_tab" msgid="3878576287868528503">"Лични"</string> <string name="work_tab" msgid="7265359366883747413">"Служебни"</string> diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml index 9cb1344ab..4b25ce368 100644 --- a/res/values-bn/strings.xml +++ b/res/values-bn/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"এতে সরান…"</string> <string name="menu_compress" msgid="37539111904724188">"সঙ্কুচিত করুন"</string> <string name="menu_extract" msgid="8171946945982532262">"এখানে রাখুন…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"সব এক্সট্র্যাক্ট করুন…"</string> <string name="menu_rename" msgid="1883113442688817554">"পুনঃনামকরণ"</string> <string name="menu_inspect" msgid="7279855349299446224">"তথ্য পান"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"লুকানো ফাইল দেখুন"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"এই মুহূর্তে কন্টেন্ট লোড করা যাবে না"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"অফিসের অ্যাপ পজ করা আছে"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"অফিসের অ্যাপ চালু করুন"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> অ্যাপ পজ করা হয়েছে"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> অ্যাপ চালু করুন"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"অফিসের ফাইল বেছে নেওয়া যাচ্ছে না"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"আপনার আইটি অ্যাডমিন আপনাকে ব্যক্তিগত অ্যাপ থেকে অফিসের ফাইল অ্যাক্সেস করতে দেয় না"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"ব্যক্তিগত ফাইল বেছে নেওয়া যাচ্ছে না"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"আপনার আইটি অ্যাডমিন আপনাকে অফিস অ্যাপ থেকে ব্যক্তিগত ফাইল অ্যাক্সেস করতে দেয় না"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> ফাইল বেছে নিতে পারে না"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"আপনার আইটি অ্যাডমিন আপনাকে <xliff:g id="PROFILE_1">%2$s</xliff:g> অ্যাপ থেকে <xliff:g id="PROFILE_0">%1$s</xliff:g> ফাইল অ্যাক্সেস করার অনুমতি দেয় না"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"অফিস প্রোফাইলে সেভ করা যাচ্ছে না"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"আপনার আইটি অ্যাডমিন আপনাকে অফিস প্রোফাইলে ব্যক্তিগত ফাইল সেভ করার অনুমতি দেয় না"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"ব্যক্তিগত প্রোফাইলে সেভ করা যাচ্ছে না"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"আপনার আইটি অ্যাডমিন আপনাকে ব্যক্তিগত প্রোফাইলে অফিসের ফাইল সেভ করার অনুমতি দেয় না"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> প্রোফাইলে সেভ করতে পারে না"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"আপনার আইটি অ্যাডমিন আপনার <xliff:g id="PROFILE_1">%2$s</xliff:g> প্রোফাইলে <xliff:g id="PROFILE_0">%1$s</xliff:g> ফাইল সেভ করার অনুমতি দেয় না"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"এটি করা যাবে না"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"আরও জানতে, আপনার আইটি অ্যাডমিনের সাথে যোগাযোগ করুন"</string> <string name="root_recent" msgid="1080156975424341623">"সাম্প্রতিক"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"নতুন নাম"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g> ফাইলের প্রিভিউ দেখুন"</string> <string name="preview_work_file" msgid="4495643735563487273">"<xliff:g id="FILENAME">%1$s</xliff:g> অফিস ফাইলের প্রিভিউ দেখুন"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="FILENAME">%2$s</xliff:g> <xliff:g id="PROFILE">%1$s</xliff:g> ফাইলের প্রিভিউ দেখুন"</string> <string name="apps_row_title" msgid="3340490016663092925">"অন্যান্য অ্যাপে ফাইল ব্রাউজ করুন"</string> <string name="anonymous_application" msgid="7633027057951625862">"বেনামী"</string> <string name="open_tree_button" msgid="6402871398424497776">"এই ফোল্ডার ব্যবহার করুন"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"এই ফোল্ডার ব্যবহার করা যাচ্ছে না"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"আপনার গোপনীয়তা সুরক্ষিত রাখতে, অন্য ফোল্ডার বেছে নিন"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"নতুন ফোল্ডার তৈরি করুন"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"এই ফোনে খুঁজুন"</string> + <string name="search_bar_hint" msgid="146031513183888721">"এই ডিভাইসে খুঁজুন"</string> <string name="delete_search_history" msgid="2202015025607694515">"সার্চের ইতিহাস মুছুন <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"ব্যক্তিগত"</string> <string name="work_tab" msgid="7265359366883747413">"অফিস"</string> diff --git a/res/values-bs/inspector_strings.xml b/res/values-bs/inspector_strings.xml index 1044ceb35..74b6dcc8a 100644 --- a/res/values-bs/inspector_strings.xml +++ b/res/values-bs/inspector_strings.xml @@ -32,7 +32,7 @@ <string name="metadata_altitude" msgid="8063792127436794294">"Visina"</string> <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string> <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string> - <string name="metadata_aperture" msgid="6538741952698935357">"Blenda"</string> + <string name="metadata_aperture" msgid="6538741952698935357">"Otvor blende"</string> <string name="metadata_shutter_speed" msgid="8204739885103326131">"Brzina zatvarača"</string> <string name="metadata_duration" msgid="3115494422055472715">"Trajanje"</string> <string name="metadata_date_time" msgid="1090351199248114406">"Vrijeme snimanja"</string> diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml index 3e2af1708..2564464ff 100644 --- a/res/values-bs/strings.xml +++ b/res/values-bs/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Premjesti u…"</string> <string name="menu_compress" msgid="37539111904724188">"Kompresiraj"</string> <string name="menu_extract" msgid="8171946945982532262">"Izdvoji u…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Izdvajanje svega…"</string> <string name="menu_rename" msgid="1883113442688817554">"Promijeni naziv"</string> <string name="menu_inspect" msgid="7279855349299446224">"Prikaži informacije"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Prikaži skrivene fajlove"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Trenutno nije moguće učitati sadržaj"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Poslovne aplikacije su pauzirane"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Uključi poslovne aplikacije"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Aplikacije profila <xliff:g id="PROFILE">%1$s</xliff:g> su pauzirane"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Uključi aplikacije profila \"<xliff:g id="PROFILE">%1$s</xliff:g>\""</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Nije moguće odabrati poslovne fajlove"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"IT administrator vam ne dozvoljava da pristupate poslovnim fajlovima iz lične aplikacije"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Nije moguće odabrati lične fajlove"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"IT administrator vam ne dozvoljava da pristupate ličnim fajlovima iz poslovne aplikacije"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Nije moguće odabrati fajlove s profila \"<xliff:g id="PROFILE">%1$s</xliff:g>\""</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"IT administrator vam ne dozvoljava da pristupite fajlovima s profila \"<xliff:g id="PROFILE_0">%1$s</xliff:g>\" iz aplikacije profila \"<xliff:g id="PROFILE_1">%2$s</xliff:g>\""</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Nije moguće sačuvati na radni profil"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"IT administrator vam ne dozvoljava da pohranjujete lične fajlove na radni profil"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Nije moguće sačuvati na lični profil"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"IT administrator vam ne dozvoljava da pohranjujete poslovne fajlove na lični profil"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Nije moguće sačuvati na profil \"<xliff:g id="PROFILE">%1$s</xliff:g>\""</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"IT administrator vam ne dozvoljava da sačuvate fajlove s profila \"<xliff:g id="PROFILE_0">%1$s</xliff:g>\" na profil \"<xliff:g id="PROFILE_1">%2$s</xliff:g>\""</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Ta radnja nije dopuštena"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Da saznate više, kontaktirajte IT administratora"</string> <string name="root_recent" msgid="1080156975424341623">"Nedavno"</string> @@ -288,6 +295,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Novo ime"</string> <string name="preview_file" msgid="4056622696305432343">"Pregled fajla <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Pregledajte poslovni fajl <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Pregled fajla <xliff:g id="FILENAME">%2$s</xliff:g> s profila \"<xliff:g id="PROFILE">%1$s</xliff:g>\""</string> <string name="apps_row_title" msgid="3340490016663092925">"Pretraživanje fajlova u drugim aplikacijama"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonimno"</string> <string name="open_tree_button" msgid="6402871398424497776">"Koristi ovaj folder"</string> @@ -296,7 +304,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Nije moguće koristiti ovaj folder"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Da zaštitite svoju privatnost, odaberite drugi folder"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Napravi novi folder"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Pretražite ovaj telefon"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Pretražite uređaj"</string> <string name="delete_search_history" msgid="2202015025607694515">"Izbriši historiju pretraživanja <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Lično"</string> <string name="work_tab" msgid="7265359366883747413">"Poslovno"</string> diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index fdc9ec638..3367fc94b 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Mou a…"</string> <string name="menu_compress" msgid="37539111904724188">"Comprimeix"</string> <string name="menu_extract" msgid="8171946945982532262">"Extreu a…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Extreu-ho tot…"</string> <string name="menu_rename" msgid="1883113442688817554">"Canvia el nom"</string> <string name="menu_inspect" msgid="7279855349299446224">"Obtén informació"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Mostra els fitxers amagats"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"En aquest moment no es pot carregar el contingut"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Les aplicacions de treball estan en pausa"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Activa les aplicacions de treball"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Les aplicacions d\'aquest perfil (<xliff:g id="PROFILE">%1$s</xliff:g>) s\'han posat en pausa"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Activa les aplicacions d\'aquest perfil (<xliff:g id="PROFILE">%1$s</xliff:g>)"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"No es poden seleccionar els fitxers de treball"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"L\'administrador de TI no et permet accedir als fitxers de treball des de l\'aplicació personal"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"No es poden seleccionar els fitxers personals"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"L\'administrador de TI no et permet accedir als fitxers personals des de l\'aplicació de treball"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"No es poden seleccionar fitxers d\'aquest perfil (<xliff:g id="PROFILE">%1$s</xliff:g>)"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"L\'administrador de TI no et permet accedir a fitxers d\'un perfil (<xliff:g id="PROFILE_0">%1$s</xliff:g>) des d\'una aplicació de l\'altre perfil (<xliff:g id="PROFILE_1">%2$s</xliff:g>)"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"No es pot desar al perfil de treball"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"L\'administrador de TI no et permet desar fitxers personals al teu perfil de treball"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"No es pot desar al perfil personal"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"L\'administrador de TI no et permet desar fitxers de treball al teu perfil personal"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"No es pot desar en aquest perfil (<xliff:g id="PROFILE">%1$s</xliff:g>)"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"L\'administrador de TI no et permet desar fitxers d\'un perfil (<xliff:g id="PROFILE_0">%1$s</xliff:g>) a l\'altre perfil (<xliff:g id="PROFILE_1">%2$s</xliff:g>)"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Aquesta acció no està permesa"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Per obtenir més informació, contacta amb l\'administrador de TI"</string> <string name="root_recent" msgid="1080156975424341623">"Recents"</string> @@ -214,7 +221,7 @@ <item quantity="one">S\'ha copiat <xliff:g id="COUNT_0">%1$d</xliff:g> element al porta-retalls.</item> </plurals> <string name="file_operation_rejected" msgid="4301554203329008794">"L\'operació del fitxer no s\'admet."</string> - <string name="file_operation_error" msgid="2234357335716533795">"S\'ha produït un error en l\'operació del fitxer."</string> + <string name="file_operation_error" msgid="2234357335716533795">"Hi ha hagut un error en l\'operació del fitxer."</string> <string name="rename_error" msgid="6700093173508118635">"No s\'ha pogut canviar el nom del document"</string> <string name="menu_eject_root" msgid="9215040039374893613">"Expulsa"</string> <string name="notification_copy_files_converted_title" msgid="6916768494891833365">"S\'han convertit alguns fitxers"</string> @@ -288,6 +295,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Nom nou"</string> <string name="preview_file" msgid="4056622696305432343">"Previsualitza el fitxer <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Previsualitza el fitxer de treball <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Previsualitza el fitxer <xliff:g id="FILENAME">%2$s</xliff:g> d\'aquest perfil (<xliff:g id="PROFILE">%1$s</xliff:g>)"</string> <string name="apps_row_title" msgid="3340490016663092925">"Cerca fitxers en altres aplicacions"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anònima"</string> <string name="open_tree_button" msgid="6402871398424497776">"Utilitza aquesta carpeta"</string> @@ -296,7 +304,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"No es pot utilitzar aquesta carpeta"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Per protegir la teva privadesa, tria una altra carpeta"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Crea una carpeta"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Cerca en aquest telèfon"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Cerca en aquest dispositiu"</string> <string name="delete_search_history" msgid="2202015025607694515">"Suprimeix l\'historial de cerques <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Personal"</string> <string name="work_tab" msgid="7265359366883747413">"Treball"</string> diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index 27aba7e47..d58addbf9 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Přesunout do…"</string> <string name="menu_compress" msgid="37539111904724188">"Zkomprimovat"</string> <string name="menu_extract" msgid="8171946945982532262">"Rozbalit do…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Extrahovat vše…"</string> <string name="menu_rename" msgid="1883113442688817554">"Přejmenovat"</string> <string name="menu_inspect" msgid="7279855349299446224">"Zobrazit informace"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Zobrazit skryté soubory"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Obsah teď nelze načíst"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Pracovní aplikace jsou pozastaveny"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Zapnout pracovní aplikace"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> aplikace jsou pozastaveny"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Zapnout <xliff:g id="PROFILE">%1$s</xliff:g> aplikace"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Pracovní soubory nelze vybrat"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Administrátor IT nepovoluje otevírat pracovní soubory pomocí osobní aplikace"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Osobní soubory nelze vybrat"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Administrátor IT nepovoluje otevírat osobní soubory pomocí pracovní aplikace"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> soubory nelze vybrat"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Administrátor IT nepovoluje přístup k <xliff:g id="PROFILE_0">%1$s</xliff:g> profilům z <xliff:g id="PROFILE_1">%2$s</xliff:g> aplikace"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Do pracovního profilu nelze ukládat"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Administrátor IT nepovoluje ukládat osobní soubory do pracovního profilu"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Do osobního profilu nelze ukládat"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Administrátor IT nepovoluje ukládat pracovní soubory do osobního profilu"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Do <xliff:g id="PROFILE">%1$s</xliff:g> profilu nelze ukládat"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Administrátor IT nepovoluje ukládat <xliff:g id="PROFILE_0">%1$s</xliff:g> soubory do <xliff:g id="PROFILE_1">%2$s</xliff:g> profilu"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Tato akce není povolena"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Další informace vám poskytne administrátor IT"</string> <string name="root_recent" msgid="1080156975424341623">"Nedávné"</string> @@ -310,6 +317,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Nový název"</string> <string name="preview_file" msgid="4056622696305432343">"Zobrazit náhled souboru <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Náhled pracovního souboru <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Zobrazit náhled <xliff:g id="PROFILE">%1$s</xliff:g> souboru <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Procházet soubory v ostatních aplikacích"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonymní"</string> <string name="open_tree_button" msgid="6402871398424497776">"Použít tuto složku"</string> @@ -318,7 +326,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Tuto složku nelze použít"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Z důvodu ochrany soukromí zvolte jinou složku"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Vytvořit novou složku"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Hledat v telefonu"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Prohledat tohle zařízení"</string> <string name="delete_search_history" msgid="2202015025607694515">"Vymazat historii vyhledávání <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Osobní"</string> <string name="work_tab" msgid="7265359366883747413">"Pracovní"</string> diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index bd7d89d4b..facc58ba5 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Flyt til…"</string> <string name="menu_compress" msgid="37539111904724188">"Komprimer"</string> <string name="menu_extract" msgid="8171946945982532262">"Pak ud i…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Pak alle ud…"</string> <string name="menu_rename" msgid="1883113442688817554">"Omdøb"</string> <string name="menu_inspect" msgid="7279855349299446224">"Få oplysninger"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Vis skjulte filer"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Der kan ikke indlæses indhold i øjeblikket"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Dine arbejdsapps er sat på pause"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Aktivér arbejdsapps"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g>-apps er sat på pause"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Aktivér <xliff:g id="PROFILE">%1$s</xliff:g>-apps"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Arbejdsfiler kan ikke vælges"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Din it-administrator har ikke givet dig tilladelse til at åbne arbejdsfiler fra en personlig app"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Personlige filer kan ikke vælges"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Din it-administrator har ikke givet dig tilladelse til at åbne personlige filer fra en arbejdsapp"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Kan ikke vælge <xliff:g id="PROFILE">%1$s</xliff:g>-filer"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Din it-administrator tillader ikke, at du tilgår <xliff:g id="PROFILE_0">%1$s</xliff:g>-filer via en <xliff:g id="PROFILE_1">%2$s</xliff:g> app"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Filerne kan ikke gemmes på din arbejdsprofil"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Din it-administrator har ikke givet dig tilladelse til at gemme personlige filer på din arbejdsprofil"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Filerne kan ikke gemmes på den personlige profil"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Din it-administrator har ikke givet dig tilladelse til at gemme arbejdsfiler på din personlige profil"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Kan ikke gemme i <xliff:g id="PROFILE">%1$s</xliff:g>-profil"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Din it-administrator tillader ikke, at du gemmer <xliff:g id="PROFILE_0">%1$s</xliff:g> filer på din <xliff:g id="PROFILE_1">%2$s</xliff:g>-profil"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Denne handling er ikke tilladt"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Kontakt din it-administrator for at få flere oplysninger"</string> <string name="root_recent" msgid="1080156975424341623">"Seneste"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Nyt navn"</string> <string name="preview_file" msgid="4056622696305432343">"Se forhåndsvisning af filen <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Se en forhåndsvisning af arbejdsfilen <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Se forhåndsvisning af <xliff:g id="PROFILE">%1$s</xliff:g>-filen <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Gennemse filer i andre apps"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonym"</string> <string name="open_tree_button" msgid="6402871398424497776">"Brug denne mappe"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Denne mappe kan ikke bruges"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"For at beskytte dit privatliv skal du vælge en anden mappe"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Opret ny mappe"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Søg på denne telefon"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Søg på denne enhed"</string> <string name="delete_search_history" msgid="2202015025607694515">"Slet søgehistorikken <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Personlig"</string> <string name="work_tab" msgid="7265359366883747413">"Arbejde"</string> diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 978822db8..0b7943238 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Verschieben nach…"</string> <string name="menu_compress" msgid="37539111904724188">"Komprimieren"</string> <string name="menu_extract" msgid="8171946945982532262">"Extrahieren nach…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Alle extrahieren…"</string> <string name="menu_rename" msgid="1883113442688817554">"Umbenennen"</string> <string name="menu_inspect" msgid="7279855349299446224">"Weitere Informationen"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Ausgeblendete Dateien anzeigen"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Inhalte können momentan nicht geladen werden"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Geschäftliche Apps sind pausiert"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Geschäftliche Apps aktivieren"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Apps aus dem Profil „<xliff:g id="PROFILE">%1$s</xliff:g>“ sind pausiert"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Apps aus dem Profil „<xliff:g id="PROFILE">%1$s</xliff:g>“ aktivieren"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Auswahl geschäftlicher Dateien nicht möglich"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Dein IT-Administrator hat festgelegt, dass du geschäftliche Dateien nicht mit einer privaten App aufrufen darfst"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Auswahl persönlicher Dateien nicht möglich"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Dein IT-Administrator hat festgelegt, dass du persönliche Dateien nicht mit einer geschäftlichen App aufrufen darfst"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Auswahl von Dateien aus dem Profil „<xliff:g id="PROFILE">%1$s</xliff:g>“ nicht möglich"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Dein IT-Administrator lässt den Zugriff auf Dateien aus dem Profil „<xliff:g id="PROFILE_0">%1$s</xliff:g>“ aus einer App „<xliff:g id="PROFILE_1">%2$s</xliff:g>“ nicht zu"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Speichern im Arbeitsprofil nicht möglich"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Dein IT-Administrator hat festgelegt, dass du persönliche Dateien nicht in deinem Arbeitsprofil speichern darfst"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Speichern im privaten Profil nicht möglich"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Dein IT-Administrator hat festgelegt, dass du geschäftliche Dateien nicht in deinem privaten Profil speichern darfst"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Speichern im Profil „<xliff:g id="PROFILE">%1$s</xliff:g>“ nicht möglich"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Dein IT-Administrator lässt das Speichern von Dateien aus dem Profil „<xliff:g id="PROFILE_0">%1$s</xliff:g>“ in deinem Profil „<xliff:g id="PROFILE_1">%2$s</xliff:g>“ nicht zu"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Diese Aktion ist nicht zulässig"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Wenn du mehr wissen möchtest, wende dich bitte an deinen IT-Administrator"</string> <string name="root_recent" msgid="1080156975424341623">"Zuletzt verwendet"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Neuer Name"</string> <string name="preview_file" msgid="4056622696305432343">"Datei \"<xliff:g id="FILENAME">%1$s</xliff:g>\" als Vorschau ansehen"</string> <string name="preview_work_file" msgid="4495643735563487273">"Vorschau der geschäftlichen Datei \"<xliff:g id="FILENAME">%1$s</xliff:g>\""</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Datei „<xliff:g id="FILENAME">%2$s</xliff:g>“ aus dem Profil „<xliff:g id="PROFILE">%1$s</xliff:g>“ als Vorschau ansehen"</string> <string name="apps_row_title" msgid="3340490016663092925">"Dateien in anderen Apps ansehen"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonym"</string> <string name="open_tree_button" msgid="6402871398424497776">"Diesen Ordner verwenden"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Dieser Ordner kann nicht verwendet werden"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Zum Schutz deiner Daten einen anderen Ordner auswählen"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Neuen Ordner erstellen"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Auf diesem Smartphone suchen"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Auf diesem Gerät suchen"</string> <string name="delete_search_history" msgid="2202015025607694515">"<xliff:g id="TEXT">%1$s</xliff:g>-Suchverlauf löschen"</string> <string name="personal_tab" msgid="3878576287868528503">"Privat"</string> <string name="work_tab" msgid="7265359366883747413">"Geschäftlich"</string> diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml index 99d9f85a0..706630dda 100644 --- a/res/values-el/strings.xml +++ b/res/values-el/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Μετακίνηση σε…"</string> <string name="menu_compress" msgid="37539111904724188">"Συμπίεση"</string> <string name="menu_extract" msgid="8171946945982532262">"Εξαγωγή σε…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Εξαγωγή όλων…"</string> <string name="menu_rename" msgid="1883113442688817554">"Μετονομασία"</string> <string name="menu_inspect" msgid="7279855349299446224">"Λήψη πληροφοριών"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Εμφάνιση κρυφών αρχείων"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Δεν είναι δυνατή η φόρτωση περιεχομένου τώρα"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Οι εφαρμογές εργασίας τέθηκαν σε παύση"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Ενεργοποίηση εφαρμογών εργασιών"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Οι εφαρμογές του προφίλ <xliff:g id="PROFILE">%1$s</xliff:g> έχουν τεθεί σε παύση"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Ενεργοποίηση εφαρμογών του προφίλ <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Δεν είναι δυνατή η επιλογή αρχείων εργασίας."</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Ο διαχειριστής δεν επιτρέπει την πρόσβαση σε αρχεία εργασίας από μια προσωπική εφαρμογή."</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Δεν είναι δυνατή η επιλογή προσωπικών αρχείων."</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Ο διαχειριστής ΙΤ δεν επιτρέπει την πρόσβαση σε προσωπικά αρχεία από μια εφαρμογή εργασιών."</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Δεν είναι δυνατή η επιλογή αρχείων του προφίλ <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Ο διαχειριστής IT δεν επιτρέπει την πρόσβαση σε αρχεία του προφίλ <xliff:g id="PROFILE_0">%1$s</xliff:g> από μια εφαρμογή του προφίλ <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Δεν είναι δυνατή η αποθήκευση στο προφίλ εργασίας."</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Ο διαχειριστής IT δεν επιτρέπει την αποθήκευση προσωπικών αρχείων στο προφίλ εργασίας σας."</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Δεν είναι δυνατή η αποθήκευση στο προσωπικό σας προφίλ."</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Ο διαχειριστής ΙΤ δεν επιτρέπει την αποθήκευση αρχείων εργασίας στο προσωπικό σας προφίλ."</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Δεν είναι δυνατή η αποθήκευση του προφίλ <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Ο διαχειριστής IT δεν επιτρέπει την αποθήκευση αρχείων του προφίλ <xliff:g id="PROFILE_0">%1$s</xliff:g> στο προφίλ <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Η συγκεκριμένη ενέργεια δεν επιτρέπεται."</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Για να μάθετε περισσότερα, επικοινωνήστε με τον διαχειριστή IT."</string> <string name="root_recent" msgid="1080156975424341623">"Πρόσφατα"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Νέο όνομα"</string> <string name="preview_file" msgid="4056622696305432343">"Προεπισκόπηση του αρχείου <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Προεπισκόπηση του αρχείου εργασίας <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Προεπισκόπηση του αρχείου <xliff:g id="FILENAME">%2$s</xliff:g> του προφίλ <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Αναζήτηση αρχείων σε άλλες εφαρμογές"</string> <string name="anonymous_application" msgid="7633027057951625862">"Ανώνυμη"</string> <string name="open_tree_button" msgid="6402871398424497776">"Χρήση αυτού του φακέλου"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Δεν είναι δυνατή η χρήση αυτού του φακέλου"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Για την προστασία του απορρήτου σας, επιλέξτε άλλο φάκελο"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Δημιουργία νέου φακέλου"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Αναζήτηση σε αυτό το τηλέφωνο"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Αναζήτηση σε αυτή τη συσκευή"</string> <string name="delete_search_history" msgid="2202015025607694515">"Διαγραφή ιστορικού αναζήτησης <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Προσωπικός"</string> <string name="work_tab" msgid="7265359366883747413">"Εργασίας"</string> diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml index c05071bff..ad4cbfeea 100644 --- a/res/values-en-rAU/strings.xml +++ b/res/values-en-rAU/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Move to…"</string> <string name="menu_compress" msgid="37539111904724188">"Compress"</string> <string name="menu_extract" msgid="8171946945982532262">"Extract to…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Extract all…"</string> <string name="menu_rename" msgid="1883113442688817554">"Rename"</string> <string name="menu_inspect" msgid="7279855349299446224">"Get info"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Show hidden files"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Can’t load content at the moment"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Work apps are paused"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Turn on work apps"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> apps are paused"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Turn on <xliff:g id="PROFILE">%1$s</xliff:g> apps"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Can’t select work files"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Your IT admin doesn’t allow you to access work files from a personal app"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Can’t select personal files"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Your IT admin doesn’t allow you to access personal files from a work app"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Can\'t select <xliff:g id="PROFILE">%1$s</xliff:g> files"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Your IT admin doesn\'t allow you to access <xliff:g id="PROFILE_0">%1$s</xliff:g> files from a <xliff:g id="PROFILE_1">%2$s</xliff:g> app"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Can’t save to work profile"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Your IT admin doesn’t allow you to save personal files to your work profile"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Can’t save to personal profile"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Your IT admin doesn’t allow you to save work files to your personal profile"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Can\'t save to <xliff:g id="PROFILE">%1$s</xliff:g> profile"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Your IT admin doesn\'t allow you to save <xliff:g id="PROFILE_0">%1$s</xliff:g> files to your <xliff:g id="PROFILE_1">%2$s</xliff:g> profile"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"This action isn’t allowed"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"To learn more, contact your IT admin"</string> <string name="root_recent" msgid="1080156975424341623">"Recent"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"New name"</string> <string name="preview_file" msgid="4056622696305432343">"Preview the file <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Preview the work file <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Preview the <xliff:g id="PROFILE">%1$s</xliff:g> file <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Browse files in other apps"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonymous"</string> <string name="open_tree_button" msgid="6402871398424497776">"Use this folder"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Can’t use this folder"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"To protect your privacy, choose another folder"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Create new folder"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Search this phone"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Search this device"</string> <string name="delete_search_history" msgid="2202015025607694515">"Delete search history <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Personal"</string> <string name="work_tab" msgid="7265359366883747413">"Work"</string> diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml index d3d6da177..df51b525d 100644 --- a/res/values-en-rCA/strings.xml +++ b/res/values-en-rCA/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Move to…"</string> <string name="menu_compress" msgid="37539111904724188">"Compress"</string> <string name="menu_extract" msgid="8171946945982532262">"Extract to…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Extract all…"</string> <string name="menu_rename" msgid="1883113442688817554">"Rename"</string> <string name="menu_inspect" msgid="7279855349299446224">"Get info"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Show hidden files"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Can’t load content at the moment"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Work apps are paused"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Turn on work apps"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> apps are paused"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Turn on <xliff:g id="PROFILE">%1$s</xliff:g> apps"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Can’t select work files"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Your IT admin doesn’t allow you to access work files from a personal app"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Can’t select personal files"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Your IT admin doesn’t allow you to access personal files from a work app"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Can’t select <xliff:g id="PROFILE">%1$s</xliff:g> files"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Your IT admin doesn’t allow you to access <xliff:g id="PROFILE_0">%1$s</xliff:g> files from a <xliff:g id="PROFILE_1">%2$s</xliff:g> app"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Can’t save to work profile"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Your IT admin doesn’t allow you to save personal files to your work profile"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Can’t save to personal profile"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Your IT admin doesn’t allow you to save work files to your personal profile"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Can’t save to <xliff:g id="PROFILE">%1$s</xliff:g> profile"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Your IT admin doesn’t allow you to save <xliff:g id="PROFILE_0">%1$s</xliff:g> files to your <xliff:g id="PROFILE_1">%2$s</xliff:g> profile"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"This action isn’t allowed"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"To learn more, contact your IT admin"</string> <string name="root_recent" msgid="1080156975424341623">"Recent"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"New name"</string> <string name="preview_file" msgid="4056622696305432343">"Preview the file <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Preview the work file <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Preview the <xliff:g id="PROFILE">%1$s</xliff:g> file <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Browse files in other apps"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonymous"</string> <string name="open_tree_button" msgid="6402871398424497776">"Use this folder"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Can’t use this folder"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"To protect your privacy, choose another folder"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Create new folder"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Search this phone"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Search this device"</string> <string name="delete_search_history" msgid="2202015025607694515">"Delete search history <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Personal"</string> <string name="work_tab" msgid="7265359366883747413">"Work"</string> diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml index c05071bff..ad4cbfeea 100644 --- a/res/values-en-rGB/strings.xml +++ b/res/values-en-rGB/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Move to…"</string> <string name="menu_compress" msgid="37539111904724188">"Compress"</string> <string name="menu_extract" msgid="8171946945982532262">"Extract to…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Extract all…"</string> <string name="menu_rename" msgid="1883113442688817554">"Rename"</string> <string name="menu_inspect" msgid="7279855349299446224">"Get info"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Show hidden files"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Can’t load content at the moment"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Work apps are paused"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Turn on work apps"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> apps are paused"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Turn on <xliff:g id="PROFILE">%1$s</xliff:g> apps"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Can’t select work files"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Your IT admin doesn’t allow you to access work files from a personal app"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Can’t select personal files"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Your IT admin doesn’t allow you to access personal files from a work app"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Can\'t select <xliff:g id="PROFILE">%1$s</xliff:g> files"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Your IT admin doesn\'t allow you to access <xliff:g id="PROFILE_0">%1$s</xliff:g> files from a <xliff:g id="PROFILE_1">%2$s</xliff:g> app"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Can’t save to work profile"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Your IT admin doesn’t allow you to save personal files to your work profile"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Can’t save to personal profile"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Your IT admin doesn’t allow you to save work files to your personal profile"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Can\'t save to <xliff:g id="PROFILE">%1$s</xliff:g> profile"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Your IT admin doesn\'t allow you to save <xliff:g id="PROFILE_0">%1$s</xliff:g> files to your <xliff:g id="PROFILE_1">%2$s</xliff:g> profile"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"This action isn’t allowed"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"To learn more, contact your IT admin"</string> <string name="root_recent" msgid="1080156975424341623">"Recent"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"New name"</string> <string name="preview_file" msgid="4056622696305432343">"Preview the file <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Preview the work file <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Preview the <xliff:g id="PROFILE">%1$s</xliff:g> file <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Browse files in other apps"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonymous"</string> <string name="open_tree_button" msgid="6402871398424497776">"Use this folder"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Can’t use this folder"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"To protect your privacy, choose another folder"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Create new folder"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Search this phone"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Search this device"</string> <string name="delete_search_history" msgid="2202015025607694515">"Delete search history <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Personal"</string> <string name="work_tab" msgid="7265359366883747413">"Work"</string> diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml index c05071bff..ad4cbfeea 100644 --- a/res/values-en-rIN/strings.xml +++ b/res/values-en-rIN/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Move to…"</string> <string name="menu_compress" msgid="37539111904724188">"Compress"</string> <string name="menu_extract" msgid="8171946945982532262">"Extract to…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Extract all…"</string> <string name="menu_rename" msgid="1883113442688817554">"Rename"</string> <string name="menu_inspect" msgid="7279855349299446224">"Get info"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Show hidden files"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Can’t load content at the moment"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Work apps are paused"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Turn on work apps"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> apps are paused"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Turn on <xliff:g id="PROFILE">%1$s</xliff:g> apps"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Can’t select work files"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Your IT admin doesn’t allow you to access work files from a personal app"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Can’t select personal files"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Your IT admin doesn’t allow you to access personal files from a work app"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Can\'t select <xliff:g id="PROFILE">%1$s</xliff:g> files"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Your IT admin doesn\'t allow you to access <xliff:g id="PROFILE_0">%1$s</xliff:g> files from a <xliff:g id="PROFILE_1">%2$s</xliff:g> app"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Can’t save to work profile"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Your IT admin doesn’t allow you to save personal files to your work profile"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Can’t save to personal profile"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Your IT admin doesn’t allow you to save work files to your personal profile"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Can\'t save to <xliff:g id="PROFILE">%1$s</xliff:g> profile"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Your IT admin doesn\'t allow you to save <xliff:g id="PROFILE_0">%1$s</xliff:g> files to your <xliff:g id="PROFILE_1">%2$s</xliff:g> profile"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"This action isn’t allowed"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"To learn more, contact your IT admin"</string> <string name="root_recent" msgid="1080156975424341623">"Recent"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"New name"</string> <string name="preview_file" msgid="4056622696305432343">"Preview the file <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Preview the work file <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Preview the <xliff:g id="PROFILE">%1$s</xliff:g> file <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Browse files in other apps"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonymous"</string> <string name="open_tree_button" msgid="6402871398424497776">"Use this folder"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Can’t use this folder"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"To protect your privacy, choose another folder"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Create new folder"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Search this phone"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Search this device"</string> <string name="delete_search_history" msgid="2202015025607694515">"Delete search history <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Personal"</string> <string name="work_tab" msgid="7265359366883747413">"Work"</string> diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml index f4089322c..b3abdd19d 100644 --- a/res/values-en-rXC/strings.xml +++ b/res/values-en-rXC/strings.xml @@ -94,14 +94,20 @@ <string name="query_error" msgid="6625421453613879336">"Can’t load content at the moment"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Work apps are paused"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Turn on work apps"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> apps are paused"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Turn on <xliff:g id="PROFILE">%1$s</xliff:g> apps"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Can’t select work files"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Your IT admin doesn’t allow you to access work files from a personal app"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Can’t select personal files"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Your IT admin doesn’t allow you to access personal files from a work app"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Can’t select <xliff:g id="PROFILE">%1$s</xliff:g> files"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Your IT admin doesn’t allow you to access <xliff:g id="PROFILE_0">%1$s</xliff:g> files from a <xliff:g id="PROFILE_1">%2$s</xliff:g> app"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Can’t save to work profile"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Your IT admin doesn’t allow you to save personal files to your work profile"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Can’t save to personal profile"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Your IT admin doesn’t allow you to save work files to your personal profile"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Can’t save to <xliff:g id="PROFILE">%1$s</xliff:g> profile"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Your IT admin doesn’t allow you to save <xliff:g id="PROFILE_0">%1$s</xliff:g> files to your <xliff:g id="PROFILE_1">%2$s</xliff:g> profile"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"This action isn’t allowed"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"To learn more, contact your IT admin"</string> <string name="root_recent" msgid="1080156975424341623">"Recent"</string> @@ -266,6 +272,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"New name"</string> <string name="preview_file" msgid="4056622696305432343">"Preview the file <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Preview the work file <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Preview the <xliff:g id="PROFILE">%1$s</xliff:g> file <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Browse files in other apps"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonymous"</string> <string name="open_tree_button" msgid="6402871398424497776">"Use this folder"</string> @@ -274,7 +281,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Can’t use this folder"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"To protect your privacy, choose another folder"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Create new folder"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Search this phone"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Search this device"</string> <string name="delete_search_history" msgid="2202015025607694515">"Delete search history <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Personal"</string> <string name="work_tab" msgid="7265359366883747413">"Work"</string> diff --git a/res/values-es-rUS/inspector_strings.xml b/res/values-es-rUS/inspector_strings.xml index f35859315..a5a479ca4 100644 --- a/res/values-es-rUS/inspector_strings.xml +++ b/res/values-es-rUS/inspector_strings.xml @@ -18,7 +18,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="inspector_title" msgid="1924760928091740238">"Información"</string> <string name="inspector_load_error" msgid="7522190243413249291">"No se pudo cargar la información del archivo"</string> - <string name="inspector_debug_section" msgid="2576052661505700421">"Información de depuración (solo programadores)"</string> + <string name="inspector_debug_section" msgid="2576052661505700421">"Información de depuración (solo desarrolladores)"</string> <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Metadatos RAW: <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string> <string name="inspector_metadata_section" msgid="6077622515328240575">"Detalles del contenido multimedia"</string> <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Este tipo de archivo se abre con"</string> diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index 39bd73fb2..c5ce3eb95 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -30,7 +30,7 @@ <string name="menu_grid" msgid="1453636521731880680">"Vista de cuadrícula"</string> <string name="menu_list" msgid="6714267452146410402">"Vista de lista"</string> <string name="menu_search" msgid="1876699106790719849">"Buscar"</string> - <string name="menu_settings" msgid="6520844520117939047">"Opciones almacenamiento"</string> + <string name="menu_settings" msgid="6520844520117939047">"Opciones de almacenamiento"</string> <string name="menu_open" msgid="9092138100049759315">"Abrir"</string> <string name="menu_open_with" msgid="5507647065467520229">"Abrir con"</string> <string name="menu_open_in_new_window" msgid="6686563636123311276">"Abrir en ventana nueva"</string> @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Mover a…"</string> <string name="menu_compress" msgid="37539111904724188">"Comprimir"</string> <string name="menu_extract" msgid="8171946945982532262">"Extraer en…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Extraer todo…"</string> <string name="menu_rename" msgid="1883113442688817554">"Cambiar nombre"</string> <string name="menu_inspect" msgid="7279855349299446224">"Obtener información"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Mostrar archivos ocultos"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"No se puede cargar el contenido en este momento"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Las apps de trabajo están detenidas"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Activa las apps de trabajo"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Se pausaron las apps de <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Activar apps de <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"No se pueden seleccionar archivos de trabajo"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Tu administrador de TI no te permite acceder a archivos de trabajo desde una app personal."</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"No se pueden seleccionar archivos personales"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Tu administrador de TI no te permite acceder a archivos personales desde una app de trabajo."</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"No se pueden seleccionar archivos <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Tu administrador de TI no permite que accedas a los archivos <xliff:g id="PROFILE_0">%1$s</xliff:g> desde una app <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"No se puede guardar en el perfil de trabajo"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Tu administrador de TI no te permite guardar archivos personales en el perfil de trabajo."</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"No se puede guardar en el perfil personal"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Tu administrador de TI no te permite guardar archivos de trabajo en el perfil personal."</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"No se puede guardar en tu perfil <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Tu administrador de TI no permite que guardes archivos <xliff:g id="PROFILE_0">%1$s</xliff:g> en el perfil de <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Esta acción no está permitida."</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Para obtener más información, comunícate con tu administrador de TI."</string> <string name="root_recent" msgid="1080156975424341623">"Recientes"</string> @@ -125,29 +132,29 @@ <string name="delete_notification_title" msgid="2512757431856830792">"Borrando los archivos"</string> <string name="copy_remaining" msgid="5390517377265177727">"<xliff:g id="DURATION">%s</xliff:g> restantes"</string> <plurals name="copy_begin" formatted="false" msgid="151184708996738192"> - <item quantity="many">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> elementos</item> - <item quantity="other">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> elementos</item> - <item quantity="one">Copiando <xliff:g id="COUNT_0">%1$d</xliff:g> elemento</item> + <item quantity="many">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> de elementos.</item> + <item quantity="other">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> elementos.</item> + <item quantity="one">Copiando <xliff:g id="COUNT_0">%1$d</xliff:g> elemento.</item> </plurals> <plurals name="compress_begin" formatted="false" msgid="3534158317098678895"> - <item quantity="many">Comprimiendo <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item> - <item quantity="other">Comprimiendo <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item> - <item quantity="one">Comprimiendo <xliff:g id="COUNT_0">%1$d</xliff:g> archivo</item> + <item quantity="many">Comprimiendo <xliff:g id="COUNT_1">%1$d</xliff:g> de archivos.</item> + <item quantity="other">Comprimiendo <xliff:g id="COUNT_1">%1$d</xliff:g> archivos.</item> + <item quantity="one">Comprimiendo <xliff:g id="COUNT_0">%1$d</xliff:g> archivo.</item> </plurals> <plurals name="extract_begin" formatted="false" msgid="1006380679562903749"> - <item quantity="many">Extrayendo <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item> - <item quantity="other">Extrayendo <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item> - <item quantity="one">Extrayendo <xliff:g id="COUNT_0">%1$d</xliff:g> archivo</item> + <item quantity="many">Extrayendo <xliff:g id="COUNT_1">%1$d</xliff:g> de archivos.</item> + <item quantity="other">Extrayendo <xliff:g id="COUNT_1">%1$d</xliff:g> archivos.</item> + <item quantity="one">Extrayendo <xliff:g id="COUNT_0">%1$d</xliff:g> archivo.</item> </plurals> <plurals name="move_begin" formatted="false" msgid="1464229874265756956"> - <item quantity="many">Moviendo <xliff:g id="COUNT_1">%1$d</xliff:g> elementos</item> - <item quantity="other">Moviendo <xliff:g id="COUNT_1">%1$d</xliff:g> elementos</item> - <item quantity="one">Moviendo <xliff:g id="COUNT_0">%1$d</xliff:g> elemento</item> + <item quantity="many">Moviendo <xliff:g id="COUNT_1">%1$d</xliff:g> de elementos.</item> + <item quantity="other">Moviendo <xliff:g id="COUNT_1">%1$d</xliff:g> elementos.</item> + <item quantity="one">Moviendo <xliff:g id="COUNT_0">%1$d</xliff:g> elemento.</item> </plurals> <plurals name="deleting" formatted="false" msgid="1729138001178158901"> - <item quantity="many">Borrando <xliff:g id="COUNT_1">%1$d</xliff:g> elementos</item> - <item quantity="other">Borrando <xliff:g id="COUNT_1">%1$d</xliff:g> elementos</item> - <item quantity="one">Borrando <xliff:g id="COUNT_0">%1$d</xliff:g> elemento</item> + <item quantity="many">Borrando <xliff:g id="COUNT_1">%1$d</xliff:g> de elementos.</item> + <item quantity="other">Borrando <xliff:g id="COUNT_1">%1$d</xliff:g> elementos.</item> + <item quantity="one">Borrando <xliff:g id="COUNT_0">%1$d</xliff:g> elemento.</item> </plurals> <string name="undo" msgid="2902438994196400565">"Deshacer"</string> <string name="copy_preparing" msgid="4759516490222449324">"Preparando…"</string> @@ -157,22 +164,22 @@ <string name="delete_preparing" msgid="7339349837842802508">"Preparando…"</string> <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string> <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963"> - <item quantity="many">No se pudieron copiar <xliff:g id="COUNT_1">%1$d</xliff:g> elementos</item> + <item quantity="many">No se pudieron copiar <xliff:g id="COUNT_1">%1$d</xliff:g> de elementos</item> <item quantity="other">No se pudieron copiar <xliff:g id="COUNT_1">%1$d</xliff:g> elementos</item> <item quantity="one">No se pudo copiar <xliff:g id="COUNT_0">%1$d</xliff:g> elemento</item> </plurals> <plurals name="compress_error_notification_title" formatted="false" msgid="3043630066678213644"> - <item quantity="many">No fue posible comprimir <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item> - <item quantity="other">No fue posible comprimir <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item> - <item quantity="one">No fue posible comprimir <xliff:g id="COUNT_0">%1$d</xliff:g> archivo</item> + <item quantity="many">No se pudieron comprimir <xliff:g id="COUNT_1">%1$d</xliff:g> de archivos</item> + <item quantity="other">No se pudieron comprimir <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item> + <item quantity="one">No se pudo comprimir <xliff:g id="COUNT_0">%1$d</xliff:g> archivo</item> </plurals> <plurals name="move_error_notification_title" formatted="false" msgid="2185736082411854754"> - <item quantity="many">No se pudieron mover <xliff:g id="COUNT_1">%1$d</xliff:g> elementos</item> + <item quantity="many">No se pudieron mover <xliff:g id="COUNT_1">%1$d</xliff:g> de elementos</item> <item quantity="other">No se pudieron mover <xliff:g id="COUNT_1">%1$d</xliff:g> elementos</item> <item quantity="one">No se pudo mover <xliff:g id="COUNT_0">%1$d</xliff:g> elemento</item> </plurals> <plurals name="delete_error_notification_title" formatted="false" msgid="7568122018481625267"> - <item quantity="many">No se pudieron borrar <xliff:g id="COUNT_1">%1$d</xliff:g> elementos</item> + <item quantity="many">No se pudieron borrar <xliff:g id="COUNT_1">%1$d</xliff:g> de elementos</item> <item quantity="other">No se pudieron borrar <xliff:g id="COUNT_1">%1$d</xliff:g> elementos</item> <item quantity="one">No se pudo borrar <xliff:g id="COUNT_0">%1$d</xliff:g> elemento</item> </plurals> @@ -189,9 +196,9 @@ <item quantity="one">No se comprimió el siguiente archivo: <xliff:g id="LIST_0">%1$s</xliff:g></item> </plurals> <plurals name="extract_failure_alert_content" formatted="false" msgid="7572748127571720803"> - <item quantity="many">No se extrajeron los siguientes archivos: <xliff:g id="LIST_1">%1$s</xliff:g></item> - <item quantity="other">No se extrajeron los siguientes archivos: <xliff:g id="LIST_1">%1$s</xliff:g></item> - <item quantity="one">No se extrajo el siguiente archivo: <xliff:g id="LIST_0">%1$s</xliff:g></item> + <item quantity="many">No se extrajeron estos archivos: <xliff:g id="LIST_1">%1$s</xliff:g></item> + <item quantity="other">No se extrajeron estos archivos: <xliff:g id="LIST_1">%1$s</xliff:g></item> + <item quantity="one">No se extrajo este archivo: <xliff:g id="LIST_0">%1$s</xliff:g></item> </plurals> <plurals name="move_failure_alert_content" formatted="false" msgid="2747390342670799196"> <item quantity="many">No se movieron los siguientes archivos: <xliff:g id="LIST_1">%1$s</xliff:g></item> @@ -204,9 +211,9 @@ <item quantity="one">No se borró el siguiente archivo: <xliff:g id="LIST_0">%1$s</xliff:g></item> </plurals> <plurals name="copy_converted_warning_content" formatted="false" msgid="7433742181712126588"> - <item quantity="many">Los siguientes archivos se convirtieron a otro formato: <xliff:g id="LIST_1">%1$s</xliff:g></item> - <item quantity="other">Los siguientes archivos se convirtieron a otro formato: <xliff:g id="LIST_1">%1$s</xliff:g></item> - <item quantity="one">El siguiente archivo se convirtió a otro formato: <xliff:g id="LIST_0">%1$s</xliff:g></item> + <item quantity="many">Estos archivos se convirtieron a otro formato: <xliff:g id="LIST_1">%1$s</xliff:g></item> + <item quantity="other">Estos archivos se convirtieron a otro formato: <xliff:g id="LIST_1">%1$s</xliff:g></item> + <item quantity="one">Este archivo se convirtió a otro formato: <xliff:g id="LIST_0">%1$s</xliff:g></item> </plurals> <plurals name="clipboard_files_clipped" formatted="false" msgid="4847061634862926902"> <item quantity="many">Se copiaron <xliff:g id="COUNT_1">%1$d</xliff:g> elementos al portapapeles.</item> @@ -236,19 +243,19 @@ <string name="delete_filename_confirmation_message" msgid="8338069763240613258">"¿Deseas borrar el archivo \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string> <string name="delete_foldername_confirmation_message" msgid="9084085260877704140">"¿Deseas borrar la carpeta \"<xliff:g id="NAME">%1$s</xliff:g>\" y su contenido?"</string> <plurals name="delete_files_confirmation_message" formatted="false" msgid="4866664063250034142"> - <item quantity="many">¿Deseas borrar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos?</item> - <item quantity="other">¿Deseas borrar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos?</item> - <item quantity="one">¿Deseas borrar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo?</item> + <item quantity="many">¿Quieres borrar <xliff:g id="COUNT_1">%1$d</xliff:g> de archivos?</item> + <item quantity="other">¿Quieres borrar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos?</item> + <item quantity="one">¿Quieres borrar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo?</item> </plurals> <plurals name="delete_folders_confirmation_message" formatted="false" msgid="1028946402799686388"> - <item quantity="many">¿Deseas borrar <xliff:g id="COUNT_1">%1$d</xliff:g> carpetas y su contenido?</item> - <item quantity="other">¿Deseas borrar <xliff:g id="COUNT_1">%1$d</xliff:g> carpetas y su contenido?</item> - <item quantity="one">¿Deseas borrar <xliff:g id="COUNT_0">%1$d</xliff:g> carpeta y su contenido?</item> + <item quantity="many">¿Quieres borrar <xliff:g id="COUNT_1">%1$d</xliff:g> de carpetas y su contenido?</item> + <item quantity="other">¿Quieres borrar <xliff:g id="COUNT_1">%1$d</xliff:g> carpetas y su contenido?</item> + <item quantity="one">¿Quieres borrar <xliff:g id="COUNT_0">%1$d</xliff:g> carpeta y su contenido?</item> </plurals> <plurals name="delete_items_confirmation_message" formatted="false" msgid="7285090426511028179"> - <item quantity="many">¿Deseas borrar <xliff:g id="COUNT_1">%1$d</xliff:g> elementos?</item> - <item quantity="other">¿Deseas borrar <xliff:g id="COUNT_1">%1$d</xliff:g> elementos?</item> - <item quantity="one">¿Deseas borrar <xliff:g id="COUNT_0">%1$d</xliff:g> elemento?</item> + <item quantity="many">¿Borrar <xliff:g id="COUNT_1">%1$d</xliff:g> de elementos?</item> + <item quantity="other">¿Borrar <xliff:g id="COUNT_1">%1$d</xliff:g> elementos?</item> + <item quantity="one">¿Borrar <xliff:g id="COUNT_0">%1$d</xliff:g> elemento?</item> </plurals> <string name="images_shortcut_label" msgid="2545168016070493574">"Imágenes"</string> <string name="archive_loading_failed" msgid="7243436722828766996">"No es posible abrir el archivo para navegar, ya que el archivo está dañado o el formato no es compatible."</string> @@ -288,6 +295,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Nombre nuevo"</string> <string name="preview_file" msgid="4056622696305432343">"Obtener vista previa del archivo <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Obtén una vista previa del archivo de trabajo <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Obtener vista previa del archivo <xliff:g id="FILENAME">%2$s</xliff:g> del perfil <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Explorar archivos en otras apps"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anónimo"</string> <string name="open_tree_button" msgid="6402871398424497776">"Usar esta carpeta"</string> @@ -296,10 +304,10 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"No se puede usar esta carpeta"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Para proteger tu privacidad, elige otra carpeta."</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Crear carpeta"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Buscar en este teléfono"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Buscar este dispositivo"</string> <string name="delete_search_history" msgid="2202015025607694515">"Borrar historial de búsqueda de <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Personal"</string> - <string name="work_tab" msgid="7265359366883747413">"De trabajo"</string> + <string name="work_tab" msgid="7265359366883747413">"Trabajo"</string> <string name="a11y_work" msgid="7504431382825242153">"Trabajo"</string> <string name="drag_from_another_app" msgid="8310249276199969905">"No puedes transferir archivos de otra app."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Se muestra en modo de cuadrícula."</string> diff --git a/res/values-es/inspector_strings.xml b/res/values-es/inspector_strings.xml index 2e12fdc09..2dcaddc7f 100644 --- a/res/values-es/inspector_strings.xml +++ b/res/values-es/inspector_strings.xml @@ -33,7 +33,7 @@ <string name="metadata_camera" msgid="2363009732801281319">"Cámara"</string> <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string> <string name="metadata_aperture" msgid="6538741952698935357">"Apertura"</string> - <string name="metadata_shutter_speed" msgid="8204739885103326131">"Velocidad del obturador"</string> + <string name="metadata_shutter_speed" msgid="8204739885103326131">"Velocidad de disparo"</string> <string name="metadata_duration" msgid="3115494422055472715">"Duración"</string> <string name="metadata_date_time" msgid="1090351199248114406">"Fecha de la foto"</string> <string name="metadata_focal_length" msgid="3440735161407699893">"Longitud focal"</string> diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index f72351880..8850843c4 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Mover a…"</string> <string name="menu_compress" msgid="37539111904724188">"Comprimir"</string> <string name="menu_extract" msgid="8171946945982532262">"Extraer a…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Extraer todo…"</string> <string name="menu_rename" msgid="1883113442688817554">"Cambiar nombre"</string> <string name="menu_inspect" msgid="7279855349299446224">"Obtener información"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Mostrar archivos ocultos"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"No se puede cargar contenido en este momento"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Las aplicaciones de trabajo están en pausa"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Activar aplicaciones de trabajo"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Las aplicaciones de este perfil (<xliff:g id="PROFILE">%1$s</xliff:g>) están pausadas"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Activar aplicaciones (<xliff:g id="PROFILE">%1$s</xliff:g>)"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"No se pueden seleccionar archivos de trabajo"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Tu administrador de TI no te permite acceder a archivos de trabajo desde una aplicación personal"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"No se pueden seleccionar archivos personales"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Tu administrador de TI no te permite acceder a archivos personales desde una aplicación de trabajo"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"No se pueden seleccionar archivos de este perfil (<xliff:g id="PROFILE">%1$s</xliff:g>)"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Tu administrador de TI no te permite acceder a archivos de este perfil (<xliff:g id="PROFILE_0">%1$s</xliff:g>) desde una aplicación del otro (<xliff:g id="PROFILE_1">%2$s</xliff:g>)"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"No se puede guardar en el perfil de trabajo"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Tu administrador de TI no te permite guardar archivos personales en tu perfil de trabajo"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"No se puede guardar en el perfil personal"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Tu administrador de TI no te permite guardar archivos de trabajo en tu perfil personal"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"No se puede guardar en este perfil (<xliff:g id="PROFILE">%1$s</xliff:g>)"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Tu administrador de TI no te permite guardar archivos de un perfil (<xliff:g id="PROFILE_0">%1$s</xliff:g>) en el otro perfil (<xliff:g id="PROFILE_1">%2$s</xliff:g>)"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Esta acción no está permitida"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Para obtener más información, ponte en contacto con tu administrador de TI"</string> <string name="root_recent" msgid="1080156975424341623">"Reciente"</string> @@ -135,9 +142,9 @@ <item quantity="one">Comprimiendo <xliff:g id="COUNT_0">%1$d</xliff:g> archivo.</item> </plurals> <plurals name="extract_begin" formatted="false" msgid="1006380679562903749"> - <item quantity="many">Se están extrayendo <xliff:g id="COUNT_1">%1$d</xliff:g> archivos.</item> - <item quantity="other">Se están extrayendo <xliff:g id="COUNT_1">%1$d</xliff:g> archivos.</item> - <item quantity="one">Se está extrayendo <xliff:g id="COUNT_0">%1$d</xliff:g> archivo.</item> + <item quantity="many">Extrayendo <xliff:g id="COUNT_1">%1$d</xliff:g> archivos.</item> + <item quantity="other">Extrayendo <xliff:g id="COUNT_1">%1$d</xliff:g> archivos.</item> + <item quantity="one">Extrayendo <xliff:g id="COUNT_0">%1$d</xliff:g> archivo.</item> </plurals> <plurals name="move_begin" formatted="false" msgid="1464229874265756956"> <item quantity="many">Moviendo <xliff:g id="COUNT_1">%1$d</xliff:g> elementos.</item> @@ -189,14 +196,14 @@ <item quantity="one">No se ha podido comprimir este archivo: <xliff:g id="LIST_0">%1$s</xliff:g></item> </plurals> <plurals name="extract_failure_alert_content" formatted="false" msgid="7572748127571720803"> - <item quantity="many">No se han podido extraer estos archivos: <xliff:g id="LIST_1">%1$s</xliff:g></item> - <item quantity="other">No se han podido extraer estos archivos: <xliff:g id="LIST_1">%1$s</xliff:g></item> - <item quantity="one">No se ha podido extraer este archivo: <xliff:g id="LIST_0">%1$s</xliff:g></item> + <item quantity="many">Estos archivos no se han extraído: <xliff:g id="LIST_1">%1$s</xliff:g></item> + <item quantity="other">Estos archivos no se han extraído: <xliff:g id="LIST_1">%1$s</xliff:g></item> + <item quantity="one">Este archivo no se ha extraído: <xliff:g id="LIST_0">%1$s</xliff:g></item> </plurals> <plurals name="move_failure_alert_content" formatted="false" msgid="2747390342670799196"> - <item quantity="many">No se han podido mover estos archivos: <xliff:g id="LIST_1">%1$s</xliff:g></item> - <item quantity="other">No se han podido mover estos archivos: <xliff:g id="LIST_1">%1$s</xliff:g></item> - <item quantity="one">No se ha podido mover este archivo: <xliff:g id="LIST_0">%1$s</xliff:g></item> + <item quantity="many">Estos archivos no se han movido: <xliff:g id="LIST_1">%1$s</xliff:g></item> + <item quantity="other">Estos archivos no se han movido: <xliff:g id="LIST_1">%1$s</xliff:g></item> + <item quantity="one">Este archivo no se ha movido: <xliff:g id="LIST_0">%1$s</xliff:g></item> </plurals> <plurals name="delete_failure_alert_content" formatted="false" msgid="6122372614839711711"> <item quantity="many">No se han podido eliminar estos archivos: <xliff:g id="LIST_1">%1$s</xliff:g></item> @@ -288,6 +295,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Nombre nuevo"</string> <string name="preview_file" msgid="4056622696305432343">"Obtener una vista previa del archivo <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Previsualizar el archivo de trabajo <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Obtener una vista previa del archivo <xliff:g id="FILENAME">%2$s</xliff:g> de este perfil (<xliff:g id="PROFILE">%1$s</xliff:g>)"</string> <string name="apps_row_title" msgid="3340490016663092925">"Ver archivos en otras aplicaciones"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anónimo"</string> <string name="open_tree_button" msgid="6402871398424497776">"Usar esta carpeta"</string> @@ -296,7 +304,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"No se puede usar esta carpeta"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Para proteger tu privacidad, elige otra carpeta"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Crear carpeta nueva"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Buscar en este teléfono"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Buscar en este dispositivo"</string> <string name="delete_search_history" msgid="2202015025607694515">"Eliminar el historial de búsqueda de <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Personal"</string> <string name="work_tab" msgid="7265359366883747413">"Trabajo"</string> diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml index b90ceb73e..21a9aaabc 100644 --- a/res/values-et/strings.xml +++ b/res/values-et/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Teisalda asukohta …"</string> <string name="menu_compress" msgid="37539111904724188">"Tihenda"</string> <string name="menu_extract" msgid="8171946945982532262">"Ekstrakti …"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Ekstrakti kõik …"</string> <string name="menu_rename" msgid="1883113442688817554">"Nimeta ümber"</string> <string name="menu_inspect" msgid="7279855349299446224">"Hangi teavet"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Kuva peidetud failid"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Sisu ei saa praegu laadida"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Töörakendused on peatatud"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Lülita töörakendused sisse"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Profiili <xliff:g id="PROFILE">%1$s</xliff:g> rakendused on peatatud"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Lülita profiili <xliff:g id="PROFILE">%1$s</xliff:g> rakendused sisse"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Tööfaile ei saa valida"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Teie IT-administraator ei luba teil isikliku rakenduse kaudu tööfailidele juurde pääseda"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Isiklikke faile ei saa valida"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Teie IT-administraator ei luba töörakenduse kaudu isiklikele failidele juurde pääseda"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Profiili <xliff:g id="PROFILE">%1$s</xliff:g> faile ei saa valida"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Teie IT-administraator ei luba teil rakenduse <xliff:g id="PROFILE_1">%2$s</xliff:g> kaudu profiili <xliff:g id="PROFILE_0">%1$s</xliff:g> failidele juurde pääseda"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Tööprofiilile ei saa salvestada"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Teie IT-administraator ei luba isiklikke faile tööprofiilile salvestada"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Isiklikule profiilile ei saa salvestada"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Teie IT-administraator ei luba teil tööfaile isiklikule profiilile salvestada"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Profiilile <xliff:g id="PROFILE">%1$s</xliff:g> ei saa salvestada"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Teie IT-administraator ei luba teil profiili <xliff:g id="PROFILE_0">%1$s</xliff:g> faile profiilile <xliff:g id="PROFILE_1">%2$s</xliff:g> salvestada"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"See toiming ei ole lubatud"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Lisateabe saamiseks võtke ühendust IT-administraatoriga"</string> <string name="root_recent" msgid="1080156975424341623">"Hiljutised"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Uus nimi"</string> <string name="preview_file" msgid="4056622696305432343">"Faili <xliff:g id="FILENAME">%1$s</xliff:g> eelvaade"</string> <string name="preview_work_file" msgid="4495643735563487273">"Kuva tööfaili <xliff:g id="FILENAME">%1$s</xliff:g> eelvaade"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Profiili <xliff:g id="PROFILE">%1$s</xliff:g> faili <xliff:g id="FILENAME">%2$s</xliff:g> eelvaade"</string> <string name="apps_row_title" msgid="3340490016663092925">"Failide sirvimine muudes rakendustes"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonüümne"</string> <string name="open_tree_button" msgid="6402871398424497776">"Kasuta seda kausta"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Seda kausta ei saa kasutada"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Oma privaatsuse kaitsmiseks kasutage teist kausta"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Loo uus kaust"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Otsige sellest telefonist"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Otsige selles seadmes"</string> <string name="delete_search_history" msgid="2202015025607694515">"Otsinguajaloo kustutamine <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Isiklik"</string> <string name="work_tab" msgid="7265359366883747413">"Töö"</string> diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml index 37b58dabc..46a1e2bfb 100644 --- a/res/values-eu/strings.xml +++ b/res/values-eu/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Eraman hona…"</string> <string name="menu_compress" msgid="37539111904724188">"Konprimatu"</string> <string name="menu_extract" msgid="8171946945982532262">"Atera hona…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Atera guztia…"</string> <string name="menu_rename" msgid="1883113442688817554">"Aldatu izena"</string> <string name="menu_inspect" msgid="7279855349299446224">"Lortu informazioa"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Erakutsi fitxategi ezkutuak"</string> @@ -94,17 +95,23 @@ <string name="query_error" msgid="6625421453613879336">"Une honetan ezin da kargatu edukia"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Pausatuta daude laneko aplikazioak"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Aktibatu laneko aplikazioak"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"\"<xliff:g id="PROFILE">%1$s</xliff:g>\" profileko aplikazioak pausatuta daude"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Aktibatu profil honetako (<xliff:g id="PROFILE">%1$s</xliff:g>) aplikazioak"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Ezin dira hautatu laneko fitxategiak"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"IKT saileko administratzaileak ez dizu ematen baimenik laneko fitxategiak aplikazio pertsonal batetik atzitzeko"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Ezin dira hautatu fitxategi pertsonalak"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"IKT saileko administratzaileak ez dizu ematen baimenik fitxategi pertsonalak laneko aplikazio batetik atzitzeko"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Ezin dira hautatu profil honetako (<xliff:g id="PROFILE">%1$s</xliff:g>) fitxategiak"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"IKT saileko administratzaileak ez dizu eman baimenik profil bateko (<xliff:g id="PROFILE_0">%1$s</xliff:g>) fitxategiak beste profil bateko (<xliff:g id="PROFILE_1">%2$s</xliff:g>) aplikazio batekin atzitzeko"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Ezin da gorde laneko profilean"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"IKT saileko administratzaileak ez dizu ematen baimenik fitxategi pertsonalak zure laneko profilean gordetzeko"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Ezin da gorde profil pertsonalean"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"IKT saileko administratzaileak ez dizu ematen baimenik laneko fitxategiak zure profil pertsonalean gordetzeko"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Ezin da gorde profil honetan (<xliff:g id="PROFILE">%1$s</xliff:g>)"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"IKT saileko administratzaileak ez dizu eman baimenik profil bateko (<xliff:g id="PROFILE_0">%1$s</xliff:g>) fitxategiak beste profil batean (<xliff:g id="PROFILE_1">%2$s</xliff:g>) gordetzeko"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Ez da onartzen ekintza"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Informazio gehiago lortzeko, jarri IKT saileko administratzailearekin harremanetan"</string> - <string name="root_recent" msgid="1080156975424341623">"Azkenak"</string> + <string name="root_recent" msgid="1080156975424341623">"Azkenaldikoak"</string> <string name="root_available_bytes" msgid="8269870862691408864">"<xliff:g id="SIZE">%1$s</xliff:g> erabilgarri"</string> <string name="root_type_service" msgid="6521366147466512289">"Biltegiratze-zerbitzuak"</string> <string name="root_type_shortcut" msgid="6059343175525442279">"Lasterbideak"</string> @@ -242,14 +249,14 @@ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> hautatuta</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> hautatuta</item> </plurals> - <string name="root_info_header_recent" msgid="5654901877295332262">"Azken fitxategiak"</string> + <string name="root_info_header_recent" msgid="5654901877295332262">"Azkenaldiko fitxategiak"</string> <string name="root_info_header_global_search" msgid="4904078222280496152">"Fitxategiak"</string> <string name="root_info_header_downloads" msgid="8848161246921154115">"Deskargak karpetako fitxategiak"</string> <string name="root_info_header_storage" msgid="2989014130584927442">"<xliff:g id="DEVICE">%1$s</xliff:g> gailuko fitxategiak"</string> <string name="root_info_header_folder" msgid="5851172222368049864">"<xliff:g id="FOLDER">%1$s</xliff:g> karpetako fitxategiak"</string> <string name="root_info_header_app" msgid="2125422047558420885">"<xliff:g id="LABEL">%1$s</xliff:g> zerbitzuko fitxategiak"</string> <string name="root_info_header_app_with_summary" msgid="3223302581236069702">"<xliff:g id="LABEL">%1$s</xliff:g> zerbitzuko fitxategiak / <xliff:g id="SUMMARY">%2$s</xliff:g>"</string> - <string name="root_info_header_image_recent" msgid="7494373563753926014">"Azken irudiak"</string> + <string name="root_info_header_image_recent" msgid="7494373563753926014">"Azkenaldiko irudiak"</string> <string name="root_info_header_image_global_search" msgid="7307009823489854697">"Irudiak"</string> <string name="root_info_header_image_downloads" msgid="7072252612657612307">"Deskargak ataleko irudiak"</string> <string name="root_info_header_image_storage" msgid="5086740886360075930">"<xliff:g id="DEVICE">%1$s</xliff:g> gailuko irudiak"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Izen berria"</string> <string name="preview_file" msgid="4056622696305432343">"Aurreikusi <xliff:g id="FILENAME">%1$s</xliff:g> fitxategia"</string> <string name="preview_work_file" msgid="4495643735563487273">"Aurreikusi laneko <xliff:g id="FILENAME">%1$s</xliff:g> fitxategia"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Aurreikusi profil honetako (<xliff:g id="PROFILE">%1$s</xliff:g>) <xliff:g id="FILENAME">%2$s</xliff:g> fitxategia"</string> <string name="apps_row_title" msgid="3340490016663092925">"Arakatu beste aplikazio batzuetako fitxategiak"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonimoa"</string> <string name="open_tree_button" msgid="6402871398424497776">"Erabili karpeta hau"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Ezin da erabili karpeta hori"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Pribatutasuna babesteko, aukeratu beste karpeta bat"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Sortu karpeta bat"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Bilatu telefono honetan"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Bilatu gailu honetan"</string> <string name="delete_search_history" msgid="2202015025607694515">"Ezabatu bilaketa-historia (<xliff:g id="TEXT">%1$s</xliff:g>)"</string> <string name="personal_tab" msgid="3878576287868528503">"Pertsonala"</string> <string name="work_tab" msgid="7265359366883747413">"Lanekoa"</string> diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index f40b13d14..1c9e0c1e5 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -28,7 +28,7 @@ <string name="title_save" msgid="4384490653102710025">"ذخیره در"</string> <string name="menu_create_dir" msgid="2413624798689091042">"پوشهٔ جدید"</string> <string name="menu_grid" msgid="1453636521731880680">"نمای جدولی"</string> - <string name="menu_list" msgid="6714267452146410402">"نمای فهرست"</string> + <string name="menu_list" msgid="6714267452146410402">"نمای فهرستی"</string> <string name="menu_search" msgid="1876699106790719849">"جستجو"</string> <string name="menu_settings" msgid="6520844520117939047">"تنظیمات فضای ذخیرهسازی"</string> <string name="menu_open" msgid="9092138100049759315">"باز"</string> @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"انتقال به…"</string> <string name="menu_compress" msgid="37539111904724188">"فشرده کردن"</string> <string name="menu_extract" msgid="8171946945982532262">"استخراج در…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"استخراج همه…"</string> <string name="menu_rename" msgid="1883113442688817554">"تغییر نام"</string> <string name="menu_inspect" msgid="7279855349299446224">"دریافت اطلاعات"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"فایلهای پنهان نشان داده شود"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"محتوا درحال حاضر بار نمیشود"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"برنامههای کاری موقتاً متوقف شدهاند."</string> <string name="quiet_mode_button" msgid="8051436551926677305">"روشن کردن برنامههای کاری"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"برنامههای <xliff:g id="PROFILE">%1$s</xliff:g> موقتاً متوقف شده است"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"روشن کردن برنامههای <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"انتخاب فایلهای کاری ممکن نیست"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"سرپرست فناوری اطلاعات اجازه نمیدهد از برنامه شخصی به فایلهای کاری دسترسی پیدا کنید"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"انتخاب فایلهای شخصی ممکن نیست"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"سرپرست فناوری اطلاعات اجازه نمیدهد از برنامه کاری به فایلهای شخصی دسترسی پیدا کنید"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"نمیتوانید فایلهای <xliff:g id="PROFILE">%1$s</xliff:g> را انتخاب کنید"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"سرپرست فناوری اطلاعات شما اجازه نمیدهد ازطریق برنامه <xliff:g id="PROFILE_1">%2$s</xliff:g> به فایلهای <xliff:g id="PROFILE_0">%1$s</xliff:g> دسترسی داشته باشید"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"ذخیره در نمایه کاری ممکن نیست"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"سرپرست فناوری اطلاعات اجازه نمیدهد فایلهای شخصی را در نمایه کاری ذخیره کنید"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"ذخیره در نمایه شخصی ممکن نیست"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"سرپرست فناوری اطلاعات اجازه نمیدهد فایلهای کاری را در نمایه شخصی ذخیره کنید"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"نمیتوانید در نمایه <xliff:g id="PROFILE">%1$s</xliff:g> ذخیره کنید"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"سرپرست فناوری اطلاعات شما اجازه نمیدهد فایلهای <xliff:g id="PROFILE_0">%1$s</xliff:g> را در نمایه <xliff:g id="PROFILE_1">%2$s</xliff:g> ذخیره کنید"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"این کنش مجاز نیست"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"برای اطلاعات بیشتر، با سرپرست فناوری اطلاعات تماس بگیرید."</string> <string name="root_recent" msgid="1080156975424341623">"اخیر"</string> @@ -167,7 +174,7 @@ <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> مورد حذف نشد</item> <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> مورد حذف نشد</item> </plurals> - <string name="notification_touch_for_details" msgid="2385563502445129570">"برای مشاهده جزئیات ضربه بزنید"</string> + <string name="notification_touch_for_details" msgid="2385563502445129570">"برای مشاهده جزئیات تکضرب بزنید"</string> <string name="close" msgid="905969391788869975">"بستن"</string> <plurals name="copy_failure_alert_content" formatted="false" msgid="5570549471912990536"> <item quantity="one">این فایلها کپی نشدند: <xliff:g id="LIST_1">%1$s</xliff:g></item> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"نام جدید"</string> <string name="preview_file" msgid="4056622696305432343">"پیشنمایش فایل <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"پیشنمایش فایل کاری <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"پیشدید کردن فایل <xliff:g id="FILENAME">%2$s</xliff:g> در <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"مرور فایلها در سایر برنامهها"</string> <string name="anonymous_application" msgid="7633027057951625862">"ناشناس"</string> <string name="open_tree_button" msgid="6402871398424497776">"استفاده از این پوشه"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"نمیتوانید از این پوشه استفاده کنید"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"برای محافظت از حریمخصوصیتان، پوشه دیگری را انتخاب کنید"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"ایجاد پوشه جدید"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"جستجوی این تلفن"</string> + <string name="search_bar_hint" msgid="146031513183888721">"جستجوی این دستگاه"</string> <string name="delete_search_history" msgid="2202015025607694515">"حذف سابقه جستجوی <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"شخصی"</string> <string name="work_tab" msgid="7265359366883747413">"کاری"</string> diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml index d7c8e3d49..6a8cb5633 100644 --- a/res/values-fi/strings.xml +++ b/res/values-fi/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Siirrä kohteeseen…"</string> <string name="menu_compress" msgid="37539111904724188">"Pakkaa"</string> <string name="menu_extract" msgid="8171946945982532262">"Pura kohteeseen…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Pura kaikki…"</string> <string name="menu_rename" msgid="1883113442688817554">"Nimeä uudelleen"</string> <string name="menu_inspect" msgid="7279855349299446224">"Näytä tiedot"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Näytä piilotetut tiedostot"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Sisällön lataaminen epäonnistui."</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Työsovellukset on keskeytetty"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Laita työsovellukset päälle"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Sovellukset on keskeytetty: <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Ota <xliff:g id="PROFILE">%1$s</xliff:g>-sovellukset käyttöön"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Työtiedostot eivät käytettävissä"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"IT-järjestelmänvalvoja ei salli sinulle pääsyä työtiedostoihin henkilökohtaisesta sovelluksesta"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Ei voi valita henkilökohtaisia tiedostoja"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"IT-järjestelmänvalvoja ei salli sinulle pääsyä henkilökohtaisiin tiedostoihin työsovelluksesta"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g>-profiileja ei voi valita"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"IT-järjestelmänvalvoja ei salli sinun käyttää näitä tiedostoja (<xliff:g id="PROFILE_0">%1$s</xliff:g>) tällä sovelluksella (<xliff:g id="PROFILE_1">%2$s</xliff:g>)"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Ei tallennettavissa työprofiiliin"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"IT-järjestelmänvalvoja ei anna sinun tallentaa henkilökohtaisia tiedostoja työprofiiliisi"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Ei tallennettavissa henkilökohtaiseen profiiliin"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"IT-järjestelmänvalvoja ei anna sinun tallentaa työtiedostoja henkilökohtaiseen profiiliisi"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Ei voi tallentaa <xliff:g id="PROFILE">%1$s</xliff:g>-profiiliin"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"IT-järjestelmänvalvoja ei salli sinun tallentaa näitä tiedostoja (<xliff:g id="PROFILE_0">%1$s</xliff:g>) <xliff:g id="PROFILE_1">%2$s</xliff:g>-profiiliin"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Tämä toiminto ei ole sallittu"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Pyydä lisätietoja IT-järjestelmänvalvojalta"</string> <string name="root_recent" msgid="1080156975424341623">"Viimeisimmät"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Uusi nimi"</string> <string name="preview_file" msgid="4056622696305432343">"Esikatsele tiedostoa <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Esikatsele työtiedostoa <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Esikatsele <xliff:g id="PROFILE">%1$s</xliff:g>-profiilin tiedostoa: <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Selaa tiedostoja muissa sovelluksissa"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonyymi"</string> <string name="open_tree_button" msgid="6402871398424497776">"Käytä tätä kansiota"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Tämä kansio ei ole käytettävissä"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Valitse toinen kansio tietosuojasi turvaamiseksi"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Luo uusi kansio"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Hae tästä puhelimesta"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Hae tältä laitteelta"</string> <string name="delete_search_history" msgid="2202015025607694515">"Poista hakuhistoria <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Henkilökohtainen"</string> <string name="work_tab" msgid="7265359366883747413">"Työ"</string> diff --git a/res/values-fr-rCA/inspector_strings.xml b/res/values-fr-rCA/inspector_strings.xml index fc49cbe37..2cf15925f 100644 --- a/res/values-fr-rCA/inspector_strings.xml +++ b/res/values-fr-rCA/inspector_strings.xml @@ -18,7 +18,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="inspector_title" msgid="1924760928091740238">"Renseignements"</string> <string name="inspector_load_error" msgid="7522190243413249291">"Impossible de charger les renseignements sur le fichier"</string> - <string name="inspector_debug_section" msgid="2576052661505700421">"Données de débogage (concepteurs uniquement)"</string> + <string name="inspector_debug_section" msgid="2576052661505700421">"Données de débogage (développeurs uniquement)"</string> <string name="inspector_debug_metadata_section" msgid="5875140675600744846">"Métadonnées brutes : <xliff:g id="METADATATYPE">%1$s</xliff:g>"</string> <string name="inspector_metadata_section" msgid="6077622515328240575">"Détails des médias"</string> <string name="handler_app_file_opens_with" msgid="5272329600389613550">"Ce type de fichier s\'ouvre avec"</string> diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml index cad5d3e1a..ede583abb 100644 --- a/res/values-fr-rCA/strings.xml +++ b/res/values-fr-rCA/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Déplacer dans…"</string> <string name="menu_compress" msgid="37539111904724188">"Compresser"</string> <string name="menu_extract" msgid="8171946945982532262">"Extraire vers…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Tout extraire…"</string> <string name="menu_rename" msgid="1883113442688817554">"Renommer"</string> <string name="menu_inspect" msgid="7279855349299446224">"En savoir plus"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Afficher les fichiers masqués"</string> @@ -65,9 +66,9 @@ <string name="button_dismiss" msgid="7235249361023803349">"Fermer"</string> <string name="button_retry" msgid="4011461781916631389">"Réessayer"</string> <string name="button_clear" msgid="5412304437764369441">"Effacer"</string> - <string name="button_show_provider" msgid="6905880493806292753">"Afficher dans l\'application du fournisseur"</string> + <string name="button_show_provider" msgid="6905880493806292753">"Afficher dans l\'appli du fournisseur"</string> <string name="button_back" msgid="1888621708934742182">"Retour"</string> - <string name="not_sorted" msgid="7813496644889115530">"Non trié"</string> + <string name="not_sorted" msgid="7813496644889115530">"Non triés"</string> <string name="sort_dimension_name" msgid="6325591541414177579">"Nom"</string> <string name="sort_dimension_summary" msgid="7724534446881397860">"Résumé"</string> <string name="sort_dimension_file_type" msgid="5779709622922085381">"Type"</string> @@ -92,16 +93,22 @@ <string name="save_error" msgid="8631128801982095782">"Échec de l\'enregistrement du document"</string> <string name="create_error" msgid="3092144450044861994">"Échec de la création du dossier"</string> <string name="query_error" msgid="6625421453613879336">"Impossible de charger le contenu pour le moment"</string> - <string name="quiet_mode_error_title" msgid="554319751414657910">"Les applications professionnelles sont interrompues"</string> - <string name="quiet_mode_button" msgid="8051436551926677305">"Activer les applications professionnelles"</string> + <string name="quiet_mode_error_title" msgid="554319751414657910">"Les applis professionnelles sont interrompues"</string> + <string name="quiet_mode_button" msgid="8051436551926677305">"Activer les applis professionnelles"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Les applis du profil de type <xliff:g id="PROFILE">%1$s</xliff:g> sont interrompues"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Activer les applis de type : <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Impossible de sélectionner des fichiers professionnels"</string> - <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Votre administrateur informatique ne vous autorise pas à accéder à des fichiers professionnels à partir d\'une application personnelle"</string> + <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Votre administrateur informatique ne vous autorise pas à accéder à des fichiers professionnels à partir d\'une appli personnelle"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Impossible de sélectionner des fichiers personnels"</string> - <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Votre administrateur informatique ne vous autorise pas à accéder à des fichiers personnels à partir d\'une application professionnelle"</string> + <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Votre administrateur informatique ne vous autorise pas à accéder à des fichiers personnels à partir d\'une appli professionnelle"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Impossible de sélectionner les fichiers de type <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Votre administrateur informatique ne vous autorise pas à accéder aux fichiers de type <xliff:g id="PROFILE_0">%1$s</xliff:g> à partir d\'une appli du profil suivant : <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Ιmpossible d\'enregistrer dans le profil professionnel"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Votre administrateur informatique ne vous autorise pas à enregistrer des fichiers personnels dans votre profil professionnel"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Impossible d\'enregistrer dans le profil personnel"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Votre administrateur informatique ne vous autorise pas à enregistrer des fichiers professionnels dans votre profil personnel"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Impossible d\'enregistrer des fichiers dans le profil suivant : <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Votre administrateur informatique ne vous autorise pas à enregistrer des fichiers de type <xliff:g id="PROFILE_0">%1$s</xliff:g> dans le profil suivant : <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Cette action n\'est pas autorisée"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Communiquez avec votre administrateur informatique pour en savoir plus"</string> <string name="root_recent" msgid="1080156975424341623">"Fichiers récents"</string> @@ -109,7 +116,7 @@ <string name="root_type_service" msgid="6521366147466512289">"Services de stockage"</string> <string name="root_type_shortcut" msgid="6059343175525442279">"Raccourcis"</string> <string name="root_type_device" msgid="1713604128005476585">"Appareils"</string> - <string name="root_type_apps" msgid="8646073235029886342">"Plus d\'applications"</string> + <string name="root_type_apps" msgid="8646073235029886342">"Plus d\'applis"</string> <string name="empty" msgid="5300254272613103004">"Aucun élément"</string> <string name="no_results" msgid="2371026325236359209">"Aucune correspondance dans %1$s"</string> <string name="toast_no_application" msgid="7555319548595113121">"Impossible d\'ouvrir le fichier"</string> @@ -125,9 +132,9 @@ <string name="delete_notification_title" msgid="2512757431856830792">"Suppression des fichiers"</string> <string name="copy_remaining" msgid="5390517377265177727">"Temps restant : <xliff:g id="DURATION">%s</xliff:g>"</string> <plurals name="copy_begin" formatted="false" msgid="151184708996738192"> - <item quantity="one">Copie de <xliff:g id="COUNT_1">%1$d</xliff:g> élément en cours.</item> - <item quantity="many">Copie de <xliff:g id="COUNT_1">%1$d</xliff:g> éléments en cours.</item> - <item quantity="other">Copie de <xliff:g id="COUNT_1">%1$d</xliff:g> éléments en cours.</item> + <item quantity="one">Copie de <xliff:g id="COUNT_1">%1$d</xliff:g> élément en cours…</item> + <item quantity="many">Copie de <xliff:g id="COUNT_1">%1$d</xliff:g> d\'éléments en cours…</item> + <item quantity="other">Copie de <xliff:g id="COUNT_1">%1$d</xliff:g> éléments en cours…</item> </plurals> <plurals name="compress_begin" formatted="false" msgid="3534158317098678895"> <item quantity="one">Compression de <xliff:g id="COUNT_1">%1$d</xliff:g> fichier en cours.</item> @@ -140,9 +147,9 @@ <item quantity="other">Extraction de <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers en cours.</item> </plurals> <plurals name="move_begin" formatted="false" msgid="1464229874265756956"> - <item quantity="one">Déplacement de <xliff:g id="COUNT_1">%1$d</xliff:g> élément en cours.</item> - <item quantity="many">Déplacement de <xliff:g id="COUNT_1">%1$d</xliff:g> éléments en cours.</item> - <item quantity="other">Déplacement de <xliff:g id="COUNT_1">%1$d</xliff:g> éléments en cours.</item> + <item quantity="one">Déplacement de <xliff:g id="COUNT_1">%1$d</xliff:g> élément en cours…</item> + <item quantity="many">Déplacement de <xliff:g id="COUNT_1">%1$d</xliff:g> d\'éléments en cours…</item> + <item quantity="other">Déplacement de <xliff:g id="COUNT_1">%1$d</xliff:g> éléments en cours…</item> </plurals> <plurals name="deleting" formatted="false" msgid="1729138001178158901"> <item quantity="one">Suppression de <xliff:g id="COUNT_1">%1$d</xliff:g> élément en cours.</item> @@ -210,7 +217,7 @@ </plurals> <plurals name="clipboard_files_clipped" formatted="false" msgid="4847061634862926902"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> élément copié dans le presse-papiers.</item> - <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> éléments copiés dans le presse-papiers.</item> + <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> d\'éléments copiés dans le presse-papiers.</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> éléments copiés dans le presse-papiers.</item> </plurals> <string name="file_operation_rejected" msgid="4301554203329008794">"Opération relative au fichier non prise en charge"</string> @@ -236,19 +243,19 @@ <string name="delete_filename_confirmation_message" msgid="8338069763240613258">"Supprimer « <xliff:g id="NAME">%1$s</xliff:g> »?"</string> <string name="delete_foldername_confirmation_message" msgid="9084085260877704140">"Supprimer le dossier « <xliff:g id="NAME">%1$s</xliff:g> » et son contenu?"</string> <plurals name="delete_files_confirmation_message" formatted="false" msgid="4866664063250034142"> - <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier?</item> - <item quantity="many">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers?</item> - <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers?</item> + <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier?</item> + <item quantity="many">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> de fichiers?</item> + <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers?</item> </plurals> <plurals name="delete_folders_confirmation_message" formatted="false" msgid="1028946402799686388"> - <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossier et son contenu?</item> - <item quantity="many">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossiers et leur contenu?</item> - <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossiers et leur contenu?</item> + <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossier et son contenu?</item> + <item quantity="many">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> de dossiers et leurs contenus?</item> + <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossiers et leurs contenus?</item> </plurals> <plurals name="delete_items_confirmation_message" formatted="false" msgid="7285090426511028179"> - <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> élément?</item> - <item quantity="many">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> éléments?</item> - <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> éléments?</item> + <item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> élément?</item> + <item quantity="many">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> d\'éléments?</item> + <item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> éléments?</item> </plurals> <string name="images_shortcut_label" msgid="2545168016070493574">"Images"</string> <string name="archive_loading_failed" msgid="7243436722828766996">"Impossible d\'ouvrir l\'archive pour la navigation. Le fichier pourrait être corrompu ou être dans un format incompatible."</string> @@ -288,20 +295,21 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Nouveau nom"</string> <string name="preview_file" msgid="4056622696305432343">"Afficher un aperçu du fichier <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Afficher l\'aperçu du fichier professionnel <xliff:g id="FILENAME">%1$s</xliff:g>"</string> - <string name="apps_row_title" msgid="3340490016663092925">"Parcourir les fichiers dans d\'autres applications"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Afficher un aperçu du fichier de type <xliff:g id="PROFILE">%1$s</xliff:g> : <xliff:g id="FILENAME">%2$s</xliff:g>"</string> + <string name="apps_row_title" msgid="3340490016663092925">"Parcourir les fichiers dans d\'autres applis"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonyme"</string> <string name="open_tree_button" msgid="6402871398424497776">"Utiliser ce dossier"</string> <string name="open_tree_dialog_title" msgid="6339509533852318569">"Autoriser <xliff:g id="APPNAME">%1$s</xliff:g> à accéder aux fichiers dans <xliff:g id="DIRECTORY">%2$s</xliff:g>?"</string> - <string name="open_tree_dialog_message" msgid="4120695398430659628">"Cela permettra à <xliff:g id="APPNAME">%1$s</xliff:g> d\'accéder au contenu actuel et futur stocké dans <xliff:g id="DIRECTORY">%2$s</xliff:g>."</string> + <string name="open_tree_dialog_message" msgid="4120695398430659628">"Cela permettra à <xliff:g id="APPNAME">%1$s</xliff:g> d\'accéder à partir de maintenant au contenu stocké dans <xliff:g id="DIRECTORY">%2$s</xliff:g>."</string> <string name="directory_blocked_header_title" msgid="1164584889578740066">"Impossible d\'utiliser ce dossier"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Pour protéger votre confidentialité, choisissez un autre dossier"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Créer un dossier"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Rechercher sur ce téléphone"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Faire une recherche dans cet appareil"</string> <string name="delete_search_history" msgid="2202015025607694515">"Supprimer l\'historique de recherche <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Personnel"</string> <string name="work_tab" msgid="7265359366883747413">"Professionnel"</string> <string name="a11y_work" msgid="7504431382825242153">"Travail"</string> - <string name="drag_from_another_app" msgid="8310249276199969905">"Vous ne pouvez pas déplacer de fichiers d\'une autre application."</string> + <string name="drag_from_another_app" msgid="8310249276199969905">"Vous ne pouvez pas déplacer de fichiers d\'une autre appli."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Affichage en mode grille."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Affichage en mode liste."</string> </resources> diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 60143d2a6..01935a805 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Déplacer vers…"</string> <string name="menu_compress" msgid="37539111904724188">"Compresser"</string> <string name="menu_extract" msgid="8171946945982532262">"Extraire sur…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Tout extraire…"</string> <string name="menu_rename" msgid="1883113442688817554">"Renommer"</string> <string name="menu_inspect" msgid="7279855349299446224">"Obtenir les informations"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Afficher les fichiers masqués"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Impossible de charger le contenu pour le moment"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Applis professionnelles en pause"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Activer les applis professionnelles"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Les applis du profil <xliff:g id="PROFILE">%1$s</xliff:g> sont en veille"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Activer les applis du profil <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Impossible de sélectionner des fichiers professionnels"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Votre administrateur informatique ne vous autorise pas à accéder à des fichiers professionnels depuis une application personnelle"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Impossible de sélectionner des fichiers personnels"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Votre administrateur informatique ne vous autorise pas à accéder à des fichiers personnels depuis une application professionnelle"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Impossible de sélectionner les fichiers du profil <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Votre administrateur informatique ne vous autorise pas à accéder aux fichiers du profil <xliff:g id="PROFILE_0">%1$s</xliff:g> à partir d\'une appli du profil <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Ιmpossible d\'enregistrer dans le profil professionnel"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Votre administrateur informatique ne vous autorise pas à enregistrer des fichiers personnels dans votre profil professionnel"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Impossible d\'enregistrer dans le profil personnel"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Votre administrateur informatique ne vous autorise pas à enregistrer des fichiers professionnels dans votre profil personnel"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Impossible d\'enregistrer les fichiers sur le profil <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Votre administrateur informatique ne vous autorise pas à enregistrer les fichiers du profil <xliff:g id="PROFILE_0">%1$s</xliff:g> sur le profil <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Cette opération n\'est pas autorisée"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Pour en savoir plus, contactez ce dernier"</string> <string name="root_recent" msgid="1080156975424341623">"Récents"</string> @@ -288,6 +295,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Nouveau nom"</string> <string name="preview_file" msgid="4056622696305432343">"Prévisualiser le fichier <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Prévisualiser le fichier professionnel <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Prévisualiser le fichier <xliff:g id="FILENAME">%2$s</xliff:g> du profil <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Parcourir les fichiers dans d\'autres applications"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonyme"</string> <string name="open_tree_button" msgid="6402871398424497776">"Utiliser ce dossier"</string> @@ -296,7 +304,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Impossible d\'utiliser ce dossier"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Pour protéger votre vie privée, choisissez un autre dossier"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Créer un dossier"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Rechercher sur ce téléphone"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Rechercher cet appareil"</string> <string name="delete_search_history" msgid="2202015025607694515">"Supprimer l\'historique des recherches <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Personnel"</string> <string name="work_tab" msgid="7265359366883747413">"Professionnel"</string> diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml index fea0de473..db1aeccf5 100644 --- a/res/values-gl/strings.xml +++ b/res/values-gl/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Mover a…"</string> <string name="menu_compress" msgid="37539111904724188">"Comprimir"</string> <string name="menu_extract" msgid="8171946945982532262">"Extraer en..."</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Extraer todo…"</string> <string name="menu_rename" msgid="1883113442688817554">"Cambiar nome"</string> <string name="menu_inspect" msgid="7279855349299446224">"Obter información"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Amosar ficheiros ocultos"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Non se pode cargar o contido neste momento"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Puxéronse en pausa as aplicacións do traballo"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Activar aplicacións do traballo"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"As aplicacións do perfil <xliff:g id="PROFILE">%1$s</xliff:g> están en pausa"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Activar aplicacións (<xliff:g id="PROFILE">%1$s</xliff:g>)"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Non se puideron seleccionar os ficheiros de traballo"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"O teu administrador de TI non permite acceder aos ficheiros do traballo desde unha aplicación persoal"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Non se puideron seleccionar os ficheiros persoais"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"O teu administrador de TI non permite acceder aos ficheiros persoais desde unha aplicación do traballo"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Non se poden seleccionar ficheiros deste perfil (<xliff:g id="PROFILE">%1$s</xliff:g>)"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"A persoa administradora de TI non che permite acceder aos ficheiros dun perfil (<xliff:g id="PROFILE_0">%1$s</xliff:g>) desde unha aplicación doutro perfil (<xliff:g id="PROFILE_1">%2$s</xliff:g>)"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Non se poden gardar os ficheiros no perfil de traballo"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"O teu administrador de TI non permite gardar ficheiros persoais no teu perfil de traballo"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Non se puideron gardar os ficheiros no perfil persoal"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"O teu administrador de TI non permite gardar ficheiros do traballo no teu perfil persoal"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Non se poden gardar ficheiros neste perfil (<xliff:g id="PROFILE">%1$s</xliff:g>)"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"A persoa administradora de TI non che permite gardar ficheiros dun perfil (<xliff:g id="PROFILE_0">%1$s</xliff:g>) noutro perfil (<xliff:g id="PROFILE_1">%2$s</xliff:g>)"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Esta acción non está permitida"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Para obter máis información, ponte en contacto co teu administrador de TI"</string> <string name="root_recent" msgid="1080156975424341623">"Recentes"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Nome novo"</string> <string name="preview_file" msgid="4056622696305432343">"Vista previa do ficheiro <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Vista previa do ficheiro do traballo <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Previsualizar o ficheiro <xliff:g id="FILENAME">%2$s</xliff:g> deste perfil (<xliff:g id="PROFILE">%1$s</xliff:g>)"</string> <string name="apps_row_title" msgid="3340490016663092925">"Consultar ficheiros noutras aplicacións"</string> <string name="anonymous_application" msgid="7633027057951625862">"Aplicación anónima"</string> <string name="open_tree_button" msgid="6402871398424497776">"Usar este cartafol"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Non se pode utilizar este cartafol"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Para protexer a túa privacidade, escolle outro cartafol"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Crear novo cartafol"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Busca neste teléfono"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Busca contido neste dispositivo"</string> <string name="delete_search_history" msgid="2202015025607694515">"Elimina o historial de busca <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Persoal"</string> <string name="work_tab" msgid="7265359366883747413">"Traballo"</string> diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml index f311d1bb1..e161c1656 100644 --- a/res/values-gu/strings.xml +++ b/res/values-gu/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"આમાં ખસેડો…"</string> <string name="menu_compress" msgid="37539111904724188">"સંકુચિત કરો"</string> <string name="menu_extract" msgid="8171946945982532262">"આમાં એક્સટ્રેક્ટ કરો…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"બધું એક્સટ્રેક્ટ કરો…"</string> <string name="menu_rename" msgid="1883113442688817554">"નામ બદલો"</string> <string name="menu_inspect" msgid="7279855349299446224">"માહિતી મેળવો"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"છુપાવેલી ફાઇલો બતાવો"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"આ પળે સામગ્રી લોડ કરી શકતાં નથી"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"ઑફિસ માટેની ઍપ થોભાવવામાં આવી છે"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"ઑફિસ માટેની ઍપ ચાલુ કરો"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g>ની ઍપ થોભાવવામાં આવી છે"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g>ની ઍપ ચાલુ કરો"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"ઑફિસની ફાઇલોને પસંદ કરી શકતા નથી"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"તમારા IT વ્યવસ્થાપક તમને વ્યક્તિગત ઍપ પરથી ઑફિસની ફાઇલોને ઍક્સેસ કરવાની મંજૂરી આપતા નથી"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"વ્યક્તિગત ફાઇલોને પસંદ કરી શકતા નથી"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"તમારા IT વ્યવસ્થાપક તમને ઑફિસ માટેની ઍપ પરથી વ્યક્તિગત ફાઇલોને ઍક્સેસ કરવાની મંજૂરી આપતા નથી"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g>ની ફાઇલ પસંદ કરી શકતા નથી"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"તમારા IT ઍડમિન તમને <xliff:g id="PROFILE_1">%2$s</xliff:g> ઍપમાંથી <xliff:g id="PROFILE_0">%1$s</xliff:g>ની ફાઇલો ઍક્સેસ કરવાની મંજૂરી આપતા નથી"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"ઑફિસની પ્રોફાઇલમાં સાચવી શકતા નથી"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"તમારા IT વ્યવસ્થાપક તમને તમારી કાર્યાલયની પ્રોફાઇલમાં વ્યક્તિગત ફાઇલોને સાચવવાની મંજૂરી આપતા નથી"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"વ્યક્તિગત પ્રોફાઇલમાં સાચવી શકતા નથી"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"તમારા IT વ્યવસ્થાપક તમને તમારી વ્યક્તિગત પ્રોફાઇલમાં ઑફિસની ફાઇલોને સાચવવાની મંજૂરી આપતા નથી"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> પ્રોફાઇલમાં સાચવી શકતા નથી"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"તમારા IT ઍડમિન તમને <xliff:g id="PROFILE_0">%1$s</xliff:g>ની ફાઇલોને તમારી <xliff:g id="PROFILE_1">%2$s</xliff:g> પ્રોફાઇલમાં સાચવવાની મંજૂરી આપતા નથી"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"આ ક્રિયાની મંજૂરી નથી"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"વધુ જાણવા માટે, તમારા IT ઍડમિનનો સંપર્ક કરો"</string> <string name="root_recent" msgid="1080156975424341623">"તાજેતરમાં"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"નવું નામ"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g> ફાઇલને પ્રીવ્યૂ કરો"</string> <string name="preview_work_file" msgid="4495643735563487273">"ઑફિસની ફાઇલ <xliff:g id="FILENAME">%1$s</xliff:g>ને પ્રીવ્યૂ કરો"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g>ની <xliff:g id="FILENAME">%2$s</xliff:g> ફાઇલને પ્રીવ્યૂ કરો"</string> <string name="apps_row_title" msgid="3340490016663092925">"અન્ય ઍપમાં ફાઇલો બ્રાઉઝ કરો"</string> <string name="anonymous_application" msgid="7633027057951625862">"અજ્ઞાત"</string> <string name="open_tree_button" msgid="6402871398424497776">"આ ફોલ્ડરનો ઉપયોગ કરો"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"આ ફોલ્ડરનો ઉપયોગ કરી શકાતો નથી"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"તમારી પ્રાઇવસી સુરક્ષિત રાખવા માટે, અન્ય ફોલ્ડર પસંદ કરો"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"નવું ફોલ્ડર બનાવો"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"આ ફોન શોધો"</string> + <string name="search_bar_hint" msgid="146031513183888721">"આ ડિવાઇસ શોધો"</string> <string name="delete_search_history" msgid="2202015025607694515">"શોધ ઇતિહાસ <xliff:g id="TEXT">%1$s</xliff:g> ડિલીટ કરો"</string> <string name="personal_tab" msgid="3878576287868528503">"વ્યક્તિગત"</string> <string name="work_tab" msgid="7265359366883747413">"ઑફિસ"</string> diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index 97f773230..96c4dcfc2 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"यहां ले जाएं…"</string> <string name="menu_compress" msgid="37539111904724188">"कंप्रेस करें"</string> <string name="menu_extract" msgid="8171946945982532262">"यहां निकालें…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"सभी को एक्सट्रैक्ट करें…"</string> <string name="menu_rename" msgid="1883113442688817554">"नाम बदलें"</string> <string name="menu_inspect" msgid="7279855349299446224">"जानकारी पाएं"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"छिपी हुई फ़ाइलें दिखाएं"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"इस समय सामग्री लोड नहीं की जा सकती"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"वर्क ऐप्लिकेशन रोक दिए गए हैं"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"वर्क ऐप्लिकेशन चालू करें"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> ऐप्लिकेशन पर रोक लगा दी गई है"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> ऐप्लिकेशन चालू करें"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"दफ़्तर की फ़ाइलें नहीं चुनी जा सकतीं"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"आपका आईटी एडमिन आपको किसी निजी ऐप्लिकेशन से दफ़्तर की फ़ाइलें ऐक्सेस करने की मंज़ूरी नहीं देता"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"निजी फ़ाइलें नहीं चुनी जा सकतीं"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"आपका आईटी एडमिन आपको ऑफ़िस के काम से जुड़े ऐप्लिकेशन से निजी फ़ाइलें ऐक्सेस करने की अनुमति नहीं देता"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> फ़ाइलों को नहीं चुना जा सकता"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"आपका आईटी एडमिन, <xliff:g id="PROFILE_0">%1$s</xliff:g> फ़ाइलों को <xliff:g id="PROFILE_1">%2$s</xliff:g> ऐप्लिकेशन से ऐक्सेस करने की अनुमति नहीं देता है"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"वर्क प्रोफ़ाइल में सेव नहीं की जा सकतीं"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"आपका आईटी एडमिन आपको निजी फ़ाइलें वर्क प्रोफ़ाइल में सेव करने की अनुमति नहीं देता"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"निजी प्रोफ़ाइल में सेव नहीं की जा सकतीं"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"आपका आईटी एडमिन आपको दफ़्तर की फ़ाइलें निजी प्रोफ़ाइल में सेव करने की अनुमति नहीं देता"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> प्रोफ़ाइल में फ़ाइलें सेव नहीं की जा सकी"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"आपका आईटी एडमिन, <xliff:g id="PROFILE_0">%1$s</xliff:g> फ़ाइलों को <xliff:g id="PROFILE_1">%2$s</xliff:g> प्रोफ़ाइल में सेव करने की अनुमति नहीं देता है"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"इसकी अनुमति नहीं है"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"ज़्यादा जानने के लिए, अपने आईटी एडमिन से संपर्क करें"</string> <string name="root_recent" msgid="1080156975424341623">"हाल ही का"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"नया नाम"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g> फ़ाइल की झलक देखें"</string> <string name="preview_work_file" msgid="4495643735563487273">"दफ़्तर की फ़ाइल <xliff:g id="FILENAME">%1$s</xliff:g> की झलक देखें"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> फ़ाइल <xliff:g id="FILENAME">%2$s</xliff:g> की झलक देखें"</string> <string name="apps_row_title" msgid="3340490016663092925">"दूसरे ऐप्लिकेशन में फ़ाइलें ब्राउज़ करें"</string> <string name="anonymous_application" msgid="7633027057951625862">"अनाम"</string> <string name="open_tree_button" msgid="6402871398424497776">"यह फ़ोल्डर इस्तेमाल करें"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"इस फ़ोल्डर का इस्तेमाल नहीं किया जा सकता"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"अपनी निजता की सुरक्षा करने के लिए, कोई और फ़ोल्डर चुनें"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"नया फ़ोल्डर बनाएं"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"इस फ़ोन में खोजें"</string> + <string name="search_bar_hint" msgid="146031513183888721">"इस डिवाइस के बारे में खोजें"</string> <string name="delete_search_history" msgid="2202015025607694515">"खोज का इतिहास मिटाएं <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"निजी"</string> <string name="work_tab" msgid="7265359366883747413">"काम से जुड़ी"</string> diff --git a/res/values-hr/inspector_strings.xml b/res/values-hr/inspector_strings.xml index 14d49858a..a9b508355 100644 --- a/res/values-hr/inspector_strings.xml +++ b/res/values-hr/inspector_strings.xml @@ -30,7 +30,7 @@ <string name="metadata_coordinates" msgid="6897383227370702734">"Koordinate"</string> <string name="metadata_coordinates_format" msgid="1402724596764547761">"<xliff:g id="LATITUDE">%1$,.3f</xliff:g>, <xliff:g id="LONGITUDE">%2$,.3f</xliff:g>"</string> <string name="metadata_altitude" msgid="8063792127436794294">"Nadmorska visina"</string> - <string name="metadata_camera" msgid="2363009732801281319">"Fotoaparat"</string> + <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string> <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string> <string name="metadata_aperture" msgid="6538741952698935357">"Otvor blende"</string> <string name="metadata_shutter_speed" msgid="8204739885103326131">"Brzina zatvarača"</string> diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml index 3837d6432..f9536bc31 100644 --- a/res/values-hr/strings.xml +++ b/res/values-hr/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Premjesti u…"</string> <string name="menu_compress" msgid="37539111904724188">"Sažmi"</string> <string name="menu_extract" msgid="8171946945982532262">"Izdvoji u…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Izdvoji sve…"</string> <string name="menu_rename" msgid="1883113442688817554">"Promijeni naziv"</string> <string name="menu_inspect" msgid="7279855349299446224">"Informacije"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Prikaži skrivene datoteke"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Sadržaj se trenutačno ne može učitati"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Poslovne aplikacije su pauzirane"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Uključi poslovne aplikacije"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Pauzirane su aplikacije (<xliff:g id="PROFILE">%1$s</xliff:g>)"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Uključite aplikacije (<xliff:g id="PROFILE">%1$s</xliff:g>)"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Nije moguće odabrati poslovne datoteke"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Vaš IT administrator ne dopušta vam pristupanje poslovnim datotekama iz osobne aplikacije"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Nije moguće odabrati osobne datoteke"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Vaš IT administrator ne dopušta vam pristup osobnim datotekama iz poslovne aplikacije"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Nije moguće odabrati datoteke (<xliff:g id="PROFILE">%1$s</xliff:g>)"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Vaš IT administrator ne dopušta vam pristup datotekama (<xliff:g id="PROFILE_0">%1$s</xliff:g>) putem aplikacije (<xliff:g id="PROFILE_1">%2$s</xliff:g>)"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Nije moguće spremati na poslovni profil"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Vaš IT administrator ne dopušta vam spremanje osobnih datoteka na vaš poslovni profil"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Nije moguće spremati na osobni profil"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Vaš IT administrator ne dopušta vam spremanje poslovnih datoteka na vaš osobni profil"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Nije moguće spremiti na profil (<xliff:g id="PROFILE">%1$s</xliff:g>)"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Vaš IT administrator ne dopušta vam da spremite datoteke (<xliff:g id="PROFILE_0">%1$s</xliff:g>) na svoj profil (<xliff:g id="PROFILE_1">%2$s</xliff:g>)"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Ta radnja nije dopuštena"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Da biste saznali više, obratite se IT administratoru"</string> <string name="root_recent" msgid="1080156975424341623">"Nedavno"</string> @@ -288,6 +295,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Novi naziv"</string> <string name="preview_file" msgid="4056622696305432343">"Pregledajte datoteku <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Pregled poslovne datoteke <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Pregledajte datoteku (<xliff:g id="PROFILE">%1$s</xliff:g>) <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Pregledajte datoteke u drugim aplikacijama"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonimno"</string> <string name="open_tree_button" msgid="6402871398424497776">"Koristi ovu mapu"</string> @@ -296,7 +304,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Ne možete upotrebljavati ovu mapu"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Radi zaštite vlastite sigurnosti odaberite neku drugu mapu"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Izradi novu mapu"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Pretražite ovaj telefon"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Pretraži ovaj uređaj"</string> <string name="delete_search_history" msgid="2202015025607694515">"Brisanje povijesti pretraživanja <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Osobno"</string> <string name="work_tab" msgid="7265359366883747413">"Posao"</string> diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml index 21b3a6cd6..8c40453d5 100644 --- a/res/values-hu/strings.xml +++ b/res/values-hu/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Áthelyezés…"</string> <string name="menu_compress" msgid="37539111904724188">"Tömörítés"</string> <string name="menu_extract" msgid="8171946945982532262">"Kicsomagolás ide…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Összes kibontása"</string> <string name="menu_rename" msgid="1883113442688817554">"Átnevezés"</string> <string name="menu_inspect" msgid="7279855349299446224">"Információ megjelenítése"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Rejtett fájlok megjelenítése"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Jelenleg nem lehet tartalmat betölteni"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"A munkahelyi alkalmazások szüneteltetve vannak"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Munkahelyi alkalmazások bekapcsolása"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"A(z) <xliff:g id="PROFILE">%1$s</xliff:g> alkalmazások szüneteltetve vannak"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> alkalmazások bekapcsolása"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Nem választhatók ki munkafájlok"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Rendszergazdája nem engedélyezi, hogy munkafájlokhoz férjen hozzá személyes alkalmazásból"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Nem választhatók ki személyes fájlok"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Rendszergazdája nem engedélyezi, hogy személyes fájlokhoz férjen hozzá munkahelyi alkalmazásból"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Nem lehet kiválasztani <xliff:g id="PROFILE">%1$s</xliff:g> fájlokat"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Rendszergazdája nem engedélyezi a(z) <xliff:g id="PROFILE_0">%1$s</xliff:g> fájlokhoz való hozzáférést <xliff:g id="PROFILE_1">%2$s</xliff:g> alkalmazásból"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Nem lehet menteni a munkaprofilba"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Rendszergazdája nem engedélyezi, hogy személyes fájlokat mentsen munkaprofiljába"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Nem lehet menteni a személyes profilba"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Rendszergazdája nem engedélyezi, hogy munkafájlokat mentsen személyes profiljába"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Nem lehet menteni a következő profilba: <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Rendszergazdája nem engedélyezi <xliff:g id="PROFILE_0">%1$s</xliff:g> fájlok mentését az Ön <xliff:g id="PROFILE_1">%2$s</xliff:g> profijába"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Ez a művelet nem engedélyezett"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"További információért forduljon rendszergazdájához"</string> <string name="root_recent" msgid="1080156975424341623">"Legutóbbiak"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Új név"</string> <string name="preview_file" msgid="4056622696305432343">"A(z) <xliff:g id="FILENAME">%1$s</xliff:g> előnézete"</string> <string name="preview_work_file" msgid="4495643735563487273">"A(z) <xliff:g id="FILENAME">%1$s</xliff:g> munkafájl előnézete"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> fájl (<xliff:g id="FILENAME">%2$s</xliff:g>) előnézetének megtekintése"</string> <string name="apps_row_title" msgid="3340490016663092925">"Fájlok böngészése más alkalmazásokban"</string> <string name="anonymous_application" msgid="7633027057951625862">"Névtelen"</string> <string name="open_tree_button" msgid="6402871398424497776">"Jelenlegi mappa használata"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Ez a mappa nem használható"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Adatainak védelme érdekében válasszon másik mappát"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Új mappa létrehozása"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Keresés ezen a telefonon"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Keresés az eszközön"</string> <string name="delete_search_history" msgid="2202015025607694515">"Keresési előzmények törlése – <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Személyes"</string> <string name="work_tab" msgid="7265359366883747413">"Munkahelyi"</string> diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml index d57beef36..e848e0429 100644 --- a/res/values-hy/strings.xml +++ b/res/values-hy/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Տեղափոխել…"</string> <string name="menu_compress" msgid="37539111904724188">"Սեղմել"</string> <string name="menu_extract" msgid="8171946945982532262">"Արտահանել…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Դուրս բերել բոլորը…"</string> <string name="menu_rename" msgid="1883113442688817554">"Վերանվանել"</string> <string name="menu_inspect" msgid="7279855349299446224">"Տեղեկություններ"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Ցուցադրել թաքցված ֆայլերը"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Այս պահին հնարավոր չէ բեռնել բովանդակությունը"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Աշխատանքային հավելվածները դադարեցված են"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Միացնել աշխատանքային հավելվածները"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> հավելվածները դադարեցված են"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Միացնել <xliff:g id="PROFILE">%1$s</xliff:g> հավելվածները"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Հնարավոր չէ աշխատանքային ֆայլեր ընտրել"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Ձեր ՏՏ ադմինիստրատորը չի թույլատրում աշխատանքային ֆայլերի օգտագործումը անձնական հավելվածներից"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Հնարավոր չէ անձնական ֆայլեր ընտրել"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Ձեր ՏՏ ադմինիստրատորը չի թույլատրում աշխատանքային ֆայլերի օգտագործումը անձնական հավելվածներից"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Հնարավոր չէ ընտրել <xliff:g id="PROFILE">%1$s</xliff:g> ֆայլեր"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Ձեր ՏՏ ադմինիստրատորը ձեզ թույլ չի տալիս օգտագործել <xliff:g id="PROFILE_0">%1$s</xliff:g> ֆայլեր <xliff:g id="PROFILE_1">%2$s</xliff:g> հավելվածից"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Հնարավոր չէ պահել աշխատանքային պրոֆիլում"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Ձեր ՏՏ ադմինիստրատորը չի թույլատրում պահել անձնական ֆայլերը աշխատանքային պրոֆիլում"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Հնարավոր չէ պահել անձնական պրոֆիլում"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Ձեր ՏՏ ադմինիստրատորը չի թույլատրում պահել աշխատանքային ֆայլերը անձնական պրոֆիլում"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Հնարավոր չէ պահել <xliff:g id="PROFILE">%1$s</xliff:g> պրոֆիլում"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Ձեր ՏՏ ադմինիստրատորը ձեզ թույլ չի տալիս պահել <xliff:g id="PROFILE_0">%1$s</xliff:g> ֆայլերը ձեր <xliff:g id="PROFILE_1">%2$s</xliff:g> պրոֆիլում"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Գործողությունը թույլատրված չէ"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Մանրամասների համար դիմեք ՏՏ ադմինիստրատորին"</string> <string name="root_recent" msgid="1080156975424341623">"Վերջինները"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Նոր անունը"</string> <string name="preview_file" msgid="4056622696305432343">"Դիտել «<xliff:g id="FILENAME">%1$s</xliff:g>» ֆայլը"</string> <string name="preview_work_file" msgid="4495643735563487273">"Նախադիտել <xliff:g id="FILENAME">%1$s</xliff:g> աշխատանքային ֆայլը"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Դիտել <xliff:g id="FILENAME">%2$s</xliff:g> <xliff:g id="PROFILE">%1$s</xliff:g> ֆայլը"</string> <string name="apps_row_title" msgid="3340490016663092925">"Գտեք ֆայլեր այլ հավելվածներում"</string> <string name="anonymous_application" msgid="7633027057951625862">"Անանուն"</string> <string name="open_tree_button" msgid="6402871398424497776">"Օգտագործել այս պանակը"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Այլ պանակ ընտրեք"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Ձեր գաղտնիությունը պաշտպանելու նպատակով մենք արգելափակել ենք այս պանակի մուտքը"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Ստեղծել նոր պանակ"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Որոնեք հեռախոսում"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Որոնեք այս սարքում"</string> <string name="delete_search_history" msgid="2202015025607694515">"Ջնջել որոնումների պատմությունը՝ <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Անձնական"</string> <string name="work_tab" msgid="7265359366883747413">"Աշխատանքային"</string> diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index b149b2af8..5d79af348 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Pindahkan ke..."</string> <string name="menu_compress" msgid="37539111904724188">"Kompresi"</string> <string name="menu_extract" msgid="8171946945982532262">"Ekstrak ke…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Ekstrak semua…"</string> <string name="menu_rename" msgid="1883113442688817554">"Ganti nama"</string> <string name="menu_inspect" msgid="7279855349299446224">"Dapatkan info"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Tampilkan file tersembunyi"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Tidak dapat memuat konten saat ini"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Aplikasi kerja dijeda"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Aktifkan aplikasi kerja"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Aplikasi <xliff:g id="PROFILE">%1$s</xliff:g> dijeda"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Aktifkan aplikasi <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Tidak dapat memilih file kerja"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Admin IT tidak mengizinkan Anda mengakses file kerja dari aplikasi pribadi"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Tidak dapat memilih file pribadi"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Admin IT tidak mengizinkan Anda mengakses file pribadi dari aplikasi kerja"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Tidak dapat memilih file <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Admin IT tidak mengizinkan Anda mengakses file <xliff:g id="PROFILE_0">%1$s</xliff:g> dari aplikasi <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Tidak dapat menyimpan ke profil kerja"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Admin IT tidak mengizinkan Anda menyimpan file pribadi ke profil kerja Anda"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Tidak dapat menyimpan ke profil pribadi"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Admin IT tidak mengizinkan Anda menyimpan file kerja ke profil pribadi Anda"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Tidak dapat menyimpan ke profil <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Admin IT tidak mengizinkan Anda menyimpan file <xliff:g id="PROFILE_0">%1$s</xliff:g> ke profil <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Tindakan ini tidak diizinkan"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Untuk mempelajari lebih lanjut, hubungi admin IT Anda"</string> <string name="root_recent" msgid="1080156975424341623">"Terbaru"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Nama baru"</string> <string name="preview_file" msgid="4056622696305432343">"Pratinjau file <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Lihat pratinjau file kerja <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Pratinjau file <xliff:g id="PROFILE">%1$s</xliff:g> <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Cari file di aplikasi lain"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonim"</string> <string name="open_tree_button" msgid="6402871398424497776">"Gunakan folder ini"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Tidak dapat menggunakan folder ini"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Untuk melindungi privasi, pilih folder lain"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Buat folder baru"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Telusuri ponsel ini"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Telusuri perangkat ini"</string> <string name="delete_search_history" msgid="2202015025607694515">"Menghapus histori penelusuran <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Pribadi"</string> <string name="work_tab" msgid="7265359366883747413">"Kerja"</string> diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml index 6498186cb..1601f65a5 100644 --- a/res/values-is/strings.xml +++ b/res/values-is/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Færa í…"</string> <string name="menu_compress" msgid="37539111904724188">"Þjappa"</string> <string name="menu_extract" msgid="8171946945982532262">"Flytja út í…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Draga allt út …"</string> <string name="menu_rename" msgid="1883113442688817554">"Endurnefna"</string> <string name="menu_inspect" msgid="7279855349299446224">"Sækja upplýsingar"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Sýna faldar skrár"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Ekki hægt að hlaða efni í augnablikinu"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Hlé gert á vinnuforritum"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Kveikja á vinnuforritum"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Hlé var gert á <xliff:g id="PROFILE">%1$s</xliff:g>-forritum"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Kveikja á <xliff:g id="PROFILE">%1$s</xliff:g>-forritum"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Ekki er hægt að velja vinnuskrár"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Kerfisstjórinn þinn leyfir þér ekki að opna vinnuskrár í forritum til einkanota"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Ekki er hægt að velja einkaskrár"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Kerfisstjórinn þinn leyfir þér ekki að opna einkaskrár í vinnuforriti"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Ekki er hægt að velja <xliff:g id="PROFILE">%1$s</xliff:g>-skrár"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Stjórnandinn þinn leyfir ekki aðgang að <xliff:g id="PROFILE_0">%1$s</xliff:g>-skrám úr <xliff:g id="PROFILE_1">%2$s</xliff:g>-forriti"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Ekki er hægt að vista á vinnusniði"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Kerfisstjórinn þinn leyfir þér ekki að vista einkaskrár á vinnusniðinu"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Ekki er hægt að vista á einkasniði"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Kerfisstjórinn þinn leyfir þér ekki að vista vinnuskrár á einkasniði"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Ekki er hægt að vista á <xliff:g id="PROFILE">%1$s</xliff:g>-sniði"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Stjórnandinn þinn leyfir ekki vistun <xliff:g id="PROFILE_0">%1$s</xliff:g>-skráa á <xliff:g id="PROFILE_1">%2$s</xliff:g>-sniði"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Þessi aðgerð er ekki leyfð"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Hafðu samband við kerfisstjórann til að fá frekari upplýsingar"</string> <string name="root_recent" msgid="1080156975424341623">"Nýlegt"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Nýtt heiti"</string> <string name="preview_file" msgid="4056622696305432343">"Forskoða skrána <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Forskoða vinnuskrána <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Forskoða <xliff:g id="PROFILE">%1$s</xliff:g>-skrána „<xliff:g id="FILENAME">%2$s</xliff:g>“"</string> <string name="apps_row_title" msgid="3340490016663092925">"Skoða skrár í öðrum forritum"</string> <string name="anonymous_application" msgid="7633027057951625862">"Nafnlaus"</string> <string name="open_tree_button" msgid="6402871398424497776">"Nota þessa möppu"</string> @@ -274,9 +282,9 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Ekki er hægt að nota þessa möppu"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Veldu aðra möppu til að tryggja persónuvernd þína"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Búa til nýja möppu"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Leita í þessum síma"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Leita í þessu tæki"</string> <string name="delete_search_history" msgid="2202015025607694515">"Eyða leitarferli <xliff:g id="TEXT">%1$s</xliff:g>"</string> - <string name="personal_tab" msgid="3878576287868528503">"Persónulegt"</string> + <string name="personal_tab" msgid="3878576287868528503">"Einkasnið"</string> <string name="work_tab" msgid="7265359366883747413">"Vinna"</string> <string name="a11y_work" msgid="7504431382825242153">"Vinna"</string> <string name="drag_from_another_app" msgid="8310249276199969905">"Ekki er hægt að færa skrár úr öðru forriti."</string> diff --git a/res/values-it/inspector_strings.xml b/res/values-it/inspector_strings.xml index 7e81318db..d86da2ecd 100644 --- a/res/values-it/inspector_strings.xml +++ b/res/values-it/inspector_strings.xml @@ -43,5 +43,5 @@ <string name="metadata_artist" msgid="8972421485694988540">"Artista"</string> <string name="metadata_composer" msgid="4696926808308256056">"Compositore"</string> <string name="metadata_album" msgid="1661699531214720236">"Album"</string> - <string name="metadata_address" msgid="1849921023707744640">"Geolocalizzazione"</string> + <string name="metadata_address" msgid="1849921023707744640">"Posizione"</string> </resources> diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index a3b3998ee..f83c11d46 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Sposta in…"</string> <string name="menu_compress" msgid="37539111904724188">"Comprimi"</string> <string name="menu_extract" msgid="8171946945982532262">"Estrai in…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Estrai tutto…"</string> <string name="menu_rename" msgid="1883113442688817554">"Rinomina"</string> <string name="menu_inspect" msgid="7279855349299446224">"Informazioni"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Mostra file nascosti"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Impossibile caricare i contenuti al momento."</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Le app di lavoro sono in pausa"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Attiva app di lavoro"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Le app del profilo <xliff:g id="PROFILE">%1$s</xliff:g> sono in pausa"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Attiva le app <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Impossibile selezionare file di lavoro"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"L\'amministratore IT non consente l\'accesso ai file di lavoro da un\'app personale"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Impossibile selezionare file personali"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"L\'amministratore IT non consente l\'accesso ai file personali da un\'app di lavoro"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Impossibile selezionare i file <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"L\'amministratore IT non consente di accedere ai file <xliff:g id="PROFILE_0">%1$s</xliff:g> da un\'app <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Impossibile salvare sul profilo di lavoro"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"L\'amministratore IT non consente il salvataggio di file personali sul tuo profilo di lavoro"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Impossibile salvare sul profilo personale"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"L\'amministratore IT non consente il salvataggio di file di lavoro sul tuo profilo personale"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Impossibile salvare sul profilo <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"L\'amministratore IT non consente di salvare i file <xliff:g id="PROFILE_0">%1$s</xliff:g> sul profilo <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Questa azione non è consentita"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Per ulteriori informazioni, contatta il tuo amministratore IT"</string> <string name="root_recent" msgid="1080156975424341623">"Recenti"</string> @@ -125,9 +132,9 @@ <string name="delete_notification_title" msgid="2512757431856830792">"Eliminazione dei file"</string> <string name="copy_remaining" msgid="5390517377265177727">"<xliff:g id="DURATION">%s</xliff:g> rimanenti"</string> <plurals name="copy_begin" formatted="false" msgid="151184708996738192"> - <item quantity="many">Copia di <xliff:g id="COUNT_1">%1$d</xliff:g> elementi.</item> - <item quantity="other">Copia di <xliff:g id="COUNT_1">%1$d</xliff:g> elementi.</item> - <item quantity="one">Copia di <xliff:g id="COUNT_0">%1$d</xliff:g> elemento.</item> + <item quantity="many">Copia di <xliff:g id="COUNT_1">%1$d</xliff:g> di elementi in corso.</item> + <item quantity="other">Copia di <xliff:g id="COUNT_1">%1$d</xliff:g> elementi in corso.</item> + <item quantity="one">Copia di <xliff:g id="COUNT_0">%1$d</xliff:g> elemento in corso.</item> </plurals> <plurals name="compress_begin" formatted="false" msgid="3534158317098678895"> <item quantity="many">Compressione di <xliff:g id="COUNT_1">%1$d</xliff:g> file in corso.</item> @@ -135,19 +142,19 @@ <item quantity="one">Compressione di <xliff:g id="COUNT_0">%1$d</xliff:g> file in corso.</item> </plurals> <plurals name="extract_begin" formatted="false" msgid="1006380679562903749"> - <item quantity="many">Estrazione di <xliff:g id="COUNT_1">%1$d</xliff:g> file in corso.</item> + <item quantity="many">Estrazione di <xliff:g id="COUNT_1">%1$d</xliff:g> di file in corso.</item> <item quantity="other">Estrazione di <xliff:g id="COUNT_1">%1$d</xliff:g> file in corso.</item> <item quantity="one">Estrazione di <xliff:g id="COUNT_0">%1$d</xliff:g> file in corso.</item> </plurals> <plurals name="move_begin" formatted="false" msgid="1464229874265756956"> - <item quantity="many">Spostamento di <xliff:g id="COUNT_1">%1$d</xliff:g> elementi.</item> - <item quantity="other">Spostamento di <xliff:g id="COUNT_1">%1$d</xliff:g> elementi.</item> - <item quantity="one">Spostamento di <xliff:g id="COUNT_0">%1$d</xliff:g> elemento.</item> + <item quantity="many">Spostamento di <xliff:g id="COUNT_1">%1$d</xliff:g> di elementi in corso.</item> + <item quantity="other">Spostamento di <xliff:g id="COUNT_1">%1$d</xliff:g> elementi in corso.</item> + <item quantity="one">Spostamento di <xliff:g id="COUNT_0">%1$d</xliff:g> elemento in corso.</item> </plurals> <plurals name="deleting" formatted="false" msgid="1729138001178158901"> - <item quantity="many">Eliminazione di <xliff:g id="COUNT_1">%1$d</xliff:g> elementi.</item> - <item quantity="other">Eliminazione di <xliff:g id="COUNT_1">%1$d</xliff:g> elementi.</item> - <item quantity="one">Eliminazione di <xliff:g id="COUNT_0">%1$d</xliff:g> elemento.</item> + <item quantity="many">Eliminazione di <xliff:g id="COUNT_1">%1$d</xliff:g> di elementi in corso.</item> + <item quantity="other">Eliminazione di <xliff:g id="COUNT_1">%1$d</xliff:g> elementi in corso.</item> + <item quantity="one">Eliminazione di <xliff:g id="COUNT_0">%1$d</xliff:g> elemento in corso.</item> </plurals> <string name="undo" msgid="2902438994196400565">"Annulla"</string> <string name="copy_preparing" msgid="4759516490222449324">"Preparazione…"</string> @@ -157,24 +164,24 @@ <string name="delete_preparing" msgid="7339349837842802508">"Preparazione…"</string> <string name="delete_progress" msgid="2627631054702306423">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="TOTALCOUNT">%2$d</xliff:g>"</string> <plurals name="copy_error_notification_title" formatted="false" msgid="3188432450429390963"> - <item quantity="many">Copia di <xliff:g id="COUNT_1">%1$d</xliff:g> elementi non riuscita</item> - <item quantity="other">Copia di <xliff:g id="COUNT_1">%1$d</xliff:g> elementi non riuscita</item> - <item quantity="one">Copia di <xliff:g id="COUNT_0">%1$d</xliff:g> elemento non riuscita</item> + <item quantity="many">Impossibile copiare <xliff:g id="COUNT_1">%1$d</xliff:g> di elementi</item> + <item quantity="other">Impossibile copiare <xliff:g id="COUNT_1">%1$d</xliff:g> elementi</item> + <item quantity="one">Impossibile copiare <xliff:g id="COUNT_0">%1$d</xliff:g> elemento</item> </plurals> <plurals name="compress_error_notification_title" formatted="false" msgid="3043630066678213644"> - <item quantity="many">Impossibile comprimere <xliff:g id="COUNT_1">%1$d</xliff:g> file</item> + <item quantity="many">Impossibile comprimere <xliff:g id="COUNT_1">%1$d</xliff:g> di file</item> <item quantity="other">Impossibile comprimere <xliff:g id="COUNT_1">%1$d</xliff:g> file</item> <item quantity="one">Impossibile comprimere <xliff:g id="COUNT_0">%1$d</xliff:g> file</item> </plurals> <plurals name="move_error_notification_title" formatted="false" msgid="2185736082411854754"> - <item quantity="many">Spostamento di <xliff:g id="COUNT_1">%1$d</xliff:g> elementi non riuscito</item> - <item quantity="other">Spostamento di <xliff:g id="COUNT_1">%1$d</xliff:g> elementi non riuscito</item> - <item quantity="one">Spostamento di <xliff:g id="COUNT_0">%1$d</xliff:g> elemento non riuscito</item> + <item quantity="many">Impossibile spostare <xliff:g id="COUNT_1">%1$d</xliff:g> di elementi</item> + <item quantity="other">Impossibile spostare <xliff:g id="COUNT_1">%1$d</xliff:g> elementi</item> + <item quantity="one">Impossibile spostare <xliff:g id="COUNT_0">%1$d</xliff:g> elemento</item> </plurals> <plurals name="delete_error_notification_title" formatted="false" msgid="7568122018481625267"> - <item quantity="many">Eliminazione di <xliff:g id="COUNT_1">%1$d</xliff:g> elementi non riuscita</item> - <item quantity="other">Eliminazione di <xliff:g id="COUNT_1">%1$d</xliff:g> elementi non riuscita</item> - <item quantity="one">Eliminazione di <xliff:g id="COUNT_0">%1$d</xliff:g> elemento non riuscita</item> + <item quantity="many">Impossibile eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> di elementi</item> + <item quantity="other">Impossibile eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> elementi</item> + <item quantity="one">Impossibile eliminare <xliff:g id="COUNT_0">%1$d</xliff:g> elemento</item> </plurals> <string name="notification_touch_for_details" msgid="2385563502445129570">"Tocca per vedere i dettagli"</string> <string name="close" msgid="905969391788869975">"Chiudi"</string> @@ -194,9 +201,9 @@ <item quantity="one">Il seguente file non è stato estratto: <xliff:g id="LIST_0">%1$s</xliff:g></item> </plurals> <plurals name="move_failure_alert_content" formatted="false" msgid="2747390342670799196"> - <item quantity="many">I seguenti file non sono stati spostati: <xliff:g id="LIST_1">%1$s</xliff:g></item> - <item quantity="other">I seguenti file non sono stati spostati: <xliff:g id="LIST_1">%1$s</xliff:g></item> - <item quantity="one">Il seguente file non è stato spostato: <xliff:g id="LIST_0">%1$s</xliff:g></item> + <item quantity="many">Questi file non sono stati spostati: <xliff:g id="LIST_1">%1$s</xliff:g></item> + <item quantity="other">Questi file non sono stati spostati: <xliff:g id="LIST_1">%1$s</xliff:g></item> + <item quantity="one">Questo file non è stato spostato: <xliff:g id="LIST_0">%1$s</xliff:g></item> </plurals> <plurals name="delete_failure_alert_content" formatted="false" msgid="6122372614839711711"> <item quantity="many">I seguenti file non sono stati eliminati: <xliff:g id="LIST_1">%1$s</xliff:g></item> @@ -209,7 +216,7 @@ <item quantity="one">Il seguente file è stato convertito in un altro formato: <xliff:g id="LIST_0">%1$s</xliff:g></item> </plurals> <plurals name="clipboard_files_clipped" formatted="false" msgid="4847061634862926902"> - <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> elementi copiati negli appunti.</item> + <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> di elementi copiati negli appunti.</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> elementi copiati negli appunti.</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elemento copiato negli appunti.</item> </plurals> @@ -224,29 +231,29 @@ <string name="allow" msgid="1275746941353040309">"Consenti"</string> <string name="deny" msgid="5127201668078153379">"Rifiuta"</string> <plurals name="elements_selected" formatted="false" msgid="4448165978637163692"> - <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> elementi selezionati</item> - <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> elementi selezionati</item> - <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elemento selezionato</item> + <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> selezionati</item> + <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selezionati</item> + <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selezionato</item> </plurals> <plurals name="elements_dragged" formatted="false" msgid="5932571296037626279"> - <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> elementi</item> + <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> di elementi</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> elementi</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elemento</item> </plurals> <string name="delete_filename_confirmation_message" msgid="8338069763240613258">"Eliminare \"<xliff:g id="NAME">%1$s</xliff:g>\"?"</string> <string name="delete_foldername_confirmation_message" msgid="9084085260877704140">"Eliminare la cartella \"<xliff:g id="NAME">%1$s</xliff:g>\" e i relativi contenuti?"</string> <plurals name="delete_files_confirmation_message" formatted="false" msgid="4866664063250034142"> - <item quantity="many">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item> + <item quantity="many">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> di file?</item> <item quantity="other">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item> <item quantity="one">Eliminare <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item> </plurals> <plurals name="delete_folders_confirmation_message" formatted="false" msgid="1028946402799686388"> - <item quantity="many">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> cartelle e i relativi contenuti?</item> - <item quantity="other">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> cartelle e i relativi contenuti?</item> - <item quantity="one">Eliminare <xliff:g id="COUNT_0">%1$d</xliff:g> cartella e i relativi contenuti?</item> + <item quantity="many">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> di cartelle e i loro contenuti?</item> + <item quantity="other">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> cartelle e i loro contenuti?</item> + <item quantity="one">Eliminare <xliff:g id="COUNT_0">%1$d</xliff:g> cartella e i suoi contenuti?</item> </plurals> <plurals name="delete_items_confirmation_message" formatted="false" msgid="7285090426511028179"> - <item quantity="many">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> elementi?</item> + <item quantity="many">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> di elementi?</item> <item quantity="other">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> elementi?</item> <item quantity="one">Eliminare <xliff:g id="COUNT_0">%1$d</xliff:g> elemento?</item> </plurals> @@ -260,9 +267,9 @@ <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Sovrascrivere <xliff:g id="NAME">%1$s</xliff:g>?"</string> <string name="continue_in_background" msgid="1974214559047793331">"Continua in background"</string> <plurals name="selected_count" formatted="false" msgid="7555250236512981129"> - <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> elementi selezionati</item> - <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> elementi selezionati</item> - <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elemento selezionato</item> + <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> di selezionati</item> + <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selezionati</item> + <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selezionato</item> </plurals> <string name="root_info_header_recent" msgid="5654901877295332262">"File recenti"</string> <string name="root_info_header_global_search" msgid="4904078222280496152">"File"</string> @@ -288,6 +295,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Nuovo nome"</string> <string name="preview_file" msgid="4056622696305432343">"Visualizza il file <xliff:g id="FILENAME">%1$s</xliff:g> in anteprima"</string> <string name="preview_work_file" msgid="4495643735563487273">"Visualizza l\'anteprima del file di lavoro <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Visualizza l\'anteprima del file <xliff:g id="PROFILE">%1$s</xliff:g> <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Sfoglia i file in altre app"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonima"</string> <string name="open_tree_button" msgid="6402871398424497776">"Usa questa cartella"</string> @@ -296,7 +304,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Impossibile usare questa cartella"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Per tutelare la tua privacy, scegli un\'altra cartella"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Crea nuova cartella"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Cerca su questo telefono"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Cerca su questo dispositivo"</string> <string name="delete_search_history" msgid="2202015025607694515">"Elimina la cronologia delle ricerche <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Personale"</string> <string name="work_tab" msgid="7265359366883747413">"Lavoro"</string> diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index bce22306b..df5d6de4c 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"העברה אל…"</string> <string name="menu_compress" msgid="37539111904724188">"דחיסה"</string> <string name="menu_extract" msgid="8171946945982532262">"חילוץ לתיקייה…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"חילוץ הכול…"</string> <string name="menu_rename" msgid="1883113442688817554">"שינוי שם"</string> <string name="menu_inspect" msgid="7279855349299446224">"מידע על המסמך"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"הצגת קבצים מוסתרים"</string> @@ -94,16 +95,22 @@ <string name="query_error" msgid="6625421453613879336">"לא ניתן כרגע לטעון תוכן"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"האפליקציות לעבודה מושהות"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"הפעלה של אפליקציות לעבודה"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"אפליקציות של <xliff:g id="PROFILE">%1$s</xliff:g> מושהות"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"הפעלת אפליקציות מפרופיל <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"לא ניתן לבחור קובצי עבודה"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"מנהל ה-IT לא מאפשר לגשת לקובצי עבודה מאפליקציה לשימוש אישי"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"לא ניתן לבחור קבצים אישיים"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"מנהל ה-IT לא מאפשר לגשת לקבצים אישיים מאפליקציה לעבודה"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"לא ניתן לבחור קבצים מפרופיל <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"אין אישור מהאדמין ב-IT לגשת לקבצים מפרופיל <xliff:g id="PROFILE_0">%1$s</xliff:g> מאפליקציה <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"לא ניתן לשמור בפרופיל העבודה"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"מנהל ה-IT לא מתיר לשמור קבצים אישיים בפרופיל העבודה שלך"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"לא ניתן לשמור בפרופיל האישי"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"מנהל ה-IT לא מתיר לשמור קובצי עבודה בפרופיל האישי שלך"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"אי אפשר לשמור בפרופיל ה<xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"אין אישור מהאדמין ב-IT לשמור קבצים מפרופיל <xliff:g id="PROFILE_0">%1$s</xliff:g> בפרופיל ה<xliff:g id="PROFILE_1">%2$s</xliff:g> שלך"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"הפעולה הזו אסורה"</string> - <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"כדי לקבל מידע נוסף יש לפנות אל מנהל ה-IT"</string> + <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"כדי לקבל מידע נוסף, צריך לפנות אל מנהל ה-IT"</string> <string name="root_recent" msgid="1080156975424341623">"בשימוש לאחרונה"</string> <string name="root_available_bytes" msgid="8269870862691408864">"מקום פנוי: <xliff:g id="SIZE">%1$s</xliff:g>"</string> <string name="root_type_service" msgid="6521366147466512289">"שירותי אחסון"</string> @@ -176,7 +183,7 @@ <item quantity="two">לא ניתן היה למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> פריטים</item> <item quantity="other">לא ניתן היה למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> פריטים</item> </plurals> - <string name="notification_touch_for_details" msgid="2385563502445129570">"יש להקיש להצגת הפרטים"</string> + <string name="notification_touch_for_details" msgid="2385563502445129570">"יש ללחוץ להצגת הפרטים"</string> <string name="close" msgid="905969391788869975">"סגירה"</string> <plurals name="copy_failure_alert_content" formatted="false" msgid="5570549471912990536"> <item quantity="one">הקבצים הבאים לא הועתקו: <xliff:g id="LIST_1">%1$s</xliff:g></item> @@ -288,6 +295,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"שם חדש"</string> <string name="preview_file" msgid="4056622696305432343">"תצוגה מקדימה של הקובץ <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"לצפייה בתצוגה מקדימה של קובץ העבודה <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"תצוגה מקדימה של קובץ <xliff:g id="FILENAME">%2$s</xliff:g> מפרופיל <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"חיפוש קבצים באפליקציות אחרות"</string> <string name="anonymous_application" msgid="7633027057951625862">"אנונימית"</string> <string name="open_tree_button" msgid="6402871398424497776">"שימוש בתיקייה הזו"</string> @@ -296,7 +304,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"לא ניתן להשתמש בתיקייה הזו"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"כדי להגן על הפרטיות שלך, עליך לבחור תיקייה אחרת"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"יצירת תיקייה חדשה"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"חיפוש בטלפון הזה"</string> + <string name="search_bar_hint" msgid="146031513183888721">"חיפוש המכשיר הזה"</string> <string name="delete_search_history" msgid="2202015025607694515">"מחיקת היסטוריית החיפושים <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"אישי"</string> <string name="work_tab" msgid="7265359366883747413">"עבודה"</string> diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index 1f94cad82..e545ab1fa 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"移動…"</string> <string name="menu_compress" msgid="37539111904724188">"圧縮"</string> <string name="menu_extract" msgid="8171946945982532262">"次の場所に解凍…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"すべて抽出…"</string> <string name="menu_rename" msgid="1883113442688817554">"名前を変更"</string> <string name="menu_inspect" msgid="7279855349299446224">"詳細情報"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"非表示のファイルを表示"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"現在、コンテンツを読み込むことができません"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"仕事用アプリ一時停止中"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"仕事用アプリをオンにする"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g>アプリ一時停止中"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g>アプリを ON にする"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"仕事用ファイルは選択できません"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"IT 管理者は、個人用アプリから仕事用ファイルにアクセスすることを許可していません"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"個人用ファイルは選択できません"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"IT 管理者は、仕事用アプリから個人用ファイルにアクセスすることを許可していません"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g>ファイルは選択できません"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"IT 管理者は、<xliff:g id="PROFILE_1">%2$s</xliff:g>アプリから<xliff:g id="PROFILE_0">%1$s</xliff:g>ファイルにアクセスすることを許可していません"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"仕事用プロファイルには保存できません"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"IT 管理者は、仕事用プロファイルに個人用ファイルを保存することを許可していません"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"個人用プロファイルには保存できません"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"IT 管理者は、個人用プロファイルに仕事用ファイルを保存することを許可していません"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g>プロファイルには保存できません"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"IT 管理者は、<xliff:g id="PROFILE_1">%2$s</xliff:g>プロファイルに<xliff:g id="PROFILE_0">%1$s</xliff:g>ファイルを保存することを許可していません"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"この操作は許可されていません"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"詳しくは、IT 管理者にお問い合わせください"</string> <string name="root_recent" msgid="1080156975424341623">"最近"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"新しい名前"</string> <string name="preview_file" msgid="4056622696305432343">"ファイル <xliff:g id="FILENAME">%1$s</xliff:g> をプレビューする"</string> <string name="preview_work_file" msgid="4495643735563487273">"仕事用ファイル <xliff:g id="FILENAME">%1$s</xliff:g> をプレビューする"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g>ファイル <xliff:g id="FILENAME">%2$s</xliff:g> をプレビューする"</string> <string name="apps_row_title" msgid="3340490016663092925">"他のアプリでファイルを探す"</string> <string name="anonymous_application" msgid="7633027057951625862">"匿名"</string> <string name="open_tree_button" msgid="6402871398424497776">"このフォルダを使用"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"このフォルダは使用できません"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"プライバシーを保護するため、別のフォルダを選択してください"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"新規フォルダを作成"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"スマートフォン内を検索"</string> + <string name="search_bar_hint" msgid="146031513183888721">"このデバイスを検索する"</string> <string name="delete_search_history" msgid="2202015025607694515">"検索履歴「<xliff:g id="TEXT">%1$s</xliff:g>」を削除します"</string> <string name="personal_tab" msgid="3878576287868528503">"個人用"</string> <string name="work_tab" msgid="7265359366883747413">"仕事用"</string> diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml index b4a85f46f..77c7cb2b1 100644 --- a/res/values-ka/strings.xml +++ b/res/values-ka/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"გადაადგილება..."</string> <string name="menu_compress" msgid="37539111904724188">"შეკუმშვა"</string> <string name="menu_extract" msgid="8171946945982532262">"ამოღება…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"ყველას ამოღება…"</string> <string name="menu_rename" msgid="1883113442688817554">"გადარქმევა"</string> <string name="menu_inspect" msgid="7279855349299446224">"ინფორმაციის მიღება"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"გამოჩნდეს დამალული ფაილები"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"კონტენტის ჩატვირთვა ამჟამად ვერ ხერხდება"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"სამსახურის აპები დაპაუზებულია"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"სამსახურის აპების ჩართვა"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> პროფილის აპები დაპაუზებულია"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> პროფილის აპების ჩართვა"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"სამსახურის ფაილების არჩევა ვერ მოხერხდება"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"თქვენი IT ადმინისტრატორი გიკრძალავთ სამსახურის ფაილებზე პერსონალური აპით წვდომას"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"პერსონალური ფაილების არჩევა ვერ მოხერხდება"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"თქვენი IT ადმინისტრატორი გიკრძალავთ პერსონალურ ფაილებზე სამსახურის აპით წვდომას"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> პროფილის ფაილების არჩევა ვერ ხერხდება"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"თქვენი IT ადმინისტრატორი <xliff:g id="PROFILE_0">%1$s</xliff:g> პროფილის ფაილების <xliff:g id="PROFILE_1">%2$s</xliff:g> აპიდან წვდომას არ უშვებს"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"სამსახურის პროფილში შენახვა ვერ მოხერხდება"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"თქვენი IT ადმინისტრატორი გიკრძალავთ პერსონალური ფაილების შენახვას თქვენს სამსახურის პროფილში"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"პერსონალურ პროფილში შენახვა ვერ მოხერხდება"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"თქვენი IT ადმინისტრატორი გიკრძალავთ სამსახურის ფაილების შენახვას თქვენს პერსონალურ პროფილში"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> პროფილში შენახვა ვერ ხერხდება"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"თქვენი IT ამინისტრატორი <xliff:g id="PROFILE_0">%1$s</xliff:g> პროფილის ფაილების თქვენს <xliff:g id="PROFILE_1">%2$s</xliff:g> პროფილში შენახვას არ უშვებს"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"ეს ქმედება დაშვებული არ არის"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს IT ადმინისტრატორს"</string> <string name="root_recent" msgid="1080156975424341623">"ბოლო"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"ახალი სახელი"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g> ფაილის გადახედვა"</string> <string name="preview_work_file" msgid="4495643735563487273">"სამუშაო ფაილის გადახედვა: <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> პროფილის <xliff:g id="FILENAME">%2$s</xliff:g> ფაილისგადახედვა"</string> <string name="apps_row_title" msgid="3340490016663092925">"ფაილების დათვალიერება სხვა აპებში"</string> <string name="anonymous_application" msgid="7633027057951625862">"ანონიმური"</string> <string name="open_tree_button" msgid="6402871398424497776">"ამ საქაღალდის გამოყენება"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"ამ საქაღალდეს ვერ გამოიყენებთ"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"თქვენი კონფიდენციალურობის დასაცავად აირჩიეთ სხვა საქაღალდე"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"ახალი საქაღალდის შექმნა"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"ამ ტელეფონში ძიება"</string> + <string name="search_bar_hint" msgid="146031513183888721">"ამ მოწყობილობის ძიება"</string> <string name="delete_search_history" msgid="2202015025607694515">"ძიების ისტორიის წაშლა <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"პირადი"</string> <string name="work_tab" msgid="7265359366883747413">"სამსახური"</string> diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml index 5e984e42e..9bc4c9a51 100644 --- a/res/values-kk/strings.xml +++ b/res/values-kk/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Тасымалдау…"</string> <string name="menu_compress" msgid="37539111904724188">"Сығу"</string> <string name="menu_extract" msgid="8171946945982532262">"Алынуда…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Барлығын шығарып алу…"</string> <string name="menu_rename" msgid="1883113442688817554">"Атын өзгерту"</string> <string name="menu_inspect" msgid="7279855349299446224">"Ақпарат алу"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Жасырын файлдарды көрсету"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Контент қазір жүктелмейді"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Жұмыс қолданбалары кідіртілді"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Жұмыс қолданбаларын қосу"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> қолданбалары уақытша тоқтатылды"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> қолданбаларын қосу"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Жұмыс файлдарын таңдау мүмкін емес"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Әкімші жұмыс файлдарына жеке қолданбадан кіруге рұқсат етпейді."</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Жеке файлдарды сақтау мүмкін емес"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Әкімші жұмыс қолданбасынан жеке файлдарға кіруге рұқсат етпейді."</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> файлдарын таңдау мүмкін емес"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Әкімшіңіз сізге <xliff:g id="PROFILE_0">%1$s</xliff:g> файлдарын <xliff:g id="PROFILE_1">%2$s</xliff:g> қолданбасынан пайдалануға рұқсат бермейді."</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Жұмыс профиліңізге сақтау мүмкін емес"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Әкімші жеке файлдарды жұмыс профиліңізге сақтауға рұқсат етпейді."</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Жеке профиліңізге сақтау мүмкін емес"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Әкімші жұмыс файлдарын жеке профиліңізге сақтауға рұқсат етпейді."</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> профиліне сақтау мүмкін емес"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Әкімшіңіз сізге <xliff:g id="PROFILE_0">%1$s</xliff:g> файлдарын <xliff:g id="PROFILE_1">%2$s</xliff:g> профиліңізге сақтауға рұқсат бермейді."</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Бұл әрекетке рұқсат берілмеген"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Толығырақ ақпарат үшін әкімшімен хабарласыңыз."</string> <string name="root_recent" msgid="1080156975424341623">"Соңғы"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Жаңа атауы"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g> файлын алдын ала көру"</string> <string name="preview_work_file" msgid="4495643735563487273">"<xliff:g id="FILENAME">%1$s</xliff:g> жұмыс файлын алдын ала көру"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> файлын (<xliff:g id="FILENAME">%2$s</xliff:g>) алдын ала көру"</string> <string name="apps_row_title" msgid="3340490016663092925">"Басқа қолданбалардағы файлдарды шолу"</string> <string name="anonymous_application" msgid="7633027057951625862">"Анонимді"</string> <string name="open_tree_button" msgid="6402871398424497776">"Осы қалтаны пайдалану"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Бұл қалтаны пайдалану мүмкін емес"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Құпиялықты қорғау мақсатында басқа қалта таңдаңыз"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Жаңа қалта жасау"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Осы телефоннан іздеу"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Осы құрылғыда іздеу"</string> <string name="delete_search_history" msgid="2202015025607694515">"Іздеу тарихын <xliff:g id="TEXT">%1$s</xliff:g> жою"</string> <string name="personal_tab" msgid="3878576287868528503">"Жеке"</string> <string name="work_tab" msgid="7265359366883747413">"Жұмыс"</string> diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml index c190ceee5..87ac1cf9d 100644 --- a/res/values-km/strings.xml +++ b/res/values-km/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"ផ្លាស់ទីទៅ…"</string> <string name="menu_compress" msgid="37539111904724188">"បង្ហាប់"</string> <string name="menu_extract" msgid="8171946945982532262">"ស្រង់ទៅ…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"ស្រង់ចេញទាំងអស់…"</string> <string name="menu_rename" msgid="1883113442688817554">"ប្ដូរឈ្មោះ"</string> <string name="menu_inspect" msgid="7279855349299446224">"ទទួលព័ត៌មាន"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"បង្ហាញឯកសារដែលបានលាក់"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"មិនអាចដំណើរការមាតិកាបានទេនៅពេលនេះ"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"កម្មវិធីការងារត្រូវបានផ្អាក"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"បើកកម្មវិធីការងារ"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"កម្មវិធី<xliff:g id="PROFILE">%1$s</xliff:g>ត្រូវបានផ្អាក"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"បើកកម្មវិធី<xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"មិនអាចជ្រើសរើសឯកសារការងារបានទេ"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"អ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នកមិនអនុញ្ញាតឱ្យអ្នកចូលប្រើឯកសារការងារពីកម្មវិធីផ្ទាល់ខ្លួនទេ"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"មិនអាចជ្រើសរើសឯកសារផ្ទាល់ខ្លួនបានទេ"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"អ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នកមិនអនុញ្ញាតឱ្យអ្នកចូលប្រើឯកសារផ្ទាល់ខ្លួនពីកម្មវិធីការងារទេ"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"មិនអាចជ្រើសរើសឯកសារ<xliff:g id="PROFILE">%1$s</xliff:g>បានទេ"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"អ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នកមិនអនុញ្ញាតឱ្យអ្នកចូលប្រើឯកសារ<xliff:g id="PROFILE_0">%1$s</xliff:g>ពីកម្មវិធី<xliff:g id="PROFILE_1">%2$s</xliff:g>ទេ"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"មិនអាចរក្សាទុកទៅកម្រងព័ត៌មានការងារបានទេ"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"អ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នកមិនអនុញ្ញាតឱ្យអ្នករក្សាទុកឯកសារផ្ទាល់ខ្លួនទៅកម្រងព័ត៌មានការងាររបស់អ្នកទេ"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"មិនអាចរក្សាទុកកម្រងព័ត៌មានផ្ទាល់ខ្លួនបានទេ"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"អ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នកមិនអនុញ្ញាតឱ្យអ្នករក្សាទុកឯកសារការងារទៅកម្រងព័ត៌មានផ្ទាល់ខ្លួនរបស់អ្នកទេ"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"មិនអាចរក្សាទុកទៅកម្រងព័ត៌មាន<xliff:g id="PROFILE">%1$s</xliff:g>ទេ"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"អ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នកមិនអនុញ្ញាតឱ្យអ្នករក្សាទុកឯកសារ<xliff:g id="PROFILE_0">%1$s</xliff:g>ទៅកម្រងព័ត៌មាន<xliff:g id="PROFILE_1">%2$s</xliff:g>របស់អ្នកទេ"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"សកម្មភាពនេះមិនត្រូវបានអនុញ្ញាតទេ"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"ដើម្បីស្វែងយល់បន្ថែម សូមទាក់ទងអ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នក"</string> <string name="root_recent" msgid="1080156975424341623">"ថ្មីៗ"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"ឈ្មោះថ្មី"</string> <string name="preview_file" msgid="4056622696305432343">"មើលឯកសារ <xliff:g id="FILENAME">%1$s</xliff:g> សាកល្បង"</string> <string name="preview_work_file" msgid="4495643735563487273">"មើលឯកសារការងារ <xliff:g id="FILENAME">%1$s</xliff:g> សាកល្បង"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"មើលឯកសារ<xliff:g id="PROFILE">%1$s</xliff:g> <xliff:g id="FILENAME">%2$s</xliff:g> សាកល្បង"</string> <string name="apps_row_title" msgid="3340490016663092925">"រុករកឯកសារនៅក្នុងកម្មវិធីផ្សេងទៀត"</string> <string name="anonymous_application" msgid="7633027057951625862">"អនាមិក"</string> <string name="open_tree_button" msgid="6402871398424497776">"ប្រើថតនេះ"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"មិនអាចប្រើថតនេះបានទេ"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"ដើម្បីការពារឯកជនភាពរបស់អ្នក សូមជ្រើសរើសថតផ្សេងទៀត"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"បង្កើតថតថ្មី"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"ស្វែងរកក្នុងទូរសព្ទនេះ"</string> + <string name="search_bar_hint" msgid="146031513183888721">"ស្វែងរកឧបករណ៍នេះ"</string> <string name="delete_search_history" msgid="2202015025607694515">"លុបប្រវត្តិស្វែងរក <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"ផ្ទាល់ខ្លួន"</string> <string name="work_tab" msgid="7265359366883747413">"ការងារ"</string> diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml index f4ee24958..bc89a9f08 100644 --- a/res/values-kn/strings.xml +++ b/res/values-kn/strings.xml @@ -25,7 +25,7 @@ <!-- no translation found for launcher_label (799410258349837668) --> <skip /> <string name="title_open" msgid="3165686459158020921">"ಇಲ್ಲಿಂದ ತೆರೆಯಿರಿ"</string> - <string name="title_save" msgid="4384490653102710025">"ಇವುಗಳಲ್ಲಿ ಉಳಿಸಿ"</string> + <string name="title_save" msgid="4384490653102710025">"ಇವುಗಳಲ್ಲಿ ಸೇವ್ ಮಾಡಿ"</string> <string name="menu_create_dir" msgid="2413624798689091042">"ಹೊಸ ಫೋಲ್ಡರ್"</string> <string name="menu_grid" msgid="1453636521731880680">"ಗ್ರಿಡ್ ವೀಕ್ಷಣೆ"</string> <string name="menu_list" msgid="6714267452146410402">"ಪಟ್ಟಿ ವೀಕ್ಷಣೆ"</string> @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"ಇದಕ್ಕೆ ಸರಿಸಿ…"</string> <string name="menu_compress" msgid="37539111904724188">"ಕುಗ್ಗಿಸಿ"</string> <string name="menu_extract" msgid="8171946945982532262">"ಇದಕ್ಕೆ ಬೇರ್ಪಡಿಸಲಾಗಿದೆ…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"ಎಲ್ಲವನ್ನೂ ಎಕ್ಸ್ಟ್ರ್ಯಾಕ್ಟ್ ಮಾಡಿ…"</string> <string name="menu_rename" msgid="1883113442688817554">"ಮರುಹೆಸರಿಸು"</string> <string name="menu_inspect" msgid="7279855349299446224">"ಮಾಹಿತಿಯನ್ನು ಪಡೆಯಿರಿ"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"ಮರೆಮಾಡಿದ ಫೈಲ್ಗಳನ್ನು ತೋರಿಸಿ"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"ಈ ಕ್ಷಣದಲ್ಲಿ ವಿಷಯವನ್ನು ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್ಗಳನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್ಗಳನ್ನು ಆನ್ ಮಾಡಿ"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> ಆ್ಯಪ್ಗಳನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> ಆ್ಯಪ್ಗಳನ್ನು ಆನ್ ಮಾಡಿ"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"ಉದ್ಯೋಗದ ಫೈಲ್ಗಳನ್ನು ಆಯ್ಕೆ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"ವೈಯಕ್ತಿಕ ಆ್ಯಪ್ ಒಂದರಿಂದ ಉದ್ಯೋಗದ ಫೈಲ್ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು ನಿಮ್ಮ ಐಟಿ ನಿರ್ವಾಹಕರು ನಿಮಗೆ ಅನುಮತಿಸುವುದಿಲ್ಲ"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"ವೈಯಕ್ತಿಕ ಫೈಲ್ಗಳನ್ನು ಆಯ್ಕೆ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್ ಒಂದರಿಂದ ವೈಯಕ್ತಿಕ ಫೈಲ್ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು ನಿಮ್ಮ ಐಟಿ ನಿರ್ವಾಹಕರು ನಿಮಗೆ ಅನುಮತಿಸುವುದಿಲ್ಲ"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> ಫೈಲ್ಗಳನ್ನು ಆಯ್ಕೆ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರು <xliff:g id="PROFILE_1">%2$s</xliff:g> ಆ್ಯಪ್ನಿಂದ <xliff:g id="PROFILE_0">%1$s</xliff:g> ಫೈಲ್ಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು ನಿಮಗೆ ಅನುಮತಿಸುವುದಿಲ್ಲ"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ಗೆ ಉಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"ನಿಮ್ಮ ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ಗೆ ವೈಯಕ್ತಿಕ ಫೈಲ್ಗಳನ್ನು ಉಳಿಸಲು ನಿಮ್ಮ ಐಟಿ ನಿರ್ವಾಹಕರು ನಿಮಗೆ ಅನುಮತಿಸುವುದಿಲ್ಲ"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"ವೈಯಕ್ತಿಕ ಪ್ರೊಫೈಲ್ಗೆ ಉಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ಪ್ರೊಫೈಲ್ಗೆ ಉದ್ಯೋಗದ ಫೈಲ್ಗಳನ್ನು ಉಳಿಸಲು ನಿಮ್ಮ ಐಟಿ ನಿರ್ವಾಹಕರು ನಿಮಗೆ ಅನುಮತಿಸುವುದಿಲ್ಲ"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> ಪ್ರೊಫೈಲ್ಗೆ ಸೇವ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರು ನಿಮ್ಮ <xliff:g id="PROFILE_1">%2$s</xliff:g> ಪ್ರೊಫೈಲ್ಗೆ <xliff:g id="PROFILE_0">%1$s</xliff:g> ಫೈಲ್ಗಳನ್ನು ಸೇವ್ ಮಾಡಲು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"ಈ ಕ್ರಿಯೆಯನ್ನು ಅನುಮತಿಸಲಾಗುವುದಿಲ್ಲ"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"ಇನ್ನಷ್ಟು ತಿಳಿಯಲು, ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ"</string> <string name="root_recent" msgid="1080156975424341623">"ಇತ್ತೀಚಿನದು"</string> @@ -168,7 +175,7 @@ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>ಐಟಂಗಳನ್ನು ಅಳಿಸಲಾಗಲಿಲ್ಲ</item> </plurals> <string name="notification_touch_for_details" msgid="2385563502445129570">"ವಿವರಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> - <string name="close" msgid="905969391788869975">"ಮುಚ್ಚು"</string> + <string name="close" msgid="905969391788869975">"ಮುಚ್ಚಿ"</string> <plurals name="copy_failure_alert_content" formatted="false" msgid="5570549471912990536"> <item quantity="one">ಈ ಫೈಲ್ಗಳನ್ನು ನಕಲು ಮಾಡಿರಲಿಲ್ಲ: <xliff:g id="LIST_1">%1$s</xliff:g></item> <item quantity="other">ಈ ಫೈಲ್ಗಳನ್ನು ನಕಲು ಮಾಡಿರಲಿಲ್ಲ: <xliff:g id="LIST_1">%1$s</xliff:g></item> @@ -215,19 +222,19 @@ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ಐಟಂಗಳು</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ಐಟಂಗಳು</item> </plurals> - <string name="delete_filename_confirmation_message" msgid="8338069763240613258">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ಅಳಿಸುವುದೇ?"</string> - <string name="delete_foldername_confirmation_message" msgid="9084085260877704140">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ಫೋಲ್ಡರ್ ಮತ್ತು ಅದರ ವಿಷಯಗಳನ್ನು ಅಳಿಸುವುದೇ?"</string> + <string name="delete_filename_confirmation_message" msgid="8338069763240613258">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ಅಳಿಸಬೇಕೆ?"</string> + <string name="delete_foldername_confirmation_message" msgid="9084085260877704140">"\"<xliff:g id="NAME">%1$s</xliff:g>\" ಫೋಲ್ಡರ್ ಮತ್ತು ಅದರ ವಿಷಯಗಳನ್ನು ಅಳಿಸಬೇಕೆ?"</string> <plurals name="delete_files_confirmation_message" formatted="false" msgid="4866664063250034142"> - <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್ಗಳನ್ನು ಅಳಿಸುವುದೇ?</item> - <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್ಗಳನ್ನು ಅಳಿಸುವುದೇ?</item> + <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್ಗಳನ್ನು ಅಳಿಸಬೇಕೆ?</item> + <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್ಗಳನ್ನು ಅಳಿಸಬೇಕೆ?</item> </plurals> <plurals name="delete_folders_confirmation_message" formatted="false" msgid="1028946402799686388"> - <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೋಲ್ಡರ್ಗಳು ಮತ್ತು ಅವುಗಳ ವಿಷಯಗಳನ್ನು ಅಳಿಸುವುದೇ?</item> - <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೋಲ್ಡರ್ಗಳು ಮತ್ತು ಅವುಗಳ ವಿಷಯಗಳನ್ನು ಅಳಿಸುವುದೇ?</item> + <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೋಲ್ಡರ್ಗಳು ಮತ್ತು ಅವುಗಳ ಕಂಟೆಂಟ್ಗಳನ್ನು ಅಳಿಸಬೇಕೆ?</item> + <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೋಲ್ಡರ್ಗಳು ಮತ್ತು ಅವುಗಳ ಕಂಟೆಂಟ್ಗಳನ್ನು ಅಳಿಸಬೇಕೆ?</item> </plurals> <plurals name="delete_items_confirmation_message" formatted="false" msgid="7285090426511028179"> - <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಐಟಂಗಳನ್ನು ಅಳಿಸುವುದೇ?</item> - <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಐಟಂಗಳನ್ನು ಅಳಿಸುವುದೇ?</item> + <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಐಟಂಗಳನ್ನು ಅಳಿಸಬೇಕೆ?</item> + <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಐಟಂಗಳನ್ನು ಅಳಿಸಬೇಕೆ?</item> </plurals> <string name="images_shortcut_label" msgid="2545168016070493574">"ಚಿತ್ರಗಳು"</string> <string name="archive_loading_failed" msgid="7243436722828766996">"ಬ್ರೌಸಿಂಗ್ಗಾಗಿ ಆರ್ಕೈವ್ ಅನ್ನು ತೆರೆಯಲು ಸಾಧ್ಯವಿಲ್ಲ. ಫೈಲ್ ದೋಷಪೂರಿತವಾಗಿದೆ ಅಥವಾ ಬೆಂಬಲಿಸದ ಸ್ವರೂಪದಲ್ಲಿರಬಹುದು."</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"ಹೊಸ ಹೆಸರು"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g> ಫೈಲ್ ಅನ್ನು ಪೂರ್ವವೀಕ್ಷಿಸಿ"</string> <string name="preview_work_file" msgid="4495643735563487273">"<xliff:g id="FILENAME">%1$s</xliff:g> ಉದ್ಯೋಗದ ಫೈಲ್ ಅನ್ನು ಪೂರ್ವವೀಕ್ಷಣೆ ಮಾಡಿ"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> ಫೈಲ್ <xliff:g id="FILENAME">%2$s</xliff:g> ಅನ್ನು ಪೂರ್ವವೀಕ್ಷಿಸಿ"</string> <string name="apps_row_title" msgid="3340490016663092925">"ಇತರ ಆ್ಯಪ್ಗಳಲ್ಲಿರುವ ಫೈಲ್ಗಳನ್ನು ಬ್ರೌಸ್ ಮಾಡಿ"</string> <string name="anonymous_application" msgid="7633027057951625862">"ಅನಾಮಧೇಯ"</string> <string name="open_tree_button" msgid="6402871398424497776">"ಈ ಫೋಲ್ಡರ್ ಬಳಸಿ"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"ಈ ಫೋಲ್ಡರ್ ಅನ್ನು ಬಳಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"ನಿಮ್ಮ ಗೌಪ್ಯತೆಯನ್ನು ಕಾಪಾಡಲು, ಬೇರೊಂದು ಫೋಲ್ಡರ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"ಹೊಸ ಫೋಲ್ಡರ್ ರಚಿಸಿ"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"ಈ ಫೋನ್ನಲ್ಲಿ ಹುಡುಕಿ"</string> + <string name="search_bar_hint" msgid="146031513183888721">"ಈ ಸಾಧನವನ್ನು ಹುಡುಕಿ"</string> <string name="delete_search_history" msgid="2202015025607694515">"ಹುಡುಕಾಟ ಇತಿಹಾಸವನ್ನು ಅಳಿಸಿ <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"ವೈಯಕ್ತಿಕ"</string> <string name="work_tab" msgid="7265359366883747413">"ಉದ್ಯೋಗ"</string> diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index ae44b2d8d..374b95d93 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"다음으로 이동:"</string> <string name="menu_compress" msgid="37539111904724188">"압축"</string> <string name="menu_extract" msgid="8171946945982532262">"다음 위치에 추출..."</string> + <string name="menu_extract_all" msgid="7335680068521252718">"모두 추출…"</string> <string name="menu_rename" msgid="1883113442688817554">"이름 바꾸기"</string> <string name="menu_inspect" msgid="7279855349299446224">"정보 확인"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"숨겨진 파일 표시"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"현재 콘텐츠를 로드할 수 없습니다."</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"직장 앱이 일시중지됨"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"직장 앱 사용 설정"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> 앱이 일시중지됨"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> 앱 사용 설정"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"직장 파일을 선택할 수 없음"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"IT 관리자가 개인 앱에서 직장 파일에 액세스하도록 허용하지 않습니다."</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"개인 파일을 선택할 수 없음"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"IT 관리자가 직장 앱에서 개인 파일에 액세스하도록 허용하지 않습니다."</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> 파일을 선택할 수 없음"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"IT 관리자가 <xliff:g id="PROFILE_1">%2$s</xliff:g> 앱에서 <xliff:g id="PROFILE_0">%1$s</xliff:g> 파일에 액세스하도록 허용하지 않습니다."</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"직장 프로필에 저장할 수 없음"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"IT 관리자가 직장 프로필에 개인 파일을 저장하도록 허용하지 않습니다."</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"개인 프로필에 저장할 수 없음"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"IT 관리자가 개인 프로필에 직장 파일을 저장하도록 허용하지 않습니다."</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> 프로필에 저장할 수 없음"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"IT 관리자가 <xliff:g id="PROFILE_0">%1$s</xliff:g> 파일을 <xliff:g id="PROFILE_1">%2$s</xliff:g> 프로필에 저장하도록 허용하지 않습니다."</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"금지된 작업"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"자세히 알아보려면 IT 관리자에게 문의하세요."</string> <string name="root_recent" msgid="1080156975424341623">"최근"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"새 이름"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g> 파일 미리보기"</string> <string name="preview_work_file" msgid="4495643735563487273">"직장 파일 <xliff:g id="FILENAME">%1$s</xliff:g> 미리보기"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> 파일(<xliff:g id="FILENAME">%2$s</xliff:g>) 미리보기"</string> <string name="apps_row_title" msgid="3340490016663092925">"다른 앱의 파일 탐색"</string> <string name="anonymous_application" msgid="7633027057951625862">"익명"</string> <string name="open_tree_button" msgid="6402871398424497776">"이 폴더 사용"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"이 폴더를 사용할 수 없음"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"개인정보 보호를 위해 다른 폴더를 선택하세요."</string> <string name="create_new_folder_button" msgid="8859613309559794890">"새 폴더 만들기"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"이 휴대전화 검색"</string> + <string name="search_bar_hint" msgid="146031513183888721">"이 기기 검색"</string> <string name="delete_search_history" msgid="2202015025607694515">"검색 기록 삭제 <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"개인"</string> <string name="work_tab" msgid="7265359366883747413">"직장"</string> diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml index 430886e8c..49ea76f6c 100644 --- a/res/values-ky/strings.xml +++ b/res/values-ky/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Төмөнкүгө жылдыруу..."</string> <string name="menu_compress" msgid="37539111904724188">"Кысуу"</string> <string name="menu_extract" msgid="8171946945982532262">"Төмөнкүгө чыгаруу…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Баарын чыгаруу…"</string> <string name="menu_rename" msgid="1883113442688817554">"Аталышын өзгөртүү"</string> <string name="menu_inspect" msgid="7279855349299446224">"Маалымат алуу"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Жашырылган файлдар көрүнсүн"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Учурда мазмун жүктөлбөй жатат"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Жумуш колдонмолору тындырылды"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Жумуш колдонмолорун күйгүзүү"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> колдонмолору тындырылды"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> колдонмолорун күйгүзүү"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Жумуш файлдарын тандоого болбойт"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"IT администраторуңуз жумуш файлдарына жеке колдонмодон кирүүгө тыюу салды"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Жеке файлдарды тандоого болбойт"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"IT администраторуңуз жеке файлдарга жумуш колдонмосунан кирүүгө тыюу салды"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> файлдарын тандоого болбойт"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"IT администратору <xliff:g id="PROFILE_0">%1$s</xliff:g> файлдарын <xliff:g id="PROFILE_1">%2$s</xliff:g> колдонмосунан пайдаланууга тыюу салды"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Жумуш профилине сактоого болбойт"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"IT администраторуңуз жеке файлдарды жумуш профилине сактоого тыюу салды"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Жеке профилге сактоого болбойт"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"IT администраторуңуз жумуш файлдарын жеке профилде сактоого тыюу салды"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> профилине сактоого болбойт"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"IT администратору <xliff:g id="PROFILE_0">%1$s</xliff:g> файлдарын <xliff:g id="PROFILE_1">%2$s</xliff:g> профилине сактоого тыюу салды"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Бул аракетке уруксат жок"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Көбүрөөк маалымат үчүн, IT администраторуңузга кайрылыңыз"</string> <string name="root_recent" msgid="1080156975424341623">"Акыркы"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Жаңы аталыш"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g> файлын алдын ала көрүү"</string> <string name="preview_work_file" msgid="4495643735563487273">"<xliff:g id="FILENAME">%1$s</xliff:g> жумуш файлын алдын ала көрүү"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> файлын (<xliff:g id="FILENAME">%2$s</xliff:g>) алдын ала көрүү"</string> <string name="apps_row_title" msgid="3340490016663092925">"Башка колдонмолордон файлдарды карап чыгуу"</string> <string name="anonymous_application" msgid="7633027057951625862">"Жашыруун"</string> <string name="open_tree_button" msgid="6402871398424497776">"Бул папканы колдонуу"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Бул папканы колдонууга болбойт"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Коопсуздугуңузду коргоо үчүн башка папканы тандаңыз"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Жаңы папка түзүү"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Ушул телефондо издөө"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Бул түзмөктү издөө"</string> <string name="delete_search_history" msgid="2202015025607694515">"Издөө таржымалы тазалансын: <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Жеке"</string> <string name="work_tab" msgid="7265359366883747413">"Жумуш"</string> diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml index 75f35dc1b..32f741faa 100644 --- a/res/values-lo/strings.xml +++ b/res/values-lo/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"ຍ້າຍໄປໃສ່..."</string> <string name="menu_compress" msgid="37539111904724188">"ບີບອັດ"</string> <string name="menu_extract" msgid="8171946945982532262">"ແຕກໄຟລ໌ໄປ…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"ດຶງຂໍ້ມູນຈາກເອກະສານທັງໝົດ…"</string> <string name="menu_rename" msgid="1883113442688817554">"ປ່ຽນຊື່"</string> <string name="menu_inspect" msgid="7279855349299446224">"ຂໍຂໍ້ມູນ"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"ສະແດງໄຟລ໌ທີ່ເຊື່ອງໄວ້"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"ບໍ່ສາມາດໂຫຼດເນື້ອຫາໄດ້ໃນຂະນະນີ້"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"ຢຸດແອັບບ່ອນເຮັດວຽກຊົ່ວຄາວແລ້ວ"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"ເປີດໃຊ້ແອັບບ່ອນເຮັດວຽກ"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"ແອັບ <xliff:g id="PROFILE">%1$s</xliff:g> ຢຸດຊົ່ວຄາວແລ້ວ"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"ເປີດແອັບ <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"ບໍ່ສາມາດເລືອກໄຟລ໌ວຽກໄດ້"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"ຜູ້ເບິ່ງແຍງໄອທີຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ເຂົ້າເຖິງໄຟລ໌ວຽກຈາກແອັບສ່ວນຕົວໄດ້"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"ບໍ່ສາມາດເລືອກໄຟລ໌ສ່ວນຕົວໄດ້"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"ຜູ້ເບິ່ງແຍງໄອທີຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ເຂົ້າເຖິງໄຟລ໌ສ່ວນຕົວຈາກແອັບວຽກໄດ້"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"ບໍ່ສາມາດເລືອກໄຟລ໌ <xliff:g id="PROFILE">%1$s</xliff:g> ໄດ້"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"ຜູ້ເບິ່ງແຍງໄອທີຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ທ່ານເຂົ້າເຖິງໄຟລ໌ <xliff:g id="PROFILE_0">%1$s</xliff:g> ຈາກແອັບ <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"ບໍ່ສາມາດບັນທຶກໄປໃສ່ໂປຣໄຟລ໌ວຽກໄດ້"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"ຜູ້ເບິ່ງແຍງໄອທີຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ບັນທຶກໄຟລ໌ສ່ວນຕົວໄປໃສ່ໂປຣໄຟລ໌ວຽກທ່ານ"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"ບໍ່ສາມາດບັນທຶກໄປໃສ່ໂປຣໄຟລ໌ສ່ວນຕົວໄດ້"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"ຜູ້ເບິ່ງແຍງໄອທີຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ທ່ານບັນທຶກໄຟລ໌ວຽກໄປໃສ່ໂປຣໄຟລ໌ສ່ວນຕົວຂອງທ່ານໄດ້"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"ບໍ່ສາມາດບັນທຶກໃສ່ໂປຣໄຟລ໌ <xliff:g id="PROFILE">%1$s</xliff:g> ໄດ້"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"ຜູ້ເບິ່ງແຍງໄອທີຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ທ່ານບັນທຶກໄຟລ໌ <xliff:g id="PROFILE_0">%1$s</xliff:g> ໃສ່ໂປຣໄຟລ໌ <xliff:g id="PROFILE_1">%2$s</xliff:g> ຂອງທ່ານ"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"ບໍ່ອະນຸຍາດຄຳສັ່ງນີ້"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"ເພື່ອສຶກສາເພີ່ມເຕີມ, ກະລຸນາຕິດຕໍ່ຜູ້ເບິ່ງແຍງໄອທີຂອງທ່ານ"</string> <string name="root_recent" msgid="1080156975424341623">"ຫຼ້າສຸດ"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"ຊື່ໃໝ່"</string> <string name="preview_file" msgid="4056622696305432343">"ເບິ່ງຕົວຢ່າງໄຟລ໌ <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"ເບິ່ງຕົວຢ່າງໄຟລ໌ວຽກ <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"ຕົວຢ່າງໄຟລ໌ <xliff:g id="PROFILE">%1$s</xliff:g> <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"ເລືອກໄຟລ໌ໃນແອັບອື່ນ"</string> <string name="anonymous_application" msgid="7633027057951625862">"ບໍ່ລະບຸຊື່"</string> <string name="open_tree_button" msgid="6402871398424497776">"ໃຊ້ໂຟນເດີນີ້"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"ບໍ່ສາມາດໃຊ້ໂຟນເດີນີ້ໄດ້"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"ໃຫ້ເລືອກໂຟນເດີອື່ນເພື່ອປົກປ້ອງຄວາມເປັນສ່ວນຕົວຂອງທ່ານ"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"ສ້າງໂຟນເດີໃໝ່"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"ຊອກຫາໂທລະສັບໜ່ວຍນີ້"</string> + <string name="search_bar_hint" msgid="146031513183888721">"ຊອກຫາອຸປະກອນນີ້"</string> <string name="delete_search_history" msgid="2202015025607694515">"ລຶບປະຫວັດການຊອກຫາ <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"ສ່ວນຕົວ"</string> <string name="work_tab" msgid="7265359366883747413">"ວຽກ"</string> diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml index e21563f93..9c3142dc4 100644 --- a/res/values-lt/strings.xml +++ b/res/values-lt/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Perkelti į…"</string> <string name="menu_compress" msgid="37539111904724188">"Suglaudinti"</string> <string name="menu_extract" msgid="8171946945982532262">"Išskleisti į..."</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Išskleisti viską…"</string> <string name="menu_rename" msgid="1883113442688817554">"Pervardyti"</string> <string name="menu_inspect" msgid="7279855349299446224">"Gauti informacijos"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Rodyti paslėptus failus"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Šiuo metu nepavyksta įkelti turinio"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Darbo programos pristabdytos"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Įjungti darbo programas"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> programos pristabdytos"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Įjungti <xliff:g id="PROFILE">%1$s</xliff:g> programas"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Negalima pasirinkti darbo failų"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"IT administratorius neleidžia pasiekti darbo failų iš asmeninės programos"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Negalima pasirinkti asmeninių failų"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"IT administratorius neleidžia pasiekti asmeninių failų iš darbo programos"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Negalima pasirinkti <xliff:g id="PROFILE">%1$s</xliff:g> failų"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"IT administratorius neleidžia pasiekti <xliff:g id="PROFILE_0">%1$s</xliff:g> failų iš <xliff:g id="PROFILE_1">%2$s</xliff:g> programos"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Negalima saugoti darbo profilyje"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"IT administratorius neleidžia saugoti asmeninių failų darbo profilyje"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Negalima saugoti asmeniniame profilyje"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"IT administratorius neleidžia saugoti darbo failų asmeniniame profilyje"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Negalima išsaugoti <xliff:g id="PROFILE">%1$s</xliff:g> profilyje"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"IT administratorius neleidžia išsaugoti <xliff:g id="PROFILE_0">%1$s</xliff:g> failų <xliff:g id="PROFILE_1">%2$s</xliff:g> profilyje"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Šis veiksmas neleidžiamas"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Jei norite sužinoti daugiau, susisiekite su savo IT administratoriumi"</string> <string name="root_recent" msgid="1080156975424341623">"Naujausi"</string> @@ -310,6 +317,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Naujas pavadinimas"</string> <string name="preview_file" msgid="4056622696305432343">"Peržiūrėti failą „<xliff:g id="FILENAME">%1$s</xliff:g>“"</string> <string name="preview_work_file" msgid="4495643735563487273">"Peržiūrėti darbo failą „<xliff:g id="FILENAME">%1$s</xliff:g>“"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Peržiūrėti <xliff:g id="PROFILE">%1$s</xliff:g> failą „<xliff:g id="FILENAME">%2$s</xliff:g>“"</string> <string name="apps_row_title" msgid="3340490016663092925">"Failų naršymas kitose programose"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anoniminė"</string> <string name="open_tree_button" msgid="6402871398424497776">"Naudoti šį aplanką"</string> @@ -318,7 +326,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Negalima naudoti šio aplanko"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Kad apsaugotumėte privatumą, pasirinkite kitą aplanką"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Kurti naują aplanką"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Ieškoti šiame telefone"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Ieškoti šiame įrenginyje"</string> <string name="delete_search_history" msgid="2202015025607694515">"Ištrinkite paieškos istoriją <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Asmeninis"</string> <string name="work_tab" msgid="7265359366883747413">"Darbo"</string> diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml index c410d6897..8afe403b6 100644 --- a/res/values-lv/strings.xml +++ b/res/values-lv/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Pārvietot uz…"</string> <string name="menu_compress" msgid="37539111904724188">"Saspiest"</string> <string name="menu_extract" msgid="8171946945982532262">"Izvilkt..."</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Izgūt visu…"</string> <string name="menu_rename" msgid="1883113442688817554">"Pārdēvēt"</string> <string name="menu_inspect" msgid="7279855349299446224">"Iegūt informāciju"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Rādīt paslēptos failus"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Pašlaik nevar ielādēt saturu."</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Darba lietotnes ir apturētas"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Ieslēgt darba lietotnes"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Šāda profila lietotņu darbība ir pārtraukta: <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Ieslēgt šāda profila lietotnes: <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Nevar atlasīt darba failus"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Jūsu IT administrators neatļauj piekļūt darba failiem no personīgās lietotnes"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Nevar atlasīt personīgos failus"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Jūsu IT administrators neatļauj piekļūt personīgajiem failiem no darba lietotnes"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Nevar atlasīt šāda profila failus: <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Jūsu IT administrators neļauj jums saglabāt viena profila (<xliff:g id="PROFILE_0">%1$s</xliff:g>) failiem, izmantojot cita profila (<xliff:g id="PROFILE_1">%2$s</xliff:g>) lietotni."</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Nevar saglabāt darba profilā"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Jūsu IT administrators neatļauj saglabāt personīgos failus jūsu darba profilā"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Nevar saglabāt personīgajā profilā"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Jūsu IT administrators neatļauj saglabāt darba failus jūsu personīgajā profilā"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Nevar saglabāt šādā profilā: <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Jūsu IT administrators neļauj jums saglabāt viena profila (<xliff:g id="PROFILE_0">%1$s</xliff:g>) failus citā profilā (<xliff:g id="PROFILE_1">%2$s</xliff:g>)."</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Šī darbība nav atļauta"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Lai uzzinātu vairāk, sazinieties ar organizācijas IT administratoru"</string> <string name="root_recent" msgid="1080156975424341623">"Neseni"</string> @@ -288,6 +295,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Jauns nosaukums"</string> <string name="preview_file" msgid="4056622696305432343">"Priekšskatīt failu <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Darba faila <xliff:g id="FILENAME">%1$s</xliff:g> priekšskatīšana"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Priekšskatīt failu <xliff:g id="FILENAME">%2$s</xliff:g> no šāda profila: <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Failu pārlūkošana citās lietotnēs"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonīma"</string> <string name="open_tree_button" msgid="6402871398424497776">"Izmantot šo mapi"</string> @@ -296,7 +304,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Nevar izmantot šo mapi"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Lai aizsargātu savu konfidencialitāti, izvēlieties citu mapi."</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Izveidot jaunu mapi"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Meklēt šajā tālrunī"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Meklēt šajā ierīcē"</string> <string name="delete_search_history" msgid="2202015025607694515">"Meklēšanas vēstures dzēšana <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Personīgais profils"</string> <string name="work_tab" msgid="7265359366883747413">"Darba profils"</string> diff --git a/res/values-mk/inspector_strings.xml b/res/values-mk/inspector_strings.xml index 9687d1d5f..72c6f9c90 100644 --- a/res/values-mk/inspector_strings.xml +++ b/res/values-mk/inspector_strings.xml @@ -37,7 +37,7 @@ <string name="metadata_duration" msgid="3115494422055472715">"Времетраење"</string> <string name="metadata_date_time" msgid="1090351199248114406">"Фотографирано на"</string> <string name="metadata_focal_length" msgid="3440735161407699893">"Фокусна должина"</string> - <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> мм"</string> + <string name="metadata_focal_format" msgid="8542211707962355623">"<xliff:g id="LENGTH">%1$.2f </xliff:g> mm"</string> <string name="metadata_iso_speed_ratings" msgid="1699781252899759058">"Еквивалент на ISO"</string> <string name="metadata_iso_format" msgid="4153285204012694861">"ISO <xliff:g id="ISO_SPEED">%1$d</xliff:g>"</string> <string name="metadata_artist" msgid="8972421485694988540">"Изведувач"</string> diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml index 5a3ee3011..94f840c94 100644 --- a/res/values-mk/strings.xml +++ b/res/values-mk/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Премести во…"</string> <string name="menu_compress" msgid="37539111904724188">"Компримирај"</string> <string name="menu_extract" msgid="8171946945982532262">"Отпакувај во…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Извлечи сѐ…"</string> <string name="menu_rename" msgid="1883113442688817554">"Преименувај"</string> <string name="menu_inspect" msgid="7279855349299446224">"Добијте информации"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Прикажи скриени датотеки"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Во моментов не може да се вчита содржината."</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Работните апликации се паузирани"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Вклучете ги работните апликации"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> апликации се паузирани"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Вклучете ги <xliff:g id="PROFILE">%1$s</xliff:g> апликации"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Не може да се изберат работни датотеки"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"IT-администраторот не ви дозволува да пристапувате до работни датотеки од лична апликација"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Не може да се изберат лични датотеки"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"IT-администраторот не ви дозволува да пристапувате до лични датотеки од работна апликација"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Не може да се изберат датотеки од <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"IT-администраторот не ви дозволува да пристапите до датотеките од <xliff:g id="PROFILE_0">%1$s</xliff:g> преку <xliff:g id="PROFILE_1">%2$s</xliff:g> апликација"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Не може да се зачува во работниот профил"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"IT-администраторот не ви дозволува да зачувувате лични датотеки во работниот профил"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Не може да се зачува во личниот профил"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"IT-администраторот не ви дозволува да зачувувате работни датотеки во личниот профил"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Не може да се зачува на <xliff:g id="PROFILE">%1$s</xliff:g> профил"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"IT-администраторот не ви дозволува да ги зачувате датотеките од <xliff:g id="PROFILE_0">%1$s</xliff:g> на вашиот <xliff:g id="PROFILE_1">%2$s</xliff:g> профил"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Дејството не е дозволено"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"За да дознаете повеќе, контактирајте со IT-администраторот"</string> <string name="root_recent" msgid="1080156975424341623">"Неодамнешни"</string> @@ -234,7 +241,7 @@ <string name="name_conflict" msgid="28407269328862986">"Датотека со истото име веќе постои."</string> <string name="authentication_required" msgid="8030880723643436099">"За да го прегледате адресаров, најавете се на <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="cant_display_content" msgid="8633226333229417237">"Не може да се прикаже содржината"</string> - <string name="sign_in" msgid="6253762676723505592">"Најави се"</string> + <string name="sign_in" msgid="6253762676723505592">"Најавете се"</string> <string name="new_archive_file_name" msgid="1604650338077249838">"архива<xliff:g id="EXTENSION">%s</xliff:g>"</string> <string name="overwrite_file_confirmation_message" msgid="2496109652768222716">"Да се презапише <xliff:g id="NAME">%1$s</xliff:g>?"</string> <string name="continue_in_background" msgid="1974214559047793331">"Продолжи во заднина"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Ново име"</string> <string name="preview_file" msgid="4056622696305432343">"Прегледајте ја датотеката <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Прегледајте ја работната датотека <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Прегледајте ја датотеката <xliff:g id="FILENAME">%2$s</xliff:g> на <xliff:g id="PROFILE">%1$s</xliff:g> профил"</string> <string name="apps_row_title" msgid="3340490016663092925">"Прелистувајте датотеки во други апликации"</string> <string name="anonymous_application" msgid="7633027057951625862">"Анонимна"</string> <string name="open_tree_button" msgid="6402871398424497776">"Користи ја папкава"</string> @@ -274,9 +282,9 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Не може да се користи папкава"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"За да ја заштитите вашата приватност, изберете друга папка"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Создај нова папка"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Пребарајте го телефонов"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Пребарајте го уредов"</string> <string name="delete_search_history" msgid="2202015025607694515">"Избришете ја историјата на пребарување <xliff:g id="TEXT">%1$s</xliff:g>"</string> - <string name="personal_tab" msgid="3878576287868528503">"Личен"</string> + <string name="personal_tab" msgid="3878576287868528503">"Лично"</string> <string name="work_tab" msgid="7265359366883747413">"Работен"</string> <string name="a11y_work" msgid="7504431382825242153">"Работен профил"</string> <string name="drag_from_another_app" msgid="8310249276199969905">"Не може да преместувате датотеки од друга апликација."</string> diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml index 4f9ec994e..cb43ab59a 100644 --- a/res/values-ml/strings.xml +++ b/res/values-ml/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"ഇതിലേക്ക് നീക്കുക..."</string> <string name="menu_compress" msgid="37539111904724188">"കംപ്രസ് ചെയ്യുക"</string> <string name="menu_extract" msgid="8171946945982532262">"എക്സ്ട്രാക്റ്റുചെയ്യുക…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"എക്സ്ട്രാക്റ്റ് ചെയ്യൂ…"</string> <string name="menu_rename" msgid="1883113442688817554">"പേര് മാറ്റുക"</string> <string name="menu_inspect" msgid="7279855349299446224">"വിവരങ്ങൾ നേടുക"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"മറച്ചിരിക്കുന്ന ഫയൽ കാണിക്കൂ"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"ഇപ്പോൾ ഉള്ളടക്കം ലോഡുചെയ്യാൻ കഴിയില്ല"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"ഔദ്യോഗിക ആപ്പുകൾ തൽക്കാലം നിർത്തിയിരിക്കുന്നു"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"ഔദ്യോഗിക ആപ്പുകൾ ഓണാക്കുക"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> ആപ്പുകൾ താൽക്കാലികമായി നിർത്തി"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> ആപ്പുകൾ ഓണാക്കുക"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"ഔദ്യോഗിക ഫയലുകൾ തിരഞ്ഞെടുക്കാനാവില്ല"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"വ്യക്തിപരമായ ആപ്പിൽ നിന്ന് ഔദ്യോഗിക ഫയലുകൾ ആക്സസ് ചെയ്യാൻ നിങ്ങളുടെ ഐടി അഡ്മിൻ അനുവദിക്കുന്നില്ല"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"വ്യക്തിപര ഫയലുകൾ തിരഞ്ഞെടുക്കാനാവില്ല"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"ഔദ്യോഗിക ആപ്പിൽ നിന്ന് വ്യക്തിപര ഫയലുകൾ ആക്സസ് ചെയ്യാൻ നിങ്ങളുടെ ഐടി അഡ്മിൻ അനുവദിക്കുന്നില്ല"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> ഫയലുകൾ തിരഞ്ഞെടുക്കാനാകുന്നില്ല"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"<xliff:g id="PROFILE_1">%2$s</xliff:g> ആപ്പിൽ നിന്ന് <xliff:g id="PROFILE_0">%1$s</xliff:g> ഫയലുകൾ ആക്സസ് ചെയ്യാൻ നിങ്ങളുടെ ഐടി അഡ്മിൻ അനുവദിക്കുന്നില്ല"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"ഔദ്യോഗിക പ്രൊഫൈലിലേക്ക് സംരക്ഷിക്കാനാവില്ല"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"വ്യക്തിപര ഫയലുകൾ ഔദ്യോഗിക പ്രൊഫൈലിലേക്ക് സംരക്ഷിക്കാൻ നിങ്ങളുടെ ഐടി അഡ്മിൻ അനുവദിക്കുന്നില്ല"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"വ്യക്തിപര പ്രൊഫൈലിലേക്ക് സംരക്ഷിക്കാനാവില്ല"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"ഔദ്യോഗിക ഫയലുകൾ നിങ്ങളുടെ വ്യക്തിപര പ്രൊഫൈലിലേക്ക് സംരക്ഷിക്കാൻ ഐടി അഡ്മിൻ അനുവദിക്കുന്നില്ല"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> പ്രൊഫൈലിലേക്ക് സംരക്ഷിക്കാനാകുന്നില്ല"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"<xliff:g id="PROFILE_0">%1$s</xliff:g> ഫയലുകൾ നിങ്ങളുടെ <xliff:g id="PROFILE_1">%2$s</xliff:g> പ്രൊഫൈലിലേക്ക് സംരക്ഷിക്കാൻ നിങ്ങളുടെ ഐടി അഡ്മിൻ അനുവദിക്കുന്നില്ല"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"ഈ പ്രവൃത്തി അനുവദനീയമല്ല"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"കൂടുതലറിയാൻ, നിങ്ങളുടെ ഐടി അഡ്മിനെ ബന്ധപ്പെടുക"</string> <string name="root_recent" msgid="1080156975424341623">"ഏറ്റവും പുതിയത്"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"പുതിയ പേര്"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g> ഫയൽ പ്രിവ്യൂ ചെയ്യുക"</string> <string name="preview_work_file" msgid="4495643735563487273">"<xliff:g id="FILENAME">%1$s</xliff:g> എന്ന ഔദ്യോഗിക ഫയൽ പ്രിവ്യൂ ചെയ്യുക"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> ഫയൽ <xliff:g id="FILENAME">%2$s</xliff:g> പ്രിവ്യൂ ചെയ്യുക"</string> <string name="apps_row_title" msgid="3340490016663092925">"ഫയലുകള് മറ്റ് ആപ്പുകളില് ബ്രൗസ് ചെയ്യുക"</string> <string name="anonymous_application" msgid="7633027057951625862">"അജ്ഞാതം"</string> <string name="open_tree_button" msgid="6402871398424497776">"ഈ ഫോൾഡർ ഉപയോഗിക്കുക"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"ഈ ഫോൾഡർ ഉപയോഗിക്കാനാവില്ല"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"നിങ്ങളുടെ സ്വകാര്യത പരിരക്ഷിക്കാൻ മറ്റൊരു ഫോൾഡർ തിരഞ്ഞെടുക്കുക"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"പുതിയ ഫോൾഡർ സൃഷ്ടിക്കുക"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"ഈ ഫോണിൽ തിരയുക"</string> + <string name="search_bar_hint" msgid="146031513183888721">"ഈ ഉപകരണം തിരയുക"</string> <string name="delete_search_history" msgid="2202015025607694515">"തിരയൽ ചരിത്രം <xliff:g id="TEXT">%1$s</xliff:g> ഇല്ലാതാക്കുക"</string> <string name="personal_tab" msgid="3878576287868528503">"വ്യക്തിപരം"</string> <string name="work_tab" msgid="7265359366883747413">"ഔദ്യോഗികം"</string> diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml index f86cbfd1c..3172a07f4 100644 --- a/res/values-mn/strings.xml +++ b/res/values-mn/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Дараахад зөөх"</string> <string name="menu_compress" msgid="37539111904724188">"Шахах"</string> <string name="menu_extract" msgid="8171946945982532262">"Дараахад задлах…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Бүгдийг задлах…"</string> <string name="menu_rename" msgid="1883113442688817554">"Нэр өөрчлөх"</string> <string name="menu_inspect" msgid="7279855349299446224">"Мэдээлэл авах"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Нуусан файлудыг харуул"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Агуулгыг ачаалах боломжгүй байна"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Ажлын аппуудыг түр зогсоосон"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Ажлын аппуудыг асаах"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g>-н аппуудыг түр зогсоосон"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g>-н аппуудыг асаах"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Ажлын файлуудыг сонгох боломжгүй байна"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Таны мэдээлэл технологийн админ танд хувийн аппаас ажлын файлуудад хандахыг зөвшөөрөөгүй байна"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Хувийн файлуудыг сонгох боломжгүй байна"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Таны мэдээлэл технологийн админ ажлын аппаас хувийн файлуудад хандахыг танд зөвшөөрөөгүй байна"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g>-н файлуудыг сонгох боломжгүй"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Танай IT админ танд <xliff:g id="PROFILE_1">%2$s</xliff:g>-н аппаас <xliff:g id="PROFILE_0">%1$s</xliff:g>-н файлуудад хандахыг зөвшөөрдөггүй"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Ажлын профайлыг хадгалах боломжгүй байна"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Таны мэдээлэл технологийн админ танд ажлын профайлдаа хувийн файлууд хадгалахыг зөвшөөрөхгүй байна"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Хувийн профайлыг хадгалах боломжгүй байна"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Таны мэдээлэл технологийн админ танд хувийн профайлдаа ажлын файлууд хадгалахыг зөвшөөрөхгүй байна"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g>-н профайлд хадгалах боломжгүй"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Танай IT админ танд <xliff:g id="PROFILE_0">%1$s</xliff:g>-н файлуудыг <xliff:g id="PROFILE_1">%2$s</xliff:g>-н профайлдаа хадгалахыг зөвшөөрдөггүй"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Энэ үйлдлийг зөвшөөрөөгүй байна"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Нэмэлт мэдээлэл авахын тулд мэдээлэл технологийн админтайгаа холбогдоно уу"</string> <string name="root_recent" msgid="1080156975424341623">"Саяхны"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Шинэ нэр"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g> файлыг урьдчилан үзэх"</string> <string name="preview_work_file" msgid="4495643735563487273">"<xliff:g id="FILENAME">%1$s</xliff:g> ажлын файлыг урьдчилан үзэх"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g>-н <xliff:g id="FILENAME">%2$s</xliff:g> файлыг урьдчилан үзэх"</string> <string name="apps_row_title" msgid="3340490016663092925">"Бусад аппын файлыг үзэх"</string> <string name="anonymous_application" msgid="7633027057951625862">"Үл мэдэгдэх"</string> <string name="open_tree_button" msgid="6402871398424497776">"Энэ фолдерыг ашиглах"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Энэ фолдерыг ашиглах боломжгүй байна"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Нууцлалаа хамгаалахын тулд өөр фолдер сонгоно уу"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Шинэ фолдер үүсгэх"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Энэ утсыг хайх"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Энэ төхөөрөмжийг хайх"</string> <string name="delete_search_history" msgid="2202015025607694515">"Хайлтын түүхийг устгах <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Хувийн"</string> <string name="work_tab" msgid="7265359366883747413">"Ажлын"</string> diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml index e5596e5c7..4229508e2 100644 --- a/res/values-mr/strings.xml +++ b/res/values-mr/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"यामध्ये हलवा…"</string> <string name="menu_compress" msgid="37539111904724188">"कॉंप्रेस करा"</string> <string name="menu_extract" msgid="8171946945982532262">"मध्ये काढा..."</string> + <string name="menu_extract_all" msgid="7335680068521252718">"सर्व काढा…"</string> <string name="menu_rename" msgid="1883113442688817554">"नाव बदला"</string> <string name="menu_inspect" msgid="7279855349299446224">"माहिती मिळवा"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"लपवलेल्या फाइल दाखवा"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"याक्षणी आशय लोड करू शकत नाही"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"कामाशी संबंधित अॅप्स थांबवली आहेत"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"कामाशी संबंधित अॅप्स सुरू करा"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> ॲप्स थांबवली आहेत"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> अॅप्स सुरू करा"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"कामासंबंधित फाइल निवडता आल्या नाहीत"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"तुमचा आयटी ॲडमिन तुम्हाला वैयक्तिक ॲपवरून कामासंबंधित फाइल अॅक्सेस करण्याची परवानगी देत नाही"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"वैयक्तिक फाइल निवडता आल्या नाहीत"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"तुमचा आयटी ॲडमिन तुम्हाला कार्य ॲपवरून वैयक्तिक फाइल अॅक्सेस करण्याची परवानगी देत नाही"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> फाइल निवडू शकत नाही"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"तुमचा आयटी ॲडमिन तुम्हाला <xliff:g id="PROFILE_1">%2$s</xliff:g> अॅपमधील <xliff:g id="PROFILE_0">%1$s</xliff:g> फाइल अॅक्सेस करण्याची अनुमती देत नाही"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"कार्य प्रोफाइलमध्ये सेव्ह करता आली नाही"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"तुमचा आयटी ॲडमिन तुम्हाला तुमच्या कार्य प्रोफाईलमध्ये वैयक्तिक फाइल सेव्ह करण्याची परवानगी देत नाही"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"वैयक्तिक प्रोफाइलमध्ये सेव्ह करता आली नाही"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"तुमचा आयटी ॲडमिन तुम्हाला तुमच्या वैयक्तिक प्रोफाईलमध्ये कामासंबंधित फाइल सेव्ह करण्याची परवानगी देत नाही"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> या प्रोफाइलवर सेव्ह करू शकत नाही"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"तुमचा आयटी ॲडमिन तुम्हाला तुमच्या <xliff:g id="PROFILE_1">%2$s</xliff:g> प्रोफाइलवर <xliff:g id="PROFILE_0">%1$s</xliff:g> फाइल सेव्ह करण्याची अनुमती देत नाही"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"या क्रियेला अनुमती नाही"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"अधिक जाणून घेण्यासाठी तुमच्या आयटी ॲडमिनशी संपर्क साधा"</string> <string name="root_recent" msgid="1080156975424341623">"अलीकडील"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"नवीन नाव"</string> <string name="preview_file" msgid="4056622696305432343">"फाइल <xliff:g id="FILENAME">%1$s</xliff:g> चे पूर्वावलोकन करा"</string> <string name="preview_work_file" msgid="4495643735563487273">"कामासंबंधित फाइल <xliff:g id="FILENAME">%1$s</xliff:g> चे पूर्वावलोकन करा"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="FILENAME">%2$s</xliff:g> या <xliff:g id="PROFILE">%1$s</xliff:g> फाइलचे पूर्वावलोकन करा"</string> <string name="apps_row_title" msgid="3340490016663092925">"इतर अॅप्समधील फाइल ब्राउझ करा"</string> <string name="anonymous_application" msgid="7633027057951625862">"अनामित"</string> <string name="open_tree_button" msgid="6402871398424497776">"हे फोल्डर वापरा"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"हे फोल्डर वापरू शकत नाही"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"तुमच्या गोपनीयतेचे संरक्षण करण्यासाठी दुसरे फोल्डर निवडा"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"नवीन फोल्डर तयार करा"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"या फोनमध्ये शोधा"</string> + <string name="search_bar_hint" msgid="146031513183888721">"हे डिव्हाइस शोधा"</string> <string name="delete_search_history" msgid="2202015025607694515">"<xliff:g id="TEXT">%1$s</xliff:g> चा शोध इतिहास हटवा"</string> <string name="personal_tab" msgid="3878576287868528503">"वैयक्तिक"</string> <string name="work_tab" msgid="7265359366883747413">"ऑफिस"</string> diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml index 3e7c0b080..7394358ca 100644 --- a/res/values-ms/strings.xml +++ b/res/values-ms/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Alihkan ke…"</string> <string name="menu_compress" msgid="37539111904724188">"Mampatkan"</string> <string name="menu_extract" msgid="8171946945982532262">"Ekstrak ke…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Ekstrak semua…"</string> <string name="menu_rename" msgid="1883113442688817554">"Namakan semula"</string> <string name="menu_inspect" msgid="7279855349299446224">"Dapatkan maklumat"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Tunjukkan fail tersembunyi"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Tidak dapat memuatkan kandungan pada masa ini"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Apl kerja dijeda"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Hidupkan apl kerja"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Apl <xliff:g id="PROFILE">%1$s</xliff:g> dijeda"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Hidupkan apl <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Tidak boleh memilih fail kerja"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Pentadbir IT anda tidak membenarkan anda mengakses fail kerja daripada apl peribadi"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Tidak boleh memilih fail peribadi"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Pentadbir IT anda tidak membenarkan anda mengakses fail peribadi daripada apl kerja"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Tidak dapat memilih fail <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Pentadbir IT anda tidak membenarkan anda mengakses fail <xliff:g id="PROFILE_0">%1$s</xliff:g> daripada apl <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Tidak dapat menyimpan pada profil kerja"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Pentadbir IT anda tidak membenarkan anda menyimpan fail peribadi pada profil kerja anda"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Tidak dapat menyimpan pada profil peribadi"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Pentadbir IT anda tidak membenarkan anda menyimpan fail kerja pada profil peribadi anda"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Tidak dapat menyimpan pada profil <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Pentadbir IT anda tidak membenarkan anda menyimpan fail <xliff:g id="PROFILE_0">%1$s</xliff:g> pada profil <xliff:g id="PROFILE_1">%2$s</xliff:g> anda"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Tindakan ini tidak dibenarkan"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Untuk mengetahui lebih lanjut, hubungi pentadbir IT anda"</string> <string name="root_recent" msgid="1080156975424341623">"Terbaharu"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Nama baharu"</string> <string name="preview_file" msgid="4056622696305432343">"Pratonton fail <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Pratonton fail kerja <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Pratonton fail <xliff:g id="PROFILE">%1$s</xliff:g> <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Semak imbas fail dalam apl lain"</string> <string name="anonymous_application" msgid="7633027057951625862">"Awanama"</string> <string name="open_tree_button" msgid="6402871398424497776">"Gunakan folder ini"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Tidak boleh menggunakan folder ini"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Untuk melindungi privasi anda, pilih folder lain"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Buat folder baharu"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Cari dalam telefon ini"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Cari peranti ini"</string> <string name="delete_search_history" msgid="2202015025607694515">"Padamkan sejarah carian <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Peribadi"</string> <string name="work_tab" msgid="7265359366883747413">"Kerja"</string> diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml index 3162237fa..49d1278e6 100644 --- a/res/values-my/strings.xml +++ b/res/values-my/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"အောက်ပါနေရာသို့ ရွှေ့ပါ…"</string> <string name="menu_compress" msgid="37539111904724188">"ချုံ့ရန်"</string> <string name="menu_extract" msgid="8171946945982532262">"ရွှေးချယ်ထည့်သွင်းရန်…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"အားလုံးထုတ်ယူရန်…"</string> <string name="menu_rename" msgid="1883113442688817554">"အမည်ပြောင်းပါ"</string> <string name="menu_inspect" msgid="7279855349299446224">"အချက်အလက် ရယူရန်"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"ဝှက်ထားသည့်ဖိုင်များ ပြရန်"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"ဖိုင်ကို လောလောဆယ် တင်ပေး၍မရသေးပါ"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"အလုပ်သုံးအက်ပ်များကို ခေတ္တရပ်ထားသည်"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"အလုပ်သုံးအက်ပ်များ ဖွင့်ရန်"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> အက်ပ်များကို ခဏရပ်ထားသည်"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> အက်ပ်များ ဖွင့်ရန်"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"အလုပ်ဖိုင်များကို ရွေး၍မရပါ"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"ကိုယ်ပိုင်အက်ပ်မှနေ၍ အလုပ်ဖိုင်များ သုံးရန် သင်၏ IT စီမံခန့်ခွဲသူက ခွင့်မပြုပါ"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"ကိုယ်ပိုင်ဖိုင်များကို ရွေး၍မရပါ"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"အလုပ်သုံးအက်ပ်မှနေ၍ ကိုယ်ပိုင်ဖိုင်များ သုံးရန် သင်၏ IT စီမံခန့်ခွဲသူက ခွင့်မပြုပါ"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> ဖိုင်များကို ရွေး၍မရပါ"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"IT စီမံခန့်ခွဲသူသည် <xliff:g id="PROFILE_1">%2$s</xliff:g> အက်ပ်မှ <xliff:g id="PROFILE_0">%1$s</xliff:g> ဖိုင်များကို သင့်အား သုံးခွင့်မပြုပါ"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"အလုပ်ပရိုဖိုင်သို့ သိမ်း၍မရပါ"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"ကိုယ်ပိုင်ဖိုင်များကို သင့်အလုပ်ပရိုဖိုင်သို့ သိမ်းရန် သင်၏ IT စီမံခန့်ခွဲသူက ခွင့်မပြုပါ"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"ကိုပိုင်ပရိုဖိုင်သို့ သိမ်း၍မရပါ"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"အလုပ်ဖိုင်များကို သင့်ကိုယ်ပိုင်ပရိုဖိုင်သို့ သိမ်းရန် သင်၏ IT စီမံခန့်ခွဲသူက ခွင့်မပြုပါ"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> ပရိုဖိုင်တွင် သိမ်း၍မရပါ"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"IT စီမံခန့်ခွဲသူသည် သင်၏ <xliff:g id="PROFILE_1">%2$s</xliff:g> ပရိုဖိုင်တွင် <xliff:g id="PROFILE_0">%1$s</xliff:g> ဖိုင်များကို သင့်အား သိမ်းခွင့်မပြုပါ။"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"ဤလုပ်ဆောင်ချက်ကို ခွင့်မပြုပါ"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"ပိုမိုလေ့လာရန် သင်၏ IT စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ"</string> <string name="root_recent" msgid="1080156975424341623">"လတ်တလော"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"အမည်အသစ်"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g> ဖိုင်ကို အစမ်းကြည့်ရန်"</string> <string name="preview_work_file" msgid="4495643735563487273">"<xliff:g id="FILENAME">%1$s</xliff:g> အလုပ်ဖိုင်ကို အစမ်းကြည့်ရှုပါ"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> ဖိုင် <xliff:g id="FILENAME">%2$s</xliff:g> ကို အစမ်းကြည့်ရှုရန်"</string> <string name="apps_row_title" msgid="3340490016663092925">"အခြားအက်ပ်များတွင် ဖိုင်များကို ဖွင့်ကြည့်ပါ"</string> <string name="anonymous_application" msgid="7633027057951625862">"အမည်မသိ"</string> <string name="open_tree_button" msgid="6402871398424497776">"ဤဖိုင်တွဲကို အသုံးပြုပါ"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"ဤဖိုင်တွဲကို အသုံးပြု၍ မရပါ"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"သင်၏ကိုယ်ရေးလုံခြုံမှုကို ကာကွယ်ရန် ဖိုင်တွဲနောက်တစ်ခု ရွေးပါ"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"ဖိုင်တွဲအသစ် ပြုလုပ်ရန်"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"ဤဖုန်းတွင် ရှာရန်"</string> + <string name="search_bar_hint" msgid="146031513183888721">"ဤစက်တွင် ရှာရန်"</string> <string name="delete_search_history" msgid="2202015025607694515">"ရှာဖွေမှတ်တမ်း <xliff:g id="TEXT">%1$s</xliff:g> ကိုဖျက်သည်"</string> <string name="personal_tab" msgid="3878576287868528503">"ကိုယ်ပိုင်"</string> <string name="work_tab" msgid="7265359366883747413">"အလုပ်"</string> diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index 95674cd81..4090122dd 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Flytt til"</string> <string name="menu_compress" msgid="37539111904724188">"Komprimer"</string> <string name="menu_extract" msgid="8171946945982532262">"Pakk ut til …"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Pakk ut alt …"</string> <string name="menu_rename" msgid="1883113442688817554">"Gi nytt navn"</string> <string name="menu_inspect" msgid="7279855349299446224">"Hent informasjon"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Vis skjulte filer"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Kan ikke laste inn innholdet for øyeblikket"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Jobbapper er satt på pause"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Slå på jobbapper"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g>-appene er satt på pause"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Slå på <xliff:g id="PROFILE">%1$s</xliff:g>-apper"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Du kan ikke velge jobbfiler"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"IT-administratoren din tillater ikke at du får tilgang til jobbfiler fra personlige apper"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Du kan ikke velge personlige filer"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"IT-administratoren din tillater ikke at du får tilgang til personlige filer fra jobbapper"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Kan ikke velge <xliff:g id="PROFILE">%1$s</xliff:g>-filer"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"IT-administratoren din lar deg ikke bruke <xliff:g id="PROFILE_0">%1$s</xliff:g>-filer fra en <xliff:g id="PROFILE_1">%2$s</xliff:g>-app"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Du kan ikke lagre i jobbprofilen"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"IT-administratoren din tillater ikke at du lagrer personlige filer i jobbprofilen din"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Du kan ikke lagre i den personlige profilen"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"IT-administratoren din tillater ikke at du lagrer jobbfiler i den personlige profilen din"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Kan ikke lagre i <xliff:g id="PROFILE">%1$s</xliff:g>-profilen"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"IT-administratoren din lar deg ikke lagre <xliff:g id="PROFILE_0">%1$s</xliff:g>-filer i <xliff:g id="PROFILE_1">%2$s</xliff:g>-profilen din"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Handlingen er ikke tillatt"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"For å finne ut mer, kontakt IT-administratoren"</string> <string name="root_recent" msgid="1080156975424341623">"Nylige"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Nytt navn"</string> <string name="preview_file" msgid="4056622696305432343">"Forhåndsvis filen <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Se en forhåndsvisning av jobbfilen, <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Forhåndsvis <xliff:g id="PROFILE">%1$s</xliff:g>-filen <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Bla gjennom filer i andre apper"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonym"</string> <string name="open_tree_button" msgid="6402871398424497776">"Bruk denne mappen"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Du kan ikke bruke denne mappen"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Velg en annen mappe for å beskytte personvernet ditt"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Opprett en ny mappe"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Søk på denne telefonen"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Søk på denne enheten"</string> <string name="delete_search_history" msgid="2202015025607694515">"Slett søkelogg <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Personlig"</string> <string name="work_tab" msgid="7265359366883747413">"Jobb"</string> diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml index 7b9cab948..1e8dc9b36 100644 --- a/res/values-ne/strings.xml +++ b/res/values-ne/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"निम्नमा सार्नुहोस्…"</string> <string name="menu_compress" msgid="37539111904724188">"कम्प्रेस गर्नुहोस्"</string> <string name="menu_extract" msgid="8171946945982532262">"यसमा एकस्ट्र्याक्ट गर्नुहोस्…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"सबै एक्स्ट्रयाक्ट गर्नुहोस्…"</string> <string name="menu_rename" msgid="1883113442688817554">"पुनःनामाकरण गर्नुहोस्"</string> <string name="menu_inspect" msgid="7279855349299446224">"जानकारी प्राप्त गर्नुहोस्"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"लुकाइएका फाइलहरू देखाउनुहोस्"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"यस समय सामग्री लोड गर्न सकिँदैन"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"कामसम्बन्धी एपहरू पज गरिएका छन्"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"कामसम्बन्धी एपहरू अन गर्नुहोस्"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> एपहरू पज गरिएका छन्"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> एपहरू अन गर्नुहोस्"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"कार्यालयका फाइलहरू चयन गर्न मिल्दैन"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"तपाईंका IT एडमिनले तपाईंलाई व्यक्तिगत एपमार्फत कार्यालयका फाइलहरू प्रयोग गर्ने अनुमति दिनुभएको छैन"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"व्यक्तिगत फाइलहरू चयन गर्न सकिएन"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"तपाईंका IT एडमिनले तपाईंलाई कामसम्बन्धी एपमार्फत व्यक्तिगत फाइलहरू प्रयोग गर्ने अनुमति दिनुभएको छैन"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> फाइलहरू चयन गर्न मिल्दैन"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"तपाईंका IT एड्मिनले तपाईंलाई <xliff:g id="PROFILE_1">%2$s</xliff:g> एपमा भएका <xliff:g id="PROFILE_0">%1$s</xliff:g> फाइलहरू एक्सेस गर्ने अनुमति दिनुभएको छैन"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"कार्यलयको प्रोफाइलमा सुरक्षित गर्न सकिएन"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"तपाईंका IT एडमिनले तपाईंलाई आफ्नो कार्यलयको प्रोफाइलमा रहेका एपहरूमा व्यक्तिगत फाइलहरू सुरक्षित गर्ने अनुमति दिनुभएको छैन"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"व्यक्तिगत प्रोफाइलमा सुरक्षित गर्न सकिएन"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"तपाईंका IT एडमिनले तपाईंलाई आफ्नो व्यक्तिगत प्रोफाइलमा रहेका एपहरूमा कार्यालयका फाइलहरू सुरक्षित गर्ने अनुमति दिनुभएको छैन"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> प्रोफाइलमा सेभ गर्न मिल्दैन"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"तपाईंका IT एड्मिनले तपाईंलाई तपाईंको <xliff:g id="PROFILE_1">%2$s</xliff:g> प्रोफाइलमा <xliff:g id="PROFILE_0">%1$s</xliff:g> फाइलहरू सेभ गर्ने अनुमति दिनुभएको छैन"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"यो कार्य गर्ने अनुमति छैन"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"थप जानकारी प्राप्त गर्न आफ्ना IT एड्मिनलाई सम्पर्क गर्नुहोस्"</string> <string name="root_recent" msgid="1080156975424341623">"हालको"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"नयाँ नाम"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g> फाइलको पूर्वावलोकन गर्नुहोस्"</string> <string name="preview_work_file" msgid="4495643735563487273">"कार्यालयको <xliff:g id="FILENAME">%1$s</xliff:g> नामक फाइलको पूर्वावलोकन गर्नुहोस्"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> फाइल <xliff:g id="FILENAME">%2$s</xliff:g> को प्रिभ्यू गर्नुहोस्"</string> <string name="apps_row_title" msgid="3340490016663092925">"अन्य एपहरूमा फाइलहरू खोज्नुहोस्"</string> <string name="anonymous_application" msgid="7633027057951625862">"अज्ञात"</string> <string name="open_tree_button" msgid="6402871398424497776">"यो फोल्डर प्रयोग गर्नुहोस्"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"यो फोल्डर प्रयोग गर्न सकिएन"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"आफ्नो गोपनीयताको संरक्षण गर्न अर्को फोल्डर छान्नुहोस्"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"नयाँ फोल्डर सिर्जना गर्नुहोस्"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"यो फोनमा खोज्नुहोस्"</string> + <string name="search_bar_hint" msgid="146031513183888721">"यो डिभाइस खोज्नुहोस्"</string> <string name="delete_search_history" msgid="2202015025607694515">"खोजसम्बन्धी इतिहास मेट्नुहोस् <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"व्यक्तिगत"</string> <string name="work_tab" msgid="7265359366883747413">"काम"</string> diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index 384b670a6..fe37feb5b 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Verplaatsen naar…"</string> <string name="menu_compress" msgid="37539111904724188">"Comprimeren"</string> <string name="menu_extract" msgid="8171946945982532262">"Uitpakken naar…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Alles uitpakken…"</string> <string name="menu_rename" msgid="1883113442688817554">"Naam wijzigen"</string> <string name="menu_inspect" msgid="7279855349299446224">"Informatie bekijken"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Verborgen bestanden tonen"</string> @@ -92,16 +93,22 @@ <string name="save_error" msgid="8631128801982095782">"Kan document niet opslaan"</string> <string name="create_error" msgid="3092144450044861994">"Kan map niet maken"</string> <string name="query_error" msgid="6625421453613879336">"Kan content momenteel niet laden"</string> - <string name="quiet_mode_error_title" msgid="554319751414657910">"Werk-apps zijn onderbroken"</string> + <string name="quiet_mode_error_title" msgid="554319751414657910">"Werk-apps zijn gepauzeerd"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Werk-apps aanzetten"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g>-apps zijn gepauzeerd"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g>-apps aanzetten"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Kan geen werkbestanden selecteren"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Je IT-beheerder staat niet toe dat je werkbestanden opent met een app die je voor persoonlijke doeleinden gebruikt"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Kan geen persoonlijke bestanden selecteren"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Je IT-beheerder staat niet toe dat je persoonlijke bestanden opent via een werk-app"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Kan geen <xliff:g id="PROFILE">%1$s</xliff:g>-bestanden selecteren"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Je IT-beheerder staat niet toe dat je <xliff:g id="PROFILE_0">%1$s</xliff:g>-bestanden opent vanuit een <xliff:g id="PROFILE_1">%2$s</xliff:g>-app"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Kan niet opslaan in werkprofiel"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Je IT-beheerder staat niet toe dat je persoonlijke bestanden opslaat in je werkprofiel"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Kan niet opslaan in persoonlijk profiel"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Je IT-beheerder staat niet toe dat je werkbestanden opslaat in je persoonlijke profiel"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Kan niet opslaan in <xliff:g id="PROFILE">%1$s</xliff:g>-profiel"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Je IT-beheerder staat niet toe dat je <xliff:g id="PROFILE_0">%1$s</xliff:g>-bestanden opslaat in je <xliff:g id="PROFILE_1">%2$s</xliff:g>-profiel"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Deze actie is niet toegestaan"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Neem voor meer informatie contact op met je IT-beheerder"</string> <string name="root_recent" msgid="1080156975424341623">"Recent"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Nieuwe naam"</string> <string name="preview_file" msgid="4056622696305432343">"Voorbeeld van het bestand <xliff:g id="FILENAME">%1$s</xliff:g> bekijken"</string> <string name="preview_work_file" msgid="4495643735563487273">"Bekijk een voorbeeld van het werkbestand <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Voorbeeld van het <xliff:g id="PROFILE">%1$s</xliff:g>-bestand <xliff:g id="FILENAME">%2$s</xliff:g> weergeven"</string> <string name="apps_row_title" msgid="3340490016663092925">"Door bestanden browsen in andere apps"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anoniem"</string> <string name="open_tree_button" msgid="6402871398424497776">"Deze map gebruiken"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Kan deze map niet gebruiken"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Kies een andere map om je privacy te beschermen"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Nieuwe map maken"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Deze telefoon doorzoeken"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Zoeken op dit apparaat"</string> <string name="delete_search_history" msgid="2202015025607694515">"Zoekgeschiedenis verwijderen <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Persoonlijk"</string> <string name="work_tab" msgid="7265359366883747413">"Werk"</string> diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml index fa895c788..645c74bf8 100644 --- a/res/values-or/strings.xml +++ b/res/values-or/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"ଏଠାକୁ ନିଅନ୍ତୁ…"</string> <string name="menu_compress" msgid="37539111904724188">"କମ୍ପ୍ରେସ୍ କରନ୍ତୁ"</string> <string name="menu_extract" msgid="8171946945982532262">"ଏଠାକୁ ଏକ୍ସଟ୍ରାକ୍ଟ କରନ୍ତୁ…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"ସବୁ ଏକ୍ସଟ୍ରାକ୍ଟ କରନ୍ତୁ…"</string> <string name="menu_rename" msgid="1883113442688817554">"ରିନେମ କରନ୍ତୁ"</string> <string name="menu_inspect" msgid="7279855349299446224">"ସୂଚନା ପାଆନ୍ତୁ"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"ଲୁକ୍କାୟିତ ଫାଇଲ ଦେଖାନ୍ତୁ"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"ଏହି ସମୟରେ କଣ୍ଟେଣ୍ଟ ଲୋଡ୍ କରିପାରିବ ନାହିଁ"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"ୱାର୍କ ଆପଗୁଡ଼ିକୁ ବିରତ କରାଯାଇଛି"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"ୱାର୍କ ଆପ୍ସ ଚାଲୁ କରନ୍ତୁ"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> ଆପ୍ସକୁ ବିରତ କରାଯାଇଛି"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> ଆପ୍ସକୁ ଚାଲୁ କରନ୍ତୁ"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"ୱାର୍କ ଫାଇଲଗୁଡ଼ିକ ଚୟନ କରାଯାଇପାରିବ ନାହିଁ"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"ଆପଣଙ୍କ IT ଆଡମିନ୍ ଆପଣଙ୍କୁ ଏକ ବ୍ୟକ୍ତିଗତ ଆପରୁ ୱାର୍କ ଫାଇଲଗୁଡ଼ିକ ଆକ୍ସେସ୍ କରିବାକୁ ଅନୁମତି ଦିଅନ୍ତି ନାହିଁ"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"ବ୍ୟକ୍ତିଗତ ଫାଇଲଗୁଡ଼ିକ ଚୟନ କରାଯାଇପାରିବ ନାହିଁ"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"ଆପଣଙ୍କ IT ଆଡମିନ୍ ଆପଣଙ୍କୁ ଏକ କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପରୁ ବ୍ୟକ୍ତିଗତ ଫାଇଲଗୁଡ଼ିକ ଆକ୍ସେସ୍ କରିବାକୁ ଅନୁମତି ଦିଅନ୍ତି ନାହିଁ"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> ଫାଇଲଗୁଡ଼ିକୁ ଚୟନ କରାଯାଇପାରିବ ନାହିଁ"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"ଆପଣଙ୍କ IT ଆଡମିନ ଏକ <xliff:g id="PROFILE_1">%2$s</xliff:g> ଆପରୁ <xliff:g id="PROFILE_0">%1$s</xliff:g> ଫାଇଲଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଅନୁମତି ଦିଅନ୍ତି ନାହିଁ"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"ୱାର୍କ ପ୍ରୋଫାଇଲରେ ସେଭ୍ କରାଯାଇପାରିବ ନାହିଁ"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"ଆପଣଙ୍କ IT ଆଡମିନ୍ ଆପଣଙ୍କୁ ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲରେ ବ୍ୟକ୍ତିଗତ ଫାଇଲଗୁଡ଼ିକୁ ସେଭ୍ କରିବାକୁ ଅନୁମତି ଦିଅନ୍ତି ନାହିଁ"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"ବ୍ୟକ୍ତିଗତ ପ୍ରୋଫାଇଲରେ ସେଭ୍ କରାଯାଇପାରିବ ନାହିଁ"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"ଆପଣଙ୍କ IT ଆଡମିନ୍ ଆପଣଙ୍କୁ ଆପଣଙ୍କ ବ୍ୟକ୍ତିଗତ ପ୍ରୋଫାଇଲରେ କାର୍ଯ୍ୟସ୍ଥଳୀର ଫାଇଲଗୁଡ଼ିକ ସେଭ୍ କରିବାକୁ ଅନୁମତି ଦିଅନ୍ତି ନାହିଁ"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> ପ୍ରୋଫାଇଲରେ ସେଭ କରାଯାଇପାରିବ ନାହିଁ"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"ଆପଣଙ୍କ IT ଆଡମିନ ଆପଣଙ୍କୁ ଆପଣଙ୍କ <xliff:g id="PROFILE_1">%2$s</xliff:g> ପ୍ରୋଫାଇଲରେ <xliff:g id="PROFILE_0">%1$s</xliff:g> ଫାଇଲଗୁଡ଼ିକୁ ସେଭ କରିବା ପାଇଁ ଅନୁମତି ଦିଅନ୍ତି ନାହିଁ"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"ଏହି କାର୍ଯ୍ୟକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"ଅଧିକ ଜାଣିବାକୁ, ଆପଣଙ୍କ IT ଆଡମିନଙ୍କ ସହ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ"</string> <string name="root_recent" msgid="1080156975424341623">"ବର୍ତ୍ତମାନର"</string> @@ -118,15 +125,15 @@ <string name="toast_share_over_limit" msgid="5805442886537093015">"<xliff:g id="COUNT">%1$d</xliff:g>ଟିରୁ ଅଧିକ ଫାଇଲ୍ ସେୟାର୍ କରାଯାଇପାରିବ ନାହିଁ"</string> <string name="toast_action_not_allowed" msgid="1329382474450572415">"କାର୍ଯ୍ୟଟିକୁ ଅନୁମତି ନାହିଁ"</string> <string name="share_via" msgid="8725082736005677161">"ଏହା ମାଧ୍ୟମରେ ସେୟାର୍ କରନ୍ତୁ"</string> - <string name="copy_notification_title" msgid="52256435625098456">"ଫାଇଲ୍ଗୁଡ଼ିକ କପୀ କରାଯାଉଛି"</string> + <string name="copy_notification_title" msgid="52256435625098456">"ଫାଇଲଗୁଡ଼ିକ କପି କରାଯାଉଛି"</string> <string name="compress_notification_title" msgid="6830195148113751021">"ଫାଇଲ୍ କମ୍ପ୍ରେସ୍ କରାଯାଉଛି"</string> <string name="extract_notification_title" msgid="5067393961754430469">"ଫାଇଲ୍ ଏକ୍ସଟ୍ରାକ୍ଟ କରିବା"</string> <string name="move_notification_title" msgid="3173424987049347605">"ଫାଇଲ୍ଗୁଡ଼ିକ ନିଆଯାଉଛି"</string> <string name="delete_notification_title" msgid="2512757431856830792">"ଫାଇଲ୍ ଡିଲିଟ୍ କରାଯାଉଛି"</string> <string name="copy_remaining" msgid="5390517377265177727">"<xliff:g id="DURATION">%s</xliff:g> ଅବଶିଷ୍ଟ"</string> <plurals name="copy_begin" formatted="false" msgid="151184708996738192"> - <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>ଟି ଆଇଟମ୍ କପୀ କରାଯାଉଛି।</item> - <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g>ଟି ଆଇଟମ୍ କପୀ କରାଯାଉଛି।</item> + <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ଆଇଟମ କପ କରାଯାଉଛି।</item> + <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ଆଇଟମ କପି କରାଯାଉଛି।</item> </plurals> <plurals name="compress_begin" formatted="false" msgid="3534158317098678895"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>ଟି ଫାଇଲ୍ କମ୍ପ୍ରେସ୍ କରାଯାଉଛି।</item> @@ -170,8 +177,8 @@ <string name="notification_touch_for_details" msgid="2385563502445129570">"ବିବରଣୀ ଦେଖିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string> <string name="close" msgid="905969391788869975">"ବନ୍ଦ କରନ୍ତୁ"</string> <plurals name="copy_failure_alert_content" formatted="false" msgid="5570549471912990536"> - <item quantity="other">ଏହି ଫାଇଲ୍ କପୀ କରାଯାଇପାରିଲା ନାହିଁ: <xliff:g id="LIST_1">%1$s</xliff:g></item> - <item quantity="one">ଏହି ଫାଇଲ୍ କପୀ କରାଯାଇପାରିଲା ନାହିଁ: <xliff:g id="LIST_0">%1$s</xliff:g></item> + <item quantity="other">ଏହି ଫାଇଲ କପି କରାଯାଇପାରିଲା ନାହିଁ: <xliff:g id="LIST_1">%1$s</xliff:g></item> + <item quantity="one">ଏହି ଫାଇଲ କପି କରାଯାଇପାରିଲା ନାହିଁ: <xliff:g id="LIST_0">%1$s</xliff:g></item> </plurals> <plurals name="compress_failure_alert_content" formatted="false" msgid="5760632881868842400"> <item quantity="other">ଏହି ଫାଇଲଗୁଡ଼ିକ ଛୋଟ କରାଯାଇପାରିଲା ନାହିଁ: <xliff:g id="LIST_1">%1$s</xliff:g></item> @@ -194,8 +201,8 @@ <item quantity="one">ଏହି ଫାଇଲ୍ ଅନ୍ୟ ଫର୍ମାଟରେ ବଦଳାଗଲା: <xliff:g id="LIST_0">%1$s</xliff:g></item> </plurals> <plurals name="clipboard_files_clipped" formatted="false" msgid="4847061634862926902"> - <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>ଟି ଆଇଟମ୍ କ୍ଲିପ୍ବୋର୍ଡକୁ କପୀ କରାଗଲା</item> - <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g>ଟି ଆଇଟମ୍ କ୍ଲିପ୍ବୋର୍ଡକୁ କପୀ କରାଗଲା</item> + <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ଆଇଟମ କ୍ଲିପବୋର୍ଡକୁ କପି କରାଗଲା</item> + <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ଆଇଟମ କ୍ଲିପବୋର୍ଡକୁ କପି କରାଗଲା</item> </plurals> <string name="file_operation_rejected" msgid="4301554203329008794">"ଫାଇଲ୍ ଅପରେସନ୍ ସପୋର୍ଟ କଲାନାହିଁ।"</string> <string name="file_operation_error" msgid="2234357335716533795">"ଫାଇଲ୍ ଅପରେସନ୍ କରାଯାଇପାରିଲା ନାହିଁ"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"ନୂଆ ନାମ"</string> <string name="preview_file" msgid="4056622696305432343">"ଫାଇଲ୍ <xliff:g id="FILENAME">%1$s</xliff:g> ପୂର୍ବାବଲୋକନ କରନ୍ତୁ"</string> <string name="preview_work_file" msgid="4495643735563487273">"କାର୍ଯ୍ୟସ୍ଥଳୀ ଫାଇଲ୍ <xliff:g id="FILENAME">%1$s</xliff:g>ର ପ୍ରିଭ୍ୟୁ କରନ୍ତୁ"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> ଫାଇଲ <xliff:g id="FILENAME">%2$s</xliff:g>ର ପ୍ରିଭ୍ୟୁ କରନ୍ତୁ"</string> <string name="apps_row_title" msgid="3340490016663092925">"ଅନ୍ୟ ଆପ୍ସରେ ଫାଇଲ୍ ବ୍ରାଉଜ୍ କରନ୍ତୁ"</string> <string name="anonymous_application" msgid="7633027057951625862">"ବେନାମୀ"</string> <string name="open_tree_button" msgid="6402871398424497776">"ଏହି ଫୋଲ୍ଡର୍ ବ୍ୟବହାର କରନ୍ତୁ"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"ଏହି ଫୋଲ୍ଡରକୁ ବ୍ୟବହାର କରାଯାଇପାରିବ ନାହିଁ"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"ଆପଣଙ୍କ ଗୋପନୀୟତାକୁ ସୁରକ୍ଷିତ କରିବାକୁ ଅନ୍ୟ ଏକ ଫୋଲ୍ଡର୍ ବାଛନ୍ତୁ"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"ନୂଆ ଫୋଲ୍ଡର୍ ତିଆରି କରନ୍ତୁ"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"ଏହି ଫୋନରେ ସର୍ଚ୍ଚ କରନ୍ତୁ"</string> + <string name="search_bar_hint" msgid="146031513183888721">"ଏହି ଡିଭାଇସକୁ ସର୍ଚ୍ଚ କରନ୍ତୁ"</string> <string name="delete_search_history" msgid="2202015025607694515">"ସର୍ଚ୍ଚ ଇତିହାସ <xliff:g id="TEXT">%1$s</xliff:g>କୁ ଡିଲିଟ କରନ୍ତୁ"</string> <string name="personal_tab" msgid="3878576287868528503">"ବ୍ୟକ୍ତିଗତ"</string> <string name="work_tab" msgid="7265359366883747413">"ୱାର୍କ"</string> diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml index aa7e2ee0b..4169a9e5c 100644 --- a/res/values-pa/strings.xml +++ b/res/values-pa/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"ਇਸ ਵਿੱਚ ਲਿਜਾਓ…"</string> <string name="menu_compress" msgid="37539111904724188">"ਨਪੀੜੋ"</string> <string name="menu_extract" msgid="8171946945982532262">"ਇਸ ਵਿੱਚ ਐਕਸਟ੍ਰੈਕਟ ਕਰੋ…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"ਸਭ ਐਕਸਟਰੈਕਟ ਕਰੋ…"</string> <string name="menu_rename" msgid="1883113442688817554">"ਨਾਮ ਬਦਲੋ"</string> <string name="menu_inspect" msgid="7279855349299446224">"ਜਾਣਕਾਰੀ ਪ੍ਰਾਪਤ ਕਰੋ"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"ਲੁਕਾਈਆਂ ਗਈਆਂ ਫ਼ਾਈਲਾਂ ਦਿਖਾਓ"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"ਇਸ ਵੇਲੇ ਸਮੱਗਰੀ ਨੂੰ ਲੋਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਨੂੰ ਰੋਕਿਆ ਗਿਆ ਹੈ"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਚਾਲੂ ਕਰੋ"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> ਐਪਾਂ ਨੂੰ ਰੋਕਿਆ ਗਿਆ ਹੈ"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> ਐਪਾਂ ਨੂੰ ਚਾਲੂ ਕਰੋ"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"ਕਾਰਜ ਸੰਬੰਧੀ ਫ਼ਾਈਲਾਂ ਨੂੰ ਨਹੀਂ ਚੁਣਿਆ ਜਾ ਸਕਦਾ"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"ਤੁਹਾਡਾ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਤੁਹਾਨੂੰ ਨਿੱਜੀ ਐਪ ਤੋਂ ਕਾਰਜ ਸੰਬੰਧੀ ਫ਼ਾਈਲਾਂ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕਰਨ ਦਿੰਦਾ"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"ਨਿੱਜੀ ਫ਼ਾਈਲਾਂ ਨੂੰ ਨਹੀਂ ਚੁਣਿਆ ਜਾ ਸਕਦਾ"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"ਤੁਹਾਡਾ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਤੁਹਾਨੂੰ ਕੰਮ ਸੰਬੰਧੀ ਐਪ ਤੋਂ ਨਿੱਜੀ ਫ਼ਾਈਲਾਂ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕਰਨ ਦਿੰਦਾ"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਚੁਣਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"ਤੁਹਾਡਾ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਤੁਹਾਨੂੰ <xliff:g id="PROFILE_1">%2$s</xliff:g> ਐਪ ਤੋਂ <xliff:g id="PROFILE_0">%1$s</xliff:g> ਫ਼ਾਈਲਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਦਿੰਦਾ"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਿੱਚ ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"ਤੁਹਾਡਾ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਤੁਹਾਨੂੰ ਆਪਣੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਿੱਚ ਨਿੱਜੀ ਫ਼ਾਈਲਾਂ ਰੱਖਿਅਤ ਨਹੀਂ ਕਰਨ ਦਿੰਦਾ"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"ਨਿੱਜੀ ਪ੍ਰੋਫਾਈਲ ਵਿੱਚ ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"ਤੁਹਾਡਾ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਤੁਹਾਨੂੰ ਆਪਣੇ ਨਿੱਜੀ ਪ੍ਰੋਫਾਈਲ ਵਿੱਚ ਕਾਰਜ ਸੰਬੰਧੀ ਫ਼ਾਈਲਾਂ ਰੱਖਿਅਤ ਨਹੀਂ ਕਰਨ ਦਿੰਦਾ"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> ਪ੍ਰੋਫਾਈਲ \'ਤੇ ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"ਤੁਹਾਡਾ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਤੁਹਾਨੂੰ <xliff:g id="PROFILE_0">%1$s</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਤੁਹਾਡੇ <xliff:g id="PROFILE_1">%2$s</xliff:g> ਪ੍ਰੋਫਾਈਲ \'ਤੇ ਰੱਖਿਅਤ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਦਿੰਦਾ"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"ਇਸ ਕਾਰਵਾਈ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"ਹੋਰ ਜਾਣਨ ਲਈ, ਆਪਣੇ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ"</string> <string name="root_recent" msgid="1080156975424341623">"ਹਾਲੀਆ"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"ਨਵਾਂ ਨਾਮ"</string> <string name="preview_file" msgid="4056622696305432343">"ਫ਼ਾਈਲ <xliff:g id="FILENAME">%1$s</xliff:g> ਦੀ ਪੂਰਵ-ਝਲਕ ਦੇਖੋ"</string> <string name="preview_work_file" msgid="4495643735563487273">"ਕਾਰਜ ਸੰਬੰਧੀ ਫ਼ਾਈਲ <xliff:g id="FILENAME">%1$s</xliff:g> ਦੀ ਪੂਰਵ-ਝਲਕ ਦੇਖੋ"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> ਫ਼ਾਈਲ <xliff:g id="FILENAME">%2$s</xliff:g> ਦੀ ਪੂਰਵ-ਝਲਕ ਦੇਖੋ"</string> <string name="apps_row_title" msgid="3340490016663092925">"ਹੋਰ ਐਪਾਂ ਵਿੱਚ ਫ਼ਾਈਲਾਂ ਬ੍ਰਾਊਜ਼ ਕਰੋ"</string> <string name="anonymous_application" msgid="7633027057951625862">"ਗੁਮਨਾਮ"</string> <string name="open_tree_button" msgid="6402871398424497776">"ਇਹ ਫੋਲਡਰ ਵਰਤੋ"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"ਇਹ ਫੋਲਡਰ ਨਹੀਂ ਵਰਤਿਆ ਜਾ ਸਕਦਾ"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"ਆਪਣੀ ਪਰਦੇਦਾਰੀ ਦੀ ਸੁਰੱਖਿਆ ਲਈ, ਕੋਈ ਹੋਰ ਫੋਲਡਰ ਚੁਣੋ"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"ਨਵਾਂ ਫੋਲਡਰ ਬਣਾਓ"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"ਇਹ ਫ਼ੋਨ ਖੋਜੋ"</string> + <string name="search_bar_hint" msgid="146031513183888721">"ਇਸ ਡੀਵਾਈਸ ਨੂੰ ਖੋਜੋ"</string> <string name="delete_search_history" msgid="2202015025607694515">"ਖੋਜ ਇਤਿਹਾਸ ਮਿਟਾਓ <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"ਨਿੱਜੀ"</string> <string name="work_tab" msgid="7265359366883747413">"ਕਾਰਜ-ਸਥਾਨ"</string> diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index 568429581..5c1360039 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Przenieś do…"</string> <string name="menu_compress" msgid="37539111904724188">"Skompresuj"</string> <string name="menu_extract" msgid="8171946945982532262">"Rozpakuj do…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Wyodrębnij wszystko…"</string> <string name="menu_rename" msgid="1883113442688817554">"Zmień nazwę"</string> <string name="menu_inspect" msgid="7279855349299446224">"Zobacz informacje"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Pokaż ukryte pliki"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Teraz nie można załadować zawartości"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Aplikacje służbowe zostały wstrzymane"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Włącz aplikacje służbowe"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Aplikacje <xliff:g id="PROFILE">%1$s</xliff:g> zostały wstrzymane"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Włącz aplikacje typu <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Nie można wybrać plików służbowych"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Administrator IT nie pozwala na dostęp do plików służbowych w aplikacjach osobistych"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Nie można wybrać plików osobistych"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Administrator IT nie pozwala na dostęp do plików osobistych w aplikacjach służbowych"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Nie można wybierać plików typu <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Administrator IT nie pozwala na dostęp do plików typu <xliff:g id="PROFILE_0">%1$s</xliff:g> z aplikacji typu <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Nie można zapisać w profilu służbowym"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Administrator IT nie pozwala na zapisywanie plików osobistych w profilu służbowym"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Nie można zapisać w profilu osobistym"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Administrator IT nie pozwala na zapisywanie plików służbowych w profilu osobistym"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Nie można zapisać w profilu typu <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Administrator IT nie pozwala na zapisywanie plików typu <xliff:g id="PROFILE_0">%1$s</xliff:g> w profilu typu <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Ta czynność jest niedozwolona"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Aby dowiedzieć się więcej, skontaktuj się z administratorem IT"</string> <string name="root_recent" msgid="1080156975424341623">"Najnowsze"</string> @@ -310,6 +317,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Nowa nazwa"</string> <string name="preview_file" msgid="4056622696305432343">"Wyświetl podgląd pliku <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Wyświetl podgląd pliku służbowego <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Wyświetl podgląd pliku <xliff:g id="FILENAME">%2$s</xliff:g> typu <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Przeglądaj pliki w innych aplikacjach"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonimowa"</string> <string name="open_tree_button" msgid="6402871398424497776">"Użyj tego folderu"</string> @@ -318,7 +326,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Nie można użyć tego folderu"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Aby chronić swoją prywatność, wybierz inny folder"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Utwórz nowy folder"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Szukaj na telefonie"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Przeszukaj to urządzenie"</string> <string name="delete_search_history" msgid="2202015025607694515">"Usuń historię wyszukiwania <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Osobiste"</string> <string name="work_tab" msgid="7265359366883747413">"Służbowe"</string> diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml index 96030ed1e..3e492209d 100644 --- a/res/values-pt-rBR/strings.xml +++ b/res/values-pt-rBR/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Mover para…"</string> <string name="menu_compress" msgid="37539111904724188">"Compactar"</string> <string name="menu_extract" msgid="8171946945982532262">"Extrair para…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Extrair tudo…"</string> <string name="menu_rename" msgid="1883113442688817554">"Renomear"</string> <string name="menu_inspect" msgid="7279855349299446224">"Ver informações"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Mostrar arquivos ocultos"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Não é possível carregar o conteúdo no momento"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Os apps de trabalho foram pausados"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Ativar apps de trabalho"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Os apps do perfil <xliff:g id="PROFILE">%1$s</xliff:g> estão pausados"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Ativar apps do perfil <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Não é possível selecionar arquivos de trabalho"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Seu administrador de TI não permite que você acesse arquivos de trabalho em um app pessoal"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Não foi possível selecionar arquivos pessoais"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Seu administrador de TI não permite que você acesse arquivos pessoais em um app de trabalho"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Não é possível selecionar arquivos do perfil <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Seu administrador de TI não permite que arquivos do perfil <xliff:g id="PROFILE_0">%1$s</xliff:g> sejam acessados por um app do perfil <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Não é possível salvar no perfil de trabalho"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Seu administrador de TI não permite que você salve arquivos pessoais no perfil de trabalho"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Não é possível salvar no perfil pessoal"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Seu administrador de TI não permite que você salve arquivos de trabalho no perfil pessoal"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Não é possível salvar no perfil <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Seu administrador de TI não permite que arquivos do perfil <xliff:g id="PROFILE_0">%1$s</xliff:g> sejam salvos no perfil <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Essa ação não é permitida"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Para saber mais, entre em contato com o administrador de TI"</string> <string name="root_recent" msgid="1080156975424341623">"Recentes"</string> @@ -288,6 +295,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Novo nome"</string> <string name="preview_file" msgid="4056622696305432343">"Visualizar o arquivo <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Visualizar o arquivo de trabalho <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Visualizar o arquivo <xliff:g id="FILENAME">%2$s</xliff:g> do perfil <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Procurar arquivos em outros apps"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anônimo"</string> <string name="open_tree_button" msgid="6402871398424497776">"Usar esta pasta"</string> @@ -296,7 +304,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Não é possível usar essa pasta"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Para proteger sua privacidade, escolha outra pasta"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Criar nova pasta"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Pesquisar neste smartphone"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Pesquisar neste dispositivo"</string> <string name="delete_search_history" msgid="2202015025607694515">"Excluir <xliff:g id="TEXT">%1$s</xliff:g> do histórico de pesquisa"</string> <string name="personal_tab" msgid="3878576287868528503">"Pessoal"</string> <string name="work_tab" msgid="7265359366883747413">"Trabalho"</string> diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index 9eb8f12c6..972ef954d 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Mover para..."</string> <string name="menu_compress" msgid="37539111904724188">"Comprimir"</string> <string name="menu_extract" msgid="8171946945982532262">"Extrair para…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Extrair tudo…"</string> <string name="menu_rename" msgid="1883113442688817554">"Mudar o nome"</string> <string name="menu_inspect" msgid="7279855349299446224">"Obter informações"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Mostrar ficheiros ocultos"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Não é possível carregar o conteúdo neste momento"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"As Apps de trabalho estão suspensas."</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Ativar apps de trabalho"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"As apps do perfil <xliff:g id="PROFILE">%1$s</xliff:g> estão pausadas"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Ativar apps de <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Não é possível selecionar ficheiros de trabalho."</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"O seu administrador de TI não lhe permite aceder a ficheiros de trabalho a partir de uma app pessoal."</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Não é possível selecionar ficheiros pessoais."</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"O seu administrador de TI não lhe permite aceder a ficheiros pessoais a partir de uma app de trabalho."</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Não é possível selecionar ficheiros de <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"O seu administrador de TI não lhe permite aceder a ficheiros de <xliff:g id="PROFILE_0">%1$s</xliff:g> a partir de uma app <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Não é possível guardar no perfil de trabalho."</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"O seu administrador de TI não lhe permite guardar ficheiros pessoais no seu perfil de trabalho."</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Não é possível guardar no perfil pessoal."</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"O seu administrador de TI não lhe permite guardar ficheiros de trabalho no seu perfil pessoal."</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Não é possível guardar no perfil de <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"O seu administrador de TI não lhe permite guardar ficheiros <xliff:g id="PROFILE_0">%1$s</xliff:g> no seu perfil de <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Esta ação não é permitida"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Para saber mais, contacte o administrador de TI."</string> <string name="root_recent" msgid="1080156975424341623">"Recentes"</string> @@ -288,6 +295,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Novo nome"</string> <string name="preview_file" msgid="4056622696305432343">"Pré-visualizar o ficheiro <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Pré-visualize o ficheiro de trabalho <xliff:g id="FILENAME">%1$s</xliff:g>."</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Pré-visualize o ficheiro de <xliff:g id="PROFILE">%1$s</xliff:g> <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Procure ficheiros noutras apps"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anónimo"</string> <string name="open_tree_button" msgid="6402871398424497776">"Usar esta pasta"</string> @@ -296,7 +304,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Não é possível utilizar esta pasta"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Para proteger a sua privacidade, escolha outra pasta."</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Criar nova pasta"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Pesquise neste telemóvel"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Pesquise este dispositivo"</string> <string name="delete_search_history" msgid="2202015025607694515">"Elimine o histórico de pesquisas <xliff:g id="TEXT">%1$s</xliff:g>."</string> <string name="personal_tab" msgid="3878576287868528503">"Pessoal"</string> <string name="work_tab" msgid="7265359366883747413">"Trabalho"</string> diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml index 96030ed1e..3e492209d 100644 --- a/res/values-pt/strings.xml +++ b/res/values-pt/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Mover para…"</string> <string name="menu_compress" msgid="37539111904724188">"Compactar"</string> <string name="menu_extract" msgid="8171946945982532262">"Extrair para…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Extrair tudo…"</string> <string name="menu_rename" msgid="1883113442688817554">"Renomear"</string> <string name="menu_inspect" msgid="7279855349299446224">"Ver informações"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Mostrar arquivos ocultos"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Não é possível carregar o conteúdo no momento"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Os apps de trabalho foram pausados"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Ativar apps de trabalho"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Os apps do perfil <xliff:g id="PROFILE">%1$s</xliff:g> estão pausados"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Ativar apps do perfil <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Não é possível selecionar arquivos de trabalho"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Seu administrador de TI não permite que você acesse arquivos de trabalho em um app pessoal"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Não foi possível selecionar arquivos pessoais"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Seu administrador de TI não permite que você acesse arquivos pessoais em um app de trabalho"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Não é possível selecionar arquivos do perfil <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Seu administrador de TI não permite que arquivos do perfil <xliff:g id="PROFILE_0">%1$s</xliff:g> sejam acessados por um app do perfil <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Não é possível salvar no perfil de trabalho"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Seu administrador de TI não permite que você salve arquivos pessoais no perfil de trabalho"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Não é possível salvar no perfil pessoal"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Seu administrador de TI não permite que você salve arquivos de trabalho no perfil pessoal"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Não é possível salvar no perfil <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Seu administrador de TI não permite que arquivos do perfil <xliff:g id="PROFILE_0">%1$s</xliff:g> sejam salvos no perfil <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Essa ação não é permitida"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Para saber mais, entre em contato com o administrador de TI"</string> <string name="root_recent" msgid="1080156975424341623">"Recentes"</string> @@ -288,6 +295,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Novo nome"</string> <string name="preview_file" msgid="4056622696305432343">"Visualizar o arquivo <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Visualizar o arquivo de trabalho <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Visualizar o arquivo <xliff:g id="FILENAME">%2$s</xliff:g> do perfil <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Procurar arquivos em outros apps"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anônimo"</string> <string name="open_tree_button" msgid="6402871398424497776">"Usar esta pasta"</string> @@ -296,7 +304,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Não é possível usar essa pasta"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Para proteger sua privacidade, escolha outra pasta"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Criar nova pasta"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Pesquisar neste smartphone"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Pesquisar neste dispositivo"</string> <string name="delete_search_history" msgid="2202015025607694515">"Excluir <xliff:g id="TEXT">%1$s</xliff:g> do histórico de pesquisa"</string> <string name="personal_tab" msgid="3878576287868528503">"Pessoal"</string> <string name="work_tab" msgid="7265359366883747413">"Trabalho"</string> diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml index cc2f20ddf..d0a89f345 100644 --- a/res/values-ro/strings.xml +++ b/res/values-ro/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Mută în…"</string> <string name="menu_compress" msgid="37539111904724188">"Comprimă"</string> <string name="menu_extract" msgid="8171946945982532262">"Extrage în…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Extrage tot…"</string> <string name="menu_rename" msgid="1883113442688817554">"Redenumește"</string> <string name="menu_inspect" msgid="7279855349299446224">"Vezi informațiile"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Afișează fișierele ascunse"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Momentan, conținutul nu poate fi încărcat"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Aplicațiile pentru lucru sunt întrerupte"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Activează aplicațiile pentru lucru"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Aplicațiile <xliff:g id="PROFILE">%1$s</xliff:g> sunt întrerupte"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Activează aplicațiile <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Nu se pot selecta fișiere de lucru"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Administratorul IT nu îți permite să accesezi fișiere de lucru dintr-o aplicație personală"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Nu se pot selecta fișiere personale"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Administratorul IT nu îți permite să accesezi fișiere personale dintr-o aplicație pentru lucru"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Nu se pot selecta fișiere <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Administratorul IT nu îți permite să accesezi fișiere <xliff:g id="PROFILE_0">%1$s</xliff:g> dintr-o aplicație <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Nu se poate salva în profilul de serviciu"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Administratorul IT nu îți permite să salvezi fișiere personale în profilul de serviciu"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Nu se poate salva în profilul personal"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Administratorul IT nu îți permite să salvezi fișiere de lucru în profilul personal"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Nu se pot salva în profilul <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Administratorul IT nu îți permite să salvezi fișiere <xliff:g id="PROFILE_0">%1$s</xliff:g> în profilul <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Acțiunea nu este permisă"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Pentru a afla mai multe, contactează administratorul IT"</string> <string name="root_recent" msgid="1080156975424341623">"Recente"</string> @@ -288,6 +295,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Nume nou"</string> <string name="preview_file" msgid="4056622696305432343">"Previzualizează fișierul <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Previzualizează fișierul de lucru <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Previzualizează fișierul <xliff:g id="PROFILE">%1$s</xliff:g> <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Caută fișiere în alte aplicații"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonim"</string> <string name="open_tree_button" msgid="6402871398424497776">"Folosește acest dosar"</string> @@ -296,9 +304,9 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Nu poți folosi acest dosar"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Alege alt dosar, ca să-ți protejezi confidențialitatea"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Creează un dosar nou"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Caută în acest telefon"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Caută acest dispozitiv"</string> <string name="delete_search_history" msgid="2202015025607694515">"Șterge istoricul căutărilor <xliff:g id="TEXT">%1$s</xliff:g>"</string> - <string name="personal_tab" msgid="3878576287868528503">"Personale"</string> + <string name="personal_tab" msgid="3878576287868528503">"Personal"</string> <string name="work_tab" msgid="7265359366883747413">"Serviciu"</string> <string name="a11y_work" msgid="7504431382825242153">"Serviciu"</string> <string name="drag_from_another_app" msgid="8310249276199969905">"Nu poți muta fișiere din altă aplicație."</string> diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 5329c0aa1..f345cef8d 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Переместить в..."</string> <string name="menu_compress" msgid="37539111904724188">"Сжать"</string> <string name="menu_extract" msgid="8171946945982532262">"Извлечь"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Извлечь все…"</string> <string name="menu_rename" msgid="1883113442688817554">"Переименовать"</string> <string name="menu_inspect" msgid="7279855349299446224">"Сведения о файле"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Показывать скрытые файлы"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Не удалось загрузить контент"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Рабочие приложения приостановлены"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Включить рабочие приложения"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Работа приложений из профиля \"<xliff:g id="PROFILE">%1$s</xliff:g>\" приостановлена"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Включить приложения из профиля \"<xliff:g id="PROFILE">%1$s</xliff:g>\""</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Невозможно выбрать рабочие файлы"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Системный администратор запретил доступ к рабочим файлам из личных приложений."</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Невозможно выбрать личные файлы"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Системный администратор запретил доступ к личным файлам из рабочего приложения."</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Невозможно выбрать файлы из профиля \"<xliff:g id="PROFILE">%1$s</xliff:g>\""</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Системный администратор запретил доступ к файлам из профиля \"<xliff:g id="PROFILE_0">%1$s</xliff:g>\" в приложении из профиля \"<xliff:g id="PROFILE_1">%2$s</xliff:g>\"."</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Невозможно сохранить файлы"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Системный администратор запретил сохранять личные файлы в рабочем профиле."</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Невозможно сохранить файлы"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Системный администратор запретил сохранять рабочие файлы в личном профиле."</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Невозможно сохранить файлы в профиле \"<xliff:g id="PROFILE">%1$s</xliff:g>\""</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Системный администратор запретил сохранять файлы из профиля \"<xliff:g id="PROFILE_0">%1$s</xliff:g>\" в профиле \"<xliff:g id="PROFILE_1">%2$s</xliff:g>\"."</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Это действие запрещено"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Чтобы узнать больше, обратитесь к администратору."</string> <string name="root_recent" msgid="1080156975424341623">"Недавние"</string> @@ -310,6 +317,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Новое название"</string> <string name="preview_file" msgid="4056622696305432343">"Открыть файл \"<xliff:g id="FILENAME">%1$s</xliff:g>\" в режиме предпросмотра."</string> <string name="preview_work_file" msgid="4495643735563487273">"Предпросмотр рабочего файла \"<xliff:g id="FILENAME">%1$s</xliff:g>\""</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Предпросмотр файла \"<xliff:g id="FILENAME">%2$s</xliff:g>\" из профиля \"<xliff:g id="PROFILE">%1$s</xliff:g>\""</string> <string name="apps_row_title" msgid="3340490016663092925">"Поиск файлов в других приложениях"</string> <string name="anonymous_application" msgid="7633027057951625862">"Анонимное приложение"</string> <string name="open_tree_button" msgid="6402871398424497776">"Использовать эту папку"</string> @@ -318,9 +326,9 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Выберите другую папку"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"В целях защиты вашей конфиденциальности мы заблокировали доступ к этой папке."</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Новая папка"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Поиск на этом телефоне"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Поиск на устройстве"</string> <string name="delete_search_history" msgid="2202015025607694515">"Очистить историю поиска: <xliff:g id="TEXT">%1$s</xliff:g>"</string> - <string name="personal_tab" msgid="3878576287868528503">"Личное"</string> + <string name="personal_tab" msgid="3878576287868528503">"Личный"</string> <string name="work_tab" msgid="7265359366883747413">"Рабочее"</string> <string name="a11y_work" msgid="7504431382825242153">"Работа"</string> <string name="drag_from_another_app" msgid="8310249276199969905">"Перемещать файлы из другого приложения нельзя."</string> diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml index 5652758bf..48d8f5f75 100644 --- a/res/values-si/strings.xml +++ b/res/values-si/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"වෙත ගෙනයන්න..."</string> <string name="menu_compress" msgid="37539111904724188">"සම්පීඩනය කරන්න"</string> <string name="menu_extract" msgid="8171946945982532262">"උපුටා ගන්න…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"සියල්ල උපුටා ගන්න…"</string> <string name="menu_rename" msgid="1883113442688817554">"යළි නම් කරන්න"</string> <string name="menu_inspect" msgid="7279855349299446224">"තොරතුරු ලබා ගන්න"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"සැඟවුණු ගොනු පෙන්වන්න"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"මේ මොහොතේ අන්තර්ගතය පූරණය කිරීමට නොහැකිය"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"කාර්යාල යෙදුම් විරාම කර ඇත"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"කාර්යාල යෙදුම් ක්රියාත්මක කරන්න"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> යෙදුම් විරාම කළා"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> යෙදුම් සක්රීය කරන්න"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"කාර්යාල ගොනු තේරීමට හැකිය"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"ඔබේ IT පරිපාලක ඔබට පෞද්ගලික යෙදුමකින් කාර්යාල ගොනු වෙත ප්රවේශ වීමට ඉඩ නොදේ"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"පෞද්ගලික ගොනු තේරීමට නොහැකිය"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"ඔබේ IT පරිපාලක ඔබට කාර්යාල යෙදුමකින් පෞද්ගලික ගොනු වෙත ප්රවේශ වීමට ඉඩ නොදේ"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> ගොනු තේරිය නොහැක"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"ඔබේ තොරතුරු තාක්ෂණ පරිපාලක <xliff:g id="PROFILE_0">%1$s</xliff:g> ගොනු වෙත <xliff:g id="PROFILE_1">%2$s</xliff:g> යෙදුමකින් ප්රවේශ වීමට ඉඩ නොදෙයි"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"කාර්යාල පැතිකඩ වෙත සුරැකිය නොහැකිය"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"ඔබේ IT පරිපාලක පෞද්ගලික ගොනු ඔබේ කාර්යාල පැතිකඩ වෙත සුරැකීමට ඉඩ නොදේ"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"පෞද්ගලික පැතිකඩ වෙත සුරැකීමට හැකිය"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"ඔබේ IT පරිපාලක කාර්යාල ගොනු ඔබේ පෞද්ගලික පැතිකඩ වෙත සුරැකීමට ඉඩ නොදේ"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> පැතිකඩට සුරැකිය නො හැකි ය"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"ඔබේ තොරතුරු තාලක්ෂණ පරිපාලක ඔබට <xliff:g id="PROFILE_0">%1$s</xliff:g> ගොනු ඔබේ <xliff:g id="PROFILE_1">%2$s</xliff:g> පැතිකඩෙහි සුරැකීමට ඉඩ නොදෙයි"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"මෙම ක්රියාව ඉඩ දී නැත"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"තවත් දැන ගැනීමට, ඔබේ IT සම්බන්ධ කර ගන්න"</string> <string name="root_recent" msgid="1080156975424341623">"මෑත"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"අලුත් නම"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g> ගොනුව පෙර දකින්න"</string> <string name="preview_work_file" msgid="4495643735563487273">"<xliff:g id="FILENAME">%1$s</xliff:g> කාර්යාල ගොනුව පෙරදසුන් කරන්න"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> <xliff:g id="FILENAME">%2$s</xliff:g> ගොනුව පෙරදකින්න"</string> <string name="apps_row_title" msgid="3340490016663092925">"වෙනත් යෙදුම්වල ගොනු බ්රවුස් කරන්න"</string> <string name="anonymous_application" msgid="7633027057951625862">"නිර්නාමික"</string> <string name="open_tree_button" msgid="6402871398424497776">"මෙම ෆෝල්ඩරය භාවිත කරන්න"</string> @@ -274,9 +282,9 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"මෙම ෆෝල්ඩරය භාවිත කළ නොහැකිය"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"ඔබේ රහස්යතාව ආරක්ෂා කිරීමට, තවත් ෆෝල්ඩරයක් තෝරා ගන්න"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"නව ෆෝල්ඩරය තනන්න"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"මෙම දුරකථනයේ සොයන්න"</string> + <string name="search_bar_hint" msgid="146031513183888721">"මෙම උපාංගය සොයන්න"</string> <string name="delete_search_history" msgid="2202015025607694515">"සෙවීම් ඉතිහාසය මකන්න <xliff:g id="TEXT">%1$s</xliff:g>"</string> - <string name="personal_tab" msgid="3878576287868528503">"පෞද්ගලික"</string> + <string name="personal_tab" msgid="3878576287868528503">"පුද්ගලික"</string> <string name="work_tab" msgid="7265359366883747413">"කාර්යාල"</string> <string name="a11y_work" msgid="7504431382825242153">"කාර්යාල"</string> <string name="drag_from_another_app" msgid="8310249276199969905">"ඔබට වෙනත් යෙදුමකින් ගොනු ගෙන ඒමට නොහැකිය."</string> diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml index 01dfe583d..db6a892e8 100644 --- a/res/values-sk/strings.xml +++ b/res/values-sk/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Presunúť do…"</string> <string name="menu_compress" msgid="37539111904724188">"Komprimovať"</string> <string name="menu_extract" msgid="8171946945982532262">"Rozbaliť do…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Extrahovať všetko…"</string> <string name="menu_rename" msgid="1883113442688817554">"Premenovať"</string> <string name="menu_inspect" msgid="7279855349299446224">"Zobraziť informácie"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Zobraziť skryté súbory"</string> @@ -52,13 +53,13 @@ <string name="menu_view_in_owner" msgid="7228948660557554770">"Zobraziť v službe <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="menu_new_window" msgid="2947837751796109126">"Nové okno"</string> <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Vystrihnúť"</string> - <string name="menu_copy_to_clipboard" msgid="5064081159073330776">"Kopírovať"</string> + <string name="menu_copy_to_clipboard" msgid="5064081159073330776">"Skopírovať"</string> <string name="menu_paste_from_clipboard" msgid="360947260414135827">"Prilepiť"</string> <string name="menu_paste_into_folder" msgid="8000644546983240101">"Prilepiť do priečinka"</string> <string name="menu_advanced_show" msgid="7558626506462906726">"Zobraziť interné úložisko"</string> <string name="menu_advanced_hide" msgid="6488381508009246334">"Skryť interné úložisko"</string> <string name="button_select" msgid="240863497069321364">"Vybrať"</string> - <string name="button_copy" msgid="8219059853840996027">"Kopírovať"</string> + <string name="button_copy" msgid="8219059853840996027">"Skopírovať"</string> <string name="button_compress" msgid="8951561310857223966">"Komprimovať"</string> <string name="button_extract" msgid="1038674453689912247">"Extrahovať"</string> <string name="button_move" msgid="8596460499325291272">"Presunúť"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Obsah momentálne nie je možné načítať"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Pracovné aplikácie sú pozastavené"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Zapnúť pracovné aplikácie"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Aplikácie profilu <xliff:g id="PROFILE">%1$s</xliff:g> sú pozastavené"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Zapnúť aplikácie profilu <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Pracovné súbory sa nedajú vybrať"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Váš správca IT vám zakázal prístup k pracovným súborom z osobnej aplikácie"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Osobné súbory sa nedajú vybrať"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Váš správca IT vám zakázal prístup k osobným súborom z pracovnej aplikácie"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Súbory profilu <xliff:g id="PROFILE">%1$s</xliff:g> sa nedajú vybrať"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Váš správca IT vám nepovolil prístup k súborom profilu <xliff:g id="PROFILE_0">%1$s</xliff:g> z aplikácie profilu <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Nie je možné ukladať do pracovného profilu"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Váš správca IT vám zakázal ukladať osobné súbory do pracovného profilu"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Nedajú sa uložiť do osobného profilu"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Váš správca IT vám zakázal ukladať pracovné súbory do osobného profilu"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Nie je možné uložiť do profilu <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Váš správca IT vám nepovolil ukladanie súborov profilu <xliff:g id="PROFILE_0">%1$s</xliff:g> do profilu <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Táto akcia nie je povolená"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Viac sa dozviete od svojho správcu IT"</string> <string name="root_recent" msgid="1080156975424341623">"Nedávne"</string> @@ -310,6 +317,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Nové názov"</string> <string name="preview_file" msgid="4056622696305432343">"Zobraziť ukážku súboru <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Zobraziť ukážku pracovného súboru <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Zobrazte si ukážku súboru profilu <xliff:g id="PROFILE">%1$s</xliff:g> s názvom <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Prehliadanie súborov v iných aplikáciách"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonymná"</string> <string name="open_tree_button" msgid="6402871398424497776">"Použiť tento priečinok"</string> @@ -318,7 +326,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Tento priečinok sa nedá použiť"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Ak chcete ochrániť svoje súkromie, vyberte iný priečinok"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Vytvoriť nový priečinok"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Hľadať v telefóne"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Vyhľadajte v tomto zariadení"</string> <string name="delete_search_history" msgid="2202015025607694515">"Odstrániť históriu vyhľadávania <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Osobné"</string> <string name="work_tab" msgid="7265359366883747413">"Práca"</string> diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml index 3a1e0b44e..d14c32517 100644 --- a/res/values-sl/strings.xml +++ b/res/values-sl/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Premakni v ..."</string> <string name="menu_compress" msgid="37539111904724188">"Stisni"</string> <string name="menu_extract" msgid="8171946945982532262">"Razširi v …"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Razširi vse …"</string> <string name="menu_rename" msgid="1883113442688817554">"Preimenuj"</string> <string name="menu_inspect" msgid="7279855349299446224">"Prikaži informacije"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Prikaži skrite datoteke"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Vsebine trenutno ni mogoče naložiti"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Delovne aplikacije so začasno zaustavljene"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Vklopi delovne aplikacije"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Aplikacije profila »<xliff:g id="PROFILE">%1$s</xliff:g>« so začasno zaustavljene"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Vklopi aplikacije profila »<xliff:g id="PROFILE">%1$s</xliff:g>«"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Ni mogoče izbrati službenih datotek"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Skrbnik za IT ne dovoli dostopa do službenih datotek iz osebne aplikacije"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Ni mogoče izbrati osebnih datotek"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Skrbnik za IT ne dovoli dostopa do osebnih datotek iz delovne aplikacije"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Ni mogoče izbrati datotek profila »<xliff:g id="PROFILE">%1$s</xliff:g>«"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Skrbnik za IT ne dovoli dostopanja do datotek profila »<xliff:g id="PROFILE_0">%1$s</xliff:g>« iz aplikacije profila »<xliff:g id="PROFILE_1">%2$s</xliff:g>«"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Ni mogoče shraniti v delovni profil"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Skrbnik za IT ne dovoli shranjevanja osebnih datotek v delovni profil"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Ni mogoče shraniti v osebni profil"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Skrbnik za IT ne dovoli shranjevanja službenih datotek v osebni profil"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Ni mogoče shraniti v profil »<xliff:g id="PROFILE">%1$s</xliff:g>«"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Skrbnik za IT ne dovoli shranjevanja datotek profila »<xliff:g id="PROFILE_0">%1$s</xliff:g>« v profil »<xliff:g id="PROFILE_1">%2$s</xliff:g>«"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"To dejanje ni dovoljeno"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Za več informacij se obrnite na skrbnika za IT"</string> <string name="root_recent" msgid="1080156975424341623">"Nedavno"</string> @@ -310,6 +317,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Novo ime"</string> <string name="preview_file" msgid="4056622696305432343">"Predogled datoteke <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Predogled delovne datoteke <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Predogled datoteke »<xliff:g id="FILENAME">%2$s</xliff:g>« iz profila »<xliff:g id="PROFILE">%1$s</xliff:g>«"</string> <string name="apps_row_title" msgid="3340490016663092925">"Brskanje po datotekah v drugih aplikacijah"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonimno"</string> <string name="open_tree_button" msgid="6402871398424497776">"Uporabi to mapo"</string> @@ -318,7 +326,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Te mape ni mogoče uporabiti"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Izberite drugo mapo, da zaščitite svojo zasebnost"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Ustvari novo mapo"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Iščite v tem telefonu"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Iskanje v tej napravi"</string> <string name="delete_search_history" msgid="2202015025607694515">"Brisanje zgodovine iskanja <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Osebno"</string> <string name="work_tab" msgid="7265359366883747413">"Služba"</string> diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml index 30d115d24..7f2ddfdd7 100644 --- a/res/values-sq/strings.xml +++ b/res/values-sq/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Zhvendos te..."</string> <string name="menu_compress" msgid="37539111904724188">"Ngjish"</string> <string name="menu_extract" msgid="8171946945982532262">"Nxirre te…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Nxirri të gjitha…"</string> <string name="menu_rename" msgid="1883113442688817554">"Riemërto"</string> <string name="menu_inspect" msgid="7279855349299446224">"Merr informacione"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Shfaq skedarët e fshehur"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Përmbajtja nuk mund të ngarkohet për momentin"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Aplikacionet e punës janë vendosur në pauzë"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Aktivizo aplikacionet e punës"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Aplikacionet e profilit \"<xliff:g id="PROFILE">%1$s</xliff:g>\" janë vendosur në pauzë"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Aktivizo aplikacionet e profilit \"<xliff:g id="PROFILE">%1$s</xliff:g>\""</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Nuk mund të zgjedhësh skedarë pune"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Administratori i teknologjisë së informacionit nuk të lejon të kesh qasje te skedarët e punës nga një aplikacion personal"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Nuk mund të zgjedhësh skedarë personalë"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Administratori yt i teknologjisë së informacionit nuk të lejon të kesh qasje te skedarët personalë nga një aplikacion i punës"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Skedarët e profilit \"<xliff:g id="PROFILE">%1$s</xliff:g>\" nuk mund të zgjidhen"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Administratori yt i teknologjisë së informacionit nuk të lejon të kesh qasje te skedarët e profilit \"<xliff:g id="PROFILE_0">%1$s</xliff:g>\" nga një aplikacion i profilit \"<xliff:g id="PROFILE_1">%2$s</xliff:g>\""</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Nuk mund të ruhen në profilin tënd të punës"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Administratori yt i teknologjisë së informacionit nuk të lejon të ruash skedarët personalë në profilin tënd të punës"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Nuk mund të ruhen në profilin tënd personal"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Administratori yt i teknologjisë së informacionit nuk të lejon të ruash skedarët e punës në profilin tënd personal"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Nuk mund të ruash te profili \"<xliff:g id="PROFILE">%1$s</xliff:g>\""</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Administratori yt i teknologjisë së informacionit nuk të lejon të ruash skedarët e profilit \"<xliff:g id="PROFILE_0">%1$s</xliff:g>\" te profili \"<xliff:g id="PROFILE_1">%2$s</xliff:g>\""</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Ky veprim nuk lejohet"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Për të mësuar më shumë, kontakto me administratorin tënd të teknologjisë së informacionit"</string> <string name="root_recent" msgid="1080156975424341623">"Të fundit"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Emri i ri"</string> <string name="preview_file" msgid="4056622696305432343">"Shiko paraprakisht skedarin <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Shiko paraprakisht skedarin e punës <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Shiko paraprakisht skedarin e profilit \"<xliff:g id="PROFILE">%1$s</xliff:g>\": <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Shfleto skedarët në aplikacionet e tjera"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonim"</string> <string name="open_tree_button" msgid="6402871398424497776">"Përdor këtë dosje"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Kjo dosje nuk mund të përdoret"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Për të mbrojtur privatësinë tënde, zgjidh një dosje tjetër"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Krijo dosje të re"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Kërko në këtë telefon"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Kërko në këtë pajisje"</string> <string name="delete_search_history" msgid="2202015025607694515">"Fshi historikun e kërkimeve për <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Personale"</string> <string name="work_tab" msgid="7265359366883747413">"Puna"</string> diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml index 8fe2718e5..343e77050 100644 --- a/res/values-sr/strings.xml +++ b/res/values-sr/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Премести у…"</string> <string name="menu_compress" msgid="37539111904724188">"Компримуј"</string> <string name="menu_extract" msgid="8171946945982532262">"Издвој у…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Издвоји све…"</string> <string name="menu_rename" msgid="1883113442688817554">"Преименуј"</string> <string name="menu_inspect" msgid="7279855349299446224">"Прикажи информације"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Приказуј скривене датотеке"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Учитавање садржаја тренутно није могуће"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Пословне апликације су паузиране"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Укључи пословне апликације"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Паузиране су апликације профила: <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Укључи апликације профила: <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Не можете да изаберете пословне фајлове"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"ИТ администратор вам не дозвољава да приступате датотекама за посао из личне апликације"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Избор личних датотека није успео"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"ИТ администратор вам не дозвољава да приступате личним датотекама из пословне апликације"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Не можете да изаберете фајлове са профила: <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"ИТ администратор не дозвољава да фајловима на профилу: <xliff:g id="PROFILE_0">%1$s</xliff:g> приступате из апликације профила: <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Не можете да сачувате на пословном профилу"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"ИТ администратор вам не дозвољава да чувате личне датотеке на пословном профилу"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Не можете да сачувате на личном профилу"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"ИТ администратор вам не дозвољава да чувате датотеке за посао на личном профилу"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Не можете да чувате на профилу: <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"ИТ администратор не дозвољава да фајлове са профила: <xliff:g id="PROFILE_0">%1$s</xliff:g> чувате на профилу: <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Ова радња није дозвољена"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Обратите се ИТ администратору да бисте сазнали више"</string> <string name="root_recent" msgid="1080156975424341623">"Недавно"</string> @@ -280,7 +287,7 @@ <string name="root_info_header_image_app_with_summary" msgid="6404842960923224778">"Слике из: <xliff:g id="LABEL">%1$s</xliff:g>/<xliff:g id="SUMMARY">%2$s</xliff:g>"</string> <string name="chip_title_images" msgid="7838299046109841015">"Слике"</string> <string name="chip_title_audio" msgid="1032801828748235436">"Звук"</string> - <string name="chip_title_videos" msgid="7011260091979776447">"Видео снимци"</string> + <string name="chip_title_videos" msgid="7011260091979776447">"Видеи"</string> <string name="chip_title_documents" msgid="7432457563000753983">"Документи"</string> <string name="chip_title_large_files" msgid="7740269190493883980">"Велике датотеке"</string> <string name="chip_title_from_this_week" msgid="4961536405220379672">"Ове недеље"</string> @@ -288,6 +295,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Нови назив"</string> <string name="preview_file" msgid="4056622696305432343">"Прегледајте датотеку <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Прегледајте датотеку за посао <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Прегледајте фајл <xliff:g id="FILENAME">%2$s</xliff:g> са профила: <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Прегледајте датотеке у другим апликацијама"</string> <string name="anonymous_application" msgid="7633027057951625862">"Анонимна"</string> <string name="open_tree_button" msgid="6402871398424497776">"Користи овај фолдер"</string> @@ -296,7 +304,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Не можете да користите овај фолдер"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Да бисте заштитили приватност, одаберите неки други фолдер"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Направи нови фолдер"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Претражите овај телефон"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Претражи овај уређај"</string> <string name="delete_search_history" msgid="2202015025607694515">"Избришите историју претраге <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Лично"</string> <string name="work_tab" msgid="7265359366883747413">"Посао"</string> diff --git a/res/values-sv/inspector_strings.xml b/res/values-sv/inspector_strings.xml index b37c48977..b82a50910 100644 --- a/res/values-sv/inspector_strings.xml +++ b/res/values-sv/inspector_strings.xml @@ -33,7 +33,7 @@ <string name="metadata_camera" msgid="2363009732801281319">"Kamera"</string> <string name="metadata_camera_format" msgid="1494489751904311612">"<xliff:g id="MAKE">%1$s</xliff:g> <xliff:g id="MODEL">%2$s</xliff:g>"</string> <string name="metadata_aperture" msgid="6538741952698935357">"Bländare"</string> - <string name="metadata_shutter_speed" msgid="8204739885103326131">"Slutarhastighet"</string> + <string name="metadata_shutter_speed" msgid="8204739885103326131">"Slutartid"</string> <string name="metadata_duration" msgid="3115494422055472715">"Längd"</string> <string name="metadata_date_time" msgid="1090351199248114406">"Taget den"</string> <string name="metadata_focal_length" msgid="3440735161407699893">"Brännvidd"</string> diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index 385808c77..1c6be4153 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Flytta till ..."</string> <string name="menu_compress" msgid="37539111904724188">"Komprimera"</string> <string name="menu_extract" msgid="8171946945982532262">"Extrahera till …"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Extrahera alla …"</string> <string name="menu_rename" msgid="1883113442688817554">"Byt namn"</string> <string name="menu_inspect" msgid="7279855349299446224">"Hämta information"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Visa dolda filer"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Det går inte att läsa in innehållet just nu"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Jobbappar har pausats"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Aktivera jobbappar"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Appar för profilen <xliff:g id="PROFILE">%1$s</xliff:g> har pausats"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Slå på <xliff:g id="PROFILE">%1$s</xliff:g>appar"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Det går inte att välja jobbfiler"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"IT-administratören tillåter inte att du öppnar jobbfiler i en privat app"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Det går inte att välja privata filer"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"IT-administratören tillåter inte att du öppnar privata filer i en jobbapp"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Det gick inte att välja <xliff:g id="PROFILE">%1$s</xliff:g>filer"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"IT-administratören tillåter inte att du sparar <xliff:g id="PROFILE_0">%1$s</xliff:g>filer från en <xliff:g id="PROFILE_1">%2$s</xliff:g> app"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Det går inte att spara i jobbprofilen"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"IT-administratören tillåter inte att du sparar privata filer i jobbprofilen"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Det går inte att spara i den privata profilen"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"IT-administratören tillåter inte att du sparar jobbfiler i den privata profilen"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Det gick inte att spara i <xliff:g id="PROFILE">%1$s</xliff:g>profilen"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"IT-administratören tillåter inte att du sparar <xliff:g id="PROFILE_0">%1$s</xliff:g>filer i den <xliff:g id="PROFILE_1">%2$s</xliff:g> profilen"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Förbjuden åtgärd"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Kontakta IT-administratören om du vill veta mer"</string> <string name="root_recent" msgid="1080156975424341623">"Senaste"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Nytt namn"</string> <string name="preview_file" msgid="4056622696305432343">"Förhandsgranska filen <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Förhandsgranska jobbfilen <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Förhandsgranska <xliff:g id="PROFILE">%1$s</xliff:g>filen <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Bläddra efter filer i andra appar"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonym"</string> <string name="open_tree_button" msgid="6402871398424497776">"Använd den här mappen"</string> @@ -274,9 +282,9 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Det går inte att använda den här mappen"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Välj en annan mapp för att skydda din integritet"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Skapa ny mapp"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Sök på telefonen"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Sök på den här enheten"</string> <string name="delete_search_history" msgid="2202015025607694515">"Radera sökhistorik – <xliff:g id="TEXT">%1$s</xliff:g>"</string> - <string name="personal_tab" msgid="3878576287868528503">"Privat"</string> + <string name="personal_tab" msgid="3878576287868528503">"Personlig"</string> <string name="work_tab" msgid="7265359366883747413">"Jobb"</string> <string name="a11y_work" msgid="7504431382825242153">"Jobb"</string> <string name="drag_from_another_app" msgid="8310249276199969905">"Du kan inte flytta filer från en annan app."</string> diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml index 47307832f..e030a1029 100644 --- a/res/values-sw/strings.xml +++ b/res/values-sw/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Hamishia kwenye..."</string> <string name="menu_compress" msgid="37539111904724188">"Bana"</string> <string name="menu_extract" msgid="8171946945982532262">"Weka kwenye…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Dondoa zote…"</string> <string name="menu_rename" msgid="1883113442688817554">"Badilisha jina"</string> <string name="menu_inspect" msgid="7279855349299446224">"Pata maelezo zaidi"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Onyesha faili zilizofichwa"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Imeshindwa kupakia maudhui kwa sasa"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Programu za kazini zimesimamishwa"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Washa programu za kazini"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Programu za <xliff:g id="PROFILE">%1$s</xliff:g> zimesitishwa"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Washa programu za <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Imeshindwa kuchagua faili za kazini"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Msimamizi wako wa TEHAMA hakuruhusu ufikie faili za kazini kwenye programu ya binafsi"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Imeshindwa kuchagua faili za binafsi"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Msimamizi wako wa TEHAMA hakuruhusu ufikie faili za binafsi ukitumia programu ya kazini"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Huwezi kuchagua faili za <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Msimamizi wako wa TEHAMA hakuruhusu ufikie faili za <xliff:g id="PROFILE_0">%1$s</xliff:g> kwenye programu yako <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Imeshindwa kuhifadhi kwenye wasifu wa kazini"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Msimamizi wako wa TEHAMA hakuruhusu uhifadhi faili za binafsi kwenye wasifu wa kazini"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Imeshindwa kuhifadhi kwenye wasifu wa binafsi"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Msimamizi wako wa TEHAMA hakuruhusu uhifadhi faili za kazini kwenye wasifu wako wa binafsi"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Imeshindwa kuhifadhi kwenye wasifu wa <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Msimamizi wako wa TEHAMA hakuruhusu uhifadhi faili <xliff:g id="PROFILE_0">%1$s</xliff:g> kwenye wasifu wako wa <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Kitendo hiki hakiruhusiwi"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Ili upate maelezo zaidi, wasiliana na msimamizi wako wa TEHAMA"</string> <string name="root_recent" msgid="1080156975424341623">"Za hivi majuzi"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Jina jipya"</string> <string name="preview_file" msgid="4056622696305432343">"Kagua faili ya <xliff:g id="FILENAME">%1$s</xliff:g> kwanza"</string> <string name="preview_work_file" msgid="4495643735563487273">"Kagua kwanza fali ya kazini ya <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Kagua kwanza faili ya <xliff:g id="PROFILE">%1$s</xliff:g> ya <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Vinjari faili katika programu nyingine"</string> <string name="anonymous_application" msgid="7633027057951625862">"Haijulikani"</string> <string name="open_tree_button" msgid="6402871398424497776">"Tumia folda hii"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Huwezi kutumia folda hii"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Ili ulinde faragha yako, chagua folda nyingine"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Fungua folda mpya"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Tafuta kwenye simu hii"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Tafuta kwenye kifaa hiki"</string> <string name="delete_search_history" msgid="2202015025607694515">"Futa <xliff:g id="TEXT">%1$s</xliff:g> ya historia ya mambo uliyotafuta"</string> <string name="personal_tab" msgid="3878576287868528503">"Binafsi"</string> <string name="work_tab" msgid="7265359366883747413">"Kazini"</string> diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml index 5ec185c48..b8392fe0b 100644 --- a/res/values-ta/strings.xml +++ b/res/values-ta/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"இங்கு நகர்த்து…"</string> <string name="menu_compress" msgid="37539111904724188">"அளவைக் குறை"</string> <string name="menu_extract" msgid="8171946945982532262">"இங்கு பிரி…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"அனைத்தையும் பிரித்தெடு…"</string> <string name="menu_rename" msgid="1883113442688817554">"பெயர் மாற்று"</string> <string name="menu_inspect" msgid="7279855349299446224">"தகவலைப் பெறு"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"மறைக்கப்பட்ட ஃபைல்களைக் காட்டு"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"தற்போது உள்ளடக்கத்தை ஏற்ற முடியவில்லை"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"பணி ஆப்ஸ் இடைநிறுத்தப்பட்டுள்ளன"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"பணி ஆப்ஸை இயக்கு"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> ஆப்ஸ் இடைநிறுத்தப்பட்டுள்ளன"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> ஆப்ஸை இயக்கு"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"பணி ஃபைல்களைத் தேர்ந்தெடுக்க முடியாது"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"பணி ஃபைல்களைத் தனிப்பட்ட பணி ஆப்ஸில் இருந்து அணுகுவதை உங்கள் IT நிர்வாகி அனுமதிக்கவில்லை"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"தனிப்பட்ட ஃபைல்களைத் தேர்ந்தெடுக்க முடியாது"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"தனிப்பட்ட ஃபைல்களைப் பணி ஆப்ஸில் இருந்து அணுகுவதை உங்கள் IT நிர்வாகி அனுமதிக்கவில்லை"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> ஃபைல்களைத் தேர்ந்தெடுக்க முடியவில்லை"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"<xliff:g id="PROFILE_0">%1$s</xliff:g> ஃபைல்களை <xliff:g id="PROFILE_1">%2$s</xliff:g> ஆப்ஸில் இருந்து அணுக உங்கள் IT நிர்வாகி அனுமதிக்கவில்லை"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"பணிக் கணக்கில் சேமிக்க முடியாது"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"தனிப்பட்ட ஃபைல்களைப் பணிக் கணக்கில் சேமிக்க உங்கள் IT நிர்வாகி அனுமதிக்கவில்லை"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"தனிப்பட்ட கணக்கில் சேமிக்க முடியாது"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"பணி ஃபைல்களைத் தனிப்பட்ட கணக்கில் சேமிக்க உங்கள் IT நிர்வாகி அனுமதிக்கவில்லை"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> சுயவிவரத்தில் சேமிக்க முடியவில்லை"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"<xliff:g id="PROFILE_0">%1$s</xliff:g> ஃபைல்களை உங்கள் <xliff:g id="PROFILE_1">%2$s</xliff:g> சுயவிவரத்தில் சேமிக்க உங்கள் IT நிர்வாகி அனுமதிக்கவில்லை"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"இந்தச் செயலுக்கு அனுமதியில்லை"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"மேலும் அறிய IT நிர்வாகியைத் தொடர்புகொள்ளவும்"</string> <string name="root_recent" msgid="1080156975424341623">"சமீபத்தியவை"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"புதிய பெயர்"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g> என்ற ஃபைல் மாதிரிக்காட்சியாகத் தெரியும்"</string> <string name="preview_work_file" msgid="4495643735563487273">"<xliff:g id="FILENAME">%1$s</xliff:g> என்ற பணி ஃபைலின் மாதிரிக்காட்சியைப் பார்க்கவும்"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> ஃபைலின் (<xliff:g id="FILENAME">%2$s</xliff:g>) மாதிரிக்காட்சியைக் காட்டும்"</string> <string name="apps_row_title" msgid="3340490016663092925">"ஃபைல்களை வேறு ஆப்ஸில் தேடவும்"</string> <string name="anonymous_application" msgid="7633027057951625862">"பெயர் குறிப்பிடாதது"</string> <string name="open_tree_button" msgid="6402871398424497776">"இந்த ஃபோல்டரைப் பயன்படுத்து"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"ஃபோல்டரைப் பயன்படுத்த இயலாது"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"உங்கள் தனியுரிமையைப் பாதுகாக்க மற்றொரு ஃபோல்டரைத் தேர்வுசெய்யவும்"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"புதிய ஃபோல்டரை உருவாக்கு"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"இந்த மொபைலில் தேடவும்"</string> + <string name="search_bar_hint" msgid="146031513183888721">"இந்தச் சாதனத்தில் தேடுக"</string> <string name="delete_search_history" msgid="2202015025607694515">"தேடல் வரலாற்றை நீக்கும் பட்டன் <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"தனிப்பட்டவை"</string> <string name="work_tab" msgid="7265359366883747413">"பணி"</string> diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml index b8879c828..2c4d3d3d0 100644 --- a/res/values-te/strings.xml +++ b/res/values-te/strings.xml @@ -24,7 +24,7 @@ <skip /> <!-- no translation found for launcher_label (799410258349837668) --> <skip /> - <string name="title_open" msgid="3165686459158020921">"ఇక్కడి నుండి తెరువు"</string> + <string name="title_open" msgid="3165686459158020921">"ఫోల్డర్ లొకేషన్ను ఎంచుకోండి"</string> <string name="title_save" msgid="4384490653102710025">"ఇందులో సేవ్ చేయండి"</string> <string name="menu_create_dir" msgid="2413624798689091042">"కొత్త ఫోల్డర్"</string> <string name="menu_grid" msgid="1453636521731880680">"గ్రిడ్ వీక్షణ"</string> @@ -35,7 +35,7 @@ <string name="menu_open_with" msgid="5507647065467520229">"దీనితో తెరువు"</string> <string name="menu_open_in_new_window" msgid="6686563636123311276">"కొత్త విండోలో తెరవండి"</string> <string name="menu_save" msgid="5195367497138965168">"సేవ్ చేయండి"</string> - <string name="menu_share" msgid="4307140947108068356">"షేర్ చేయి"</string> + <string name="menu_share" msgid="4307140947108068356">"షేర్ చేయండి"</string> <string name="menu_delete" msgid="1022254131543256626">"తొలగించండి"</string> <string name="menu_select_all" msgid="7600576812185570403">"అన్నింటినీ ఎంచుకోండి"</string> <string name="menu_deselect_all" msgid="7729916068862742979">"అన్నింటి ఎంపికను తీసివేయండి"</string> @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"ఇక్కడికి తరలించు..."</string> <string name="menu_compress" msgid="37539111904724188">"కుదించు"</string> <string name="menu_extract" msgid="8171946945982532262">"దీనిలోకి సంగ్రహించు…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"అన్నీ ఎక్స్ట్రాక్ట్ చేయండి…"</string> <string name="menu_rename" msgid="1883113442688817554">"పేరు మార్చు"</string> <string name="menu_inspect" msgid="7279855349299446224">"సమాచారాన్ని పొందండి"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"దాచబడిన ఫైళ్లను చూపించు"</string> @@ -86,7 +87,7 @@ <string name="directory_items" msgid="6645621978998614003">"అంశాల సంఖ్య"</string> <string name="sort_direction_ascending" msgid="5882787683763248102">"ఆరోహణ"</string> <string name="sort_direction_descending" msgid="1729187589765894076">"అవరోహణ"</string> - <string name="open_external_app" msgid="7107920381038980086">"<xliff:g id="APPNAME">%1$s</xliff:g>ని తెరువు"</string> + <string name="open_external_app" msgid="7107920381038980086">"<xliff:g id="APPNAME">%1$s</xliff:g>ను తెరవండి"</string> <string name="drawer_open" msgid="8071673398187261741">"మూలాలను చూపు"</string> <string name="drawer_close" msgid="4263880768630848848">"మూలాలను దాచు"</string> <string name="save_error" msgid="8631128801982095782">"డాక్యుమెంట్ను సేవ్ చేయడంలో విఫలమైంది"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"ఈ సమయంలో కంటెంట్ను లోడ్ చేయడం సాధ్యపడదు"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"వర్క్ యాప్లు పాజ్ చేయబడ్డాయి"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"వర్క్ యాప్లను ఆన్ చేయండి"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> యాప్లు పాజ్ చేయబడ్డాయి"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> యాప్లను ఆన్ చేయండి"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"కార్యాలయ ఫైళ్లను ఎంపిక చేయడం సాధ్యం కాదు"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"వ్యక్తిగత యాప్ నుండి ఆఫీస్ ఫైళ్లను యాక్సెస్ చేయడానికి మీ IT అడ్మిన్ అనుమతించరు"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"వ్యక్తిగత ఫైళ్లను ఎంపిక చేయడం సాధ్యం కాదు"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"ఆఫీస్ యాప్ నుండి వ్యక్తిగత ఫైళ్లను యాక్సెస్ చేయడానికి మీ IT అడ్మిన్ అనుమతించరు"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> ఫైల్స్ను ఎంచుకోలేరు"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"<xliff:g id="PROFILE_1">%2$s</xliff:g> యాప్ నుండి <xliff:g id="PROFILE_0">%1$s</xliff:g> ఫైల్స్ను యాక్సెస్ చేయడానికి మీ IT అడ్మిన్ మిమ్మల్ని అనుమతించరు"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"కార్యాలయ ప్రొఫైల్కి సేవ్ చేయడం సాధ్యం కాదు"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"మీ కార్యాలయ ప్రొఫైల్లో వ్యక్తిగత ఫైళ్లను సేవ్ చేయడానికి మీ IT అడ్మిన్ అనుమతించరు"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"వ్యక్తిగత ప్రొఫైల్లో సేవ్ చేయడం సాధ్యం కాదు"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"మీ వ్యక్తిగత ప్రొఫైల్లో కార్యాలయ ఫైళ్లను సేవ్ చేయడానికి మీ IT అడ్మిన్ అనుమతించరు"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> ప్రొఫైల్లో సేవ్ చేయడం సాధ్యం కాదు"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"మీ IT అడ్మిన్ మీ <xliff:g id="PROFILE_1">%2$s</xliff:g> ప్రొఫైల్లో <xliff:g id="PROFILE_0">%1$s</xliff:g> ఫైల్స్ను సేవ్ చేయడానికి మిమ్మల్ని అనుమతించరు"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"ఈ చర్య అనుమతించబడదు"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"మరింత తెలుసుకోవడానికి, మీ IT అడ్మిన్ను కాంటాక్ట్ చేయండి"</string> <string name="root_recent" msgid="1080156975424341623">"ఇటీవలివి"</string> @@ -168,7 +175,7 @@ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> అంశాన్ని తొలగించడం సాధ్యపడలేదు</item> </plurals> <string name="notification_touch_for_details" msgid="2385563502445129570">"వివరాలను చూడటానికి నొక్కండి"</string> - <string name="close" msgid="905969391788869975">"మూసివేయి"</string> + <string name="close" msgid="905969391788869975">"మూసివేయండి"</string> <plurals name="copy_failure_alert_content" formatted="false" msgid="5570549471912990536"> <item quantity="other">ఈ ఫైళ్లు కాపీ కాలేదు: <xliff:g id="LIST_1">%1$s</xliff:g></item> <item quantity="one">ఈ ఫైల్ కాపీ కాలేదు: <xliff:g id="LIST_0">%1$s</xliff:g></item> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"కొత్త పేరు"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g>ని ప్రివ్యూ చేయండి"</string> <string name="preview_work_file" msgid="4495643735563487273">"కార్యాలయ ఫైల్ <xliff:g id="FILENAME">%1$s</xliff:g>ని ప్రివ్యూ చేయండి"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> ఫైల్ <xliff:g id="FILENAME">%2$s</xliff:g>ను ప్రివ్యూ చేయండి"</string> <string name="apps_row_title" msgid="3340490016663092925">"ఇతర యాప్లలోని ఫైళ్లను బ్రౌజ్ చేయండి"</string> <string name="anonymous_application" msgid="7633027057951625862">"తెలియనిది"</string> <string name="open_tree_button" msgid="6402871398424497776">"ఈ ఫోల్డర్ను ఉపయోగించండి"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"ఈ ఫోల్డర్ను ఉపయోగించడం సాధ్యం కాదు"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"మీ గోప్యతను కాపాడుకోవటానికి, మరొక ఫోల్డర్ను ఎంచుకోండి"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"కొత్త ఫోల్డర్ని క్రియేట్ చేయండి"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"ఈ ఫోన్లో వెతకండి"</string> + <string name="search_bar_hint" msgid="146031513183888721">"ఈ పరికరాన్ని సెర్చ్ చేయండి"</string> <string name="delete_search_history" msgid="2202015025607694515">"సెర్చ్ హిస్టరీ <xliff:g id="TEXT">%1$s</xliff:g>ను తొలగించండి"</string> <string name="personal_tab" msgid="3878576287868528503">"వ్యక్తిగత డైరెక్టరీ"</string> <string name="work_tab" msgid="7265359366883747413">"కార్యాలయ డైరెక్టరీ"</string> diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml index a01e97016..7c917a2b0 100644 --- a/res/values-th/strings.xml +++ b/res/values-th/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"ย้ายไปที่…"</string> <string name="menu_compress" msgid="37539111904724188">"บีบอัด"</string> <string name="menu_extract" msgid="8171946945982532262">"แตกข้อมูลไปยัง…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"แตกเอกสารทั้งหมด…"</string> <string name="menu_rename" msgid="1883113442688817554">"เปลี่ยนชื่อ"</string> <string name="menu_inspect" msgid="7279855349299446224">"รับข้อมูล"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"แสดงไฟล์ที่ซ่อนไว้"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"โหลดเนื้อหาไม่ได้ในขณะนี้"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"แอปงานหยุดชั่วคราว"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"เปิดแอปงาน"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"แอป<xliff:g id="PROFILE">%1$s</xliff:g>หยุดชั่วคราวแล้ว"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"เปิดใช้แอป<xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"เลือกไฟล์งานไม่ได้"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"ผู้ดูแลระบบไอทีไม่อนุญาตให้เข้าถึงไฟล์งานจากแอปส่วนตัว"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"เลือกไฟล์ส่วนตัวไม่ได้"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"ผู้ดูแลระบบไอทีไม่อนุญาตให้เข้าถึงไฟล์ส่วนตัวจากแอปงาน"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"เลือกไฟล์<xliff:g id="PROFILE">%1$s</xliff:g>ไม่ได้"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"ผู้ดูแลระบบไอทีไม่อนุญาตให้คุณเข้าถึงไฟล์<xliff:g id="PROFILE_0">%1$s</xliff:g>จากแอป<xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"บันทึกในโปรไฟล์งานไม่ได้"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"ผู้ดูแลระบบไอทีไม่อนุญาตให้บันทึกไฟล์ส่วนตัวไว้ในโปรไฟล์งาน"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"บันทึกในโปรไฟล์ส่วนตัวไม่ได้"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"ผู้ดูแลระบบไอทีไม่อนุญาตให้บันทึกไฟล์งานไว้ในโปรไฟล์ส่วนตัว"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"บันทึกลงในโปรไฟล์<xliff:g id="PROFILE">%1$s</xliff:g>ไม่ได้"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"ผู้ดูแลระบบไอทีไม่อนุญาตให้คุณบันทึกไฟล์<xliff:g id="PROFILE_0">%1$s</xliff:g>ลงในโปรไฟล์<xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"ไม่อนุญาตการทำงานนี้"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"โปรดติดต่อผู้ดูแลระบบไอทีเพื่อสอบถามข้อมูลเพิ่มเติม"</string> <string name="root_recent" msgid="1080156975424341623">"ล่าสุด"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"ชื่อใหม่"</string> <string name="preview_file" msgid="4056622696305432343">"แสดงพรีวิวไฟล์ <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"แสดงตัวอย่างไฟล์งาน <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"แสดงตัวอย่างไฟล์<xliff:g id="PROFILE">%1$s</xliff:g>ชื่อ <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"เรียกดูไฟล์ในแอปอื่นๆ"</string> <string name="anonymous_application" msgid="7633027057951625862">"ไม่ระบุชื่อ"</string> <string name="open_tree_button" msgid="6402871398424497776">"ใช้โฟลเดอร์นี้"</string> @@ -274,9 +282,9 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"ใช้โฟลเดอร์นี้ไม่ได้"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"เลือกโฟลเดอร์อื่นเพื่อปกป้องความเป็นส่วนตัว"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"สร้างโฟลเดอร์ใหม่"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"ค้นหาในโทรศัพท์เครื่องนี้"</string> + <string name="search_bar_hint" msgid="146031513183888721">"ค้นหาอุปกรณ์นี้"</string> <string name="delete_search_history" msgid="2202015025607694515">"ลบประวัติการค้นหา <xliff:g id="TEXT">%1$s</xliff:g>"</string> - <string name="personal_tab" msgid="3878576287868528503">"ส่วนตัว"</string> + <string name="personal_tab" msgid="3878576287868528503">"ส่วนบุคคล"</string> <string name="work_tab" msgid="7265359366883747413">"งาน"</string> <string name="a11y_work" msgid="7504431382825242153">"งาน"</string> <string name="drag_from_another_app" msgid="8310249276199969905">"คุณย้ายไฟล์จากแอปอื่นไม่ได้"</string> diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml index 3778d1027..f4c397dda 100644 --- a/res/values-tl/strings.xml +++ b/res/values-tl/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Ilipat sa…"</string> <string name="menu_compress" msgid="37539111904724188">"I-compress"</string> <string name="menu_extract" msgid="8171946945982532262">"I-extract sa…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"I-extract lahat…"</string> <string name="menu_rename" msgid="1883113442688817554">"Palitan ang pangalan"</string> <string name="menu_inspect" msgid="7279855349299446224">"Kumuha ng impormasyon"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Ipakita ang hidden files"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Hindi ma-load ang content sa ngayon"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Naka-pause ang mga app para sa trabaho"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"I-on ang mga app para sa trabaho"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Naka-pause ang mga <xliff:g id="PROFILE">%1$s</xliff:g> app"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"I-on ang mga <xliff:g id="PROFILE">%1$s</xliff:g> app"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Hindi makapili ng mga file sa trabaho"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Hindi ka pinapayagan ng iyong IT admin na mag-access ng mga file sa trabaho mula sa personal na app"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Hindi makapili ng mga personal na file"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Hindi ka pinapayagan ng iyong IT admin na mag-access ng mga personal na file mula sa app para sa trabaho"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Hindi mapili ang mga file ng <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Hindi ka pinapayagan ng iyong IT admin na i-access ang mga file ng <xliff:g id="PROFILE_0">%1$s</xliff:g> mula sa isang <xliff:g id="PROFILE_1">%2$s</xliff:g> app"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Hindi ma-save sa profile sa trabaho"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Hindi ka pinapayagan ng iyong IT admin na mag-save ng mga personal na file sa profile mo sa trabaho"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Hindi ma-save sa personal na profile"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Hindi ka pinapayagan ng iyong IT admin na mag-save ng mga file sa trabaho sa personal na profile mo"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Hindi ma-save sa profile sa <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Hindi ka pinapayagan ng IT admin mo na i-save ang mga file ng <xliff:g id="PROFILE_0">%1$s</xliff:g> sa iyong profile sa <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Hindi pinapayagan ang pagkilos na ito"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Para matuto pa, makipag-ugnayan sa iyong IT admin"</string> <string name="root_recent" msgid="1080156975424341623">"Kamakailan"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Bagong pangalan"</string> <string name="preview_file" msgid="4056622696305432343">"I-preview ang file na <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"I-preview ang file sa trabaho na <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"I-preview ang file ng <xliff:g id="PROFILE">%1$s</xliff:g> na <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"I-browse ang mga file sa iba pang app"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonymous"</string> <string name="open_tree_button" msgid="6402871398424497776">"Gamitin ang folder na ito"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Hindi magagamit ang folder na ito"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Para maprotektahan ang iyong privacy, pumili ng ibang folder"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Gumawa ng bagong folder"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Maghanap sa teleponong ito"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Maghanap sa device na ito"</string> <string name="delete_search_history" msgid="2202015025607694515">"I-delete ang history ng paghahanap <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Personal"</string> <string name="work_tab" msgid="7265359366883747413">"Work"</string> diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index a1462f5fe..ea91bfdee 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Klasöre taşı..."</string> <string name="menu_compress" msgid="37539111904724188">"Sıkıştır"</string> <string name="menu_extract" msgid="8171946945982532262">"Şuraya çıkar:"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Tümünü çıkar…"</string> <string name="menu_rename" msgid="1883113442688817554">"Yeniden adlandır"</string> <string name="menu_inspect" msgid="7279855349299446224">"Bilgi al"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Gizli dosyaları göster"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"İçerik şu anda yüklenemiyor"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"İş uygulamaları duraklatıldı"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"İş uygulamalarını aç"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> uygulamaları duraklatıldı"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> uygulamalarını aç"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"İş dosyaları seçilemiyor"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"BT yöneticiniz kişisel bir uygulamadan iş dosyalarına erişmenize izin vermiyor"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Kişisel dosyalar seçilemiyor"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"BT yöneticiniz bir iş uygulamasından kişisel dosyalara erişmenize izin vermiyor"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> dosyalarınız seçilemiyor"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"BT yöneticiniz, <xliff:g id="PROFILE_1">%2$s</xliff:g> uygulamanızdan <xliff:g id="PROFILE_0">%1$s</xliff:g> dosyalarına erişmenize izin vermiyor"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"İş profiline kaydedilemiyor"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"BT yöneticiniz kişisel dosyaları iş profilinize kaydetmenize izin vermiyor"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Kişisel profile kaydedilemiyor"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"BT yöneticiniz iş dosyalarını kişisel profilinize kaydetmenize izin vermiyor"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> profilinize kaydedilemiyor"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"BT yöneticiniz, <xliff:g id="PROFILE_0">%1$s</xliff:g> dosyalarınızı <xliff:g id="PROFILE_1">%2$s</xliff:g> profilinize kaydetmenize izin vermiyor"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Bu işleme izin verilmiyor"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"BT yöneticinizden daha fazla bilgi alabilirsiniz."</string> <string name="root_recent" msgid="1080156975424341623">"Son"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Yeni ad"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g> dosyasını önizleyin"</string> <string name="preview_work_file" msgid="4495643735563487273">"<xliff:g id="FILENAME">%1$s</xliff:g> adlı iş dosyasını önizleyin"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> dosyasını (<xliff:g id="FILENAME">%2$s</xliff:g>) önizleyin"</string> <string name="apps_row_title" msgid="3340490016663092925">"Diğer uygulamalardaki dosyalara göz atın"</string> <string name="anonymous_application" msgid="7633027057951625862">"Adsız"</string> <string name="open_tree_button" msgid="6402871398424497776">"Bu klasörü kullan"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Bu klasör kullanılamıyor"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Gizliliğinizi korumak için başka bir klasör seçin"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Yeni klasör oluştur"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Bu telefonu arayın"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Bu cihazda arama yapın"</string> <string name="delete_search_history" msgid="2202015025607694515">"Arama geçmişini sil <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Kişisel"</string> <string name="work_tab" msgid="7265359366883747413">"İş"</string> diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index 30d8d7933..f36363d34 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Перемістити в…"</string> <string name="menu_compress" msgid="37539111904724188">"Стиснути"</string> <string name="menu_extract" msgid="8171946945982532262">"Розпакувати…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Розархівувати все…"</string> <string name="menu_rename" msgid="1883113442688817554">"Перейменувати"</string> <string name="menu_inspect" msgid="7279855349299446224">"Переглянути інформацію"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Показувати приховані файли"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Зараз не вдається завантажити вміст"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Робочі додатки призупинено"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Увімкнути робочі додатки"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Додатки профілю \"<xliff:g id="PROFILE">%1$s</xliff:g>\" призупинено"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Увімкнути додатки в профілі \"<xliff:g id="PROFILE">%1$s</xliff:g>\""</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Не вдається вибрати робочі файли"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Ваш ІТ-адміністратор не дозволяє отримувати доступ до робочих файлів з особистого додатка"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Не вдається вибрати особисті файли"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Ваш ІТ-адміністратор не дозволяє отримувати доступ до особистих файлів із робочого додатка"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Не вдається вибрати файли в профілі \"<xliff:g id="PROFILE">%1$s</xliff:g>\""</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Ваш адміністратор не дозволяє отримувати доступ до файлів профілю \"<xliff:g id="PROFILE_0">%1$s</xliff:g>\" із цього додатка (<xliff:g id="PROFILE_1">%2$s</xliff:g>)"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Не вдається зберегти в робочому профілі"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Ваш ІТ-адміністратор не дозволяє зберігати особисті файли в робочому профілі"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Не вдається зберегти в особистому профілі"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Ваш ІТ-адміністратор не дозволяє зберігати робочі файли в особистому профілі"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Не вдається зберегти файли в профілі \"<xliff:g id="PROFILE">%1$s</xliff:g>\""</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Ваш адміністратор не дозволяє зберігати файли з одного профілю (<xliff:g id="PROFILE_0">%1$s</xliff:g>) в іншому (<xliff:g id="PROFILE_1">%2$s</xliff:g>)"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Ця дія заборонена"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Щоб дізнатися більше, зверніться до ІТ-адміністратора"</string> <string name="root_recent" msgid="1080156975424341623">"Останні"</string> @@ -310,6 +317,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Нова назва"</string> <string name="preview_file" msgid="4056622696305432343">"Переглянути файл \"<xliff:g id="FILENAME">%1$s</xliff:g>\""</string> <string name="preview_work_file" msgid="4495643735563487273">"Попередній перегляд робочого файлу \"<xliff:g id="FILENAME">%1$s</xliff:g>\""</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Перегляньте файл <xliff:g id="FILENAME">%2$s</xliff:g> профілю \"<xliff:g id="PROFILE">%1$s</xliff:g>\""</string> <string name="apps_row_title" msgid="3340490016663092925">"Пошук файлів в інших додатках"</string> <string name="anonymous_application" msgid="7633027057951625862">"Анонімно"</string> <string name="open_tree_button" msgid="6402871398424497776">"Використовувати цю папку"</string> @@ -318,7 +326,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Не вдається вибрати цю папку"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Щоб захистити свою конфіденційність, виберіть іншу папку"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Створити папку"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Пошук на цьому телефоні"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Пошук на цьому пристрої"</string> <string name="delete_search_history" msgid="2202015025607694515">"Видалити історію пошуку (<xliff:g id="TEXT">%1$s</xliff:g>)"</string> <string name="personal_tab" msgid="3878576287868528503">"Особисте"</string> <string name="work_tab" msgid="7265359366883747413">"Робоче"</string> diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml index e2d3d1c14..6ef8b2787 100644 --- a/res/values-ur/strings.xml +++ b/res/values-ur/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"اس میں منتقل کریں…"</string> <string name="menu_compress" msgid="37539111904724188">"کمپریس کریں"</string> <string name="menu_extract" msgid="8171946945982532262">"اس میں کھولیں۔۔۔"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"سبھی نکالیں…"</string> <string name="menu_rename" msgid="1883113442688817554">"نام تبدیل کریں"</string> <string name="menu_inspect" msgid="7279855349299446224">"معلومات حاصل کریں"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"پوشیدہ فائلز دکھائیں"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"اس وقت مواد لوڈ نہیں ہو سکتا"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"ورک ایپس موقوف ہیں"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"ورک ایپس آن کریں"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> ایپس موقوف ہیں"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> ایپس آن کریں"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"دفتری فائلز منتخب نہیں کر سکتے"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"آپ کا IT منتظم آپ کو ذاتی ایپ سے دفتری فائلز تک رسائی حاصل کرنے کی اجازت نہیں دیتا ہے"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"ذاتی فائلز منتخب نہیں کر سکتے"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"آپ کا IT منتظم آپ کو دفتری ایپ سے ذاتی فائلز تک رسائی حاصل کرنے کی اجازت نہیں دیتا ہے"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> فائلز منتخب نہیں کر سکتے"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"آپ کا IT منتظم آپ کو <xliff:g id="PROFILE_1">%2$s</xliff:g> ایپ سے <xliff:g id="PROFILE_0">%1$s</xliff:g> فائلز تک رسائی کی اجازت نہیں دیتا ہے"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"دفتری پروفائل میں محفوظ نہیں کر سکتے"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"آپ کا IT منتظم آپ کو اپنی دفتری پروفائل میں ذاتی فائلز کو محفوظ کرنے کی اجازت نہیں دیتا ہے"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"ذاتی پروفائل میں محفوظ نہیں کر سکتے"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"آپ کا IT منتظم آپ کو اپنی ذاتی پروفائل میں دفتری فائلز کو محفوظ کرنے کی اجازت نہیں دیتا ہے"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> پروفائل میں محفوظ نہیں کیا جا سکتا"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"آپ کا IT منتظم آپ کو اپنی <xliff:g id="PROFILE_1">%2$s</xliff:g> پروفائل میں <xliff:g id="PROFILE_0">%1$s</xliff:g> فائلز محفوظ کرنے کی اجازت نہیں دیتا ہے"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"اس کارروائی کی اجازت نہیں ہے"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"مزید جاننے کے لیے، اپنے IT منتظم سے رابطہ کریں۔"</string> <string name="root_recent" msgid="1080156975424341623">"حالیہ"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"نیا نام"</string> <string name="preview_file" msgid="4056622696305432343">"فائل <xliff:g id="FILENAME">%1$s</xliff:g> کا پیش منظر"</string> <string name="preview_work_file" msgid="4495643735563487273">"دفتری فائل <xliff:g id="FILENAME">%1$s</xliff:g> کا پیش منظر"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> کی فائل <xliff:g id="FILENAME">%2$s</xliff:g> کا پیش منظر دکھائیں"</string> <string name="apps_row_title" msgid="3340490016663092925">"دیگر ایپس میں فائلز کو براؤز کریں"</string> <string name="anonymous_application" msgid="7633027057951625862">"گمنام"</string> <string name="open_tree_button" msgid="6402871398424497776">"اس فولڈر کو استعمال کریں"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"اس فولڈر کا استعمال نہیں کیا جا سکتا"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"اپنی رازداری کے تحفظ کے لیے کوئی دوسرا فولڈر منتخب کریں"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"نیا فولڈر بنائیں"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"اس فون میں تلاش کریں"</string> + <string name="search_bar_hint" msgid="146031513183888721">"اس آلے پر تلاش کریں"</string> <string name="delete_search_history" msgid="2202015025607694515">"تلاش کی سرگزشت کی <xliff:g id="TEXT">%1$s</xliff:g> حذف کریں"</string> <string name="personal_tab" msgid="3878576287868528503">"ذاتی"</string> <string name="work_tab" msgid="7265359366883747413">"دفتری"</string> diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml index dd005e20c..703119c70 100644 --- a/res/values-uz/strings.xml +++ b/res/values-uz/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Boshqa joyga olish…"</string> <string name="menu_compress" msgid="37539111904724188">"Arxivlash"</string> <string name="menu_extract" msgid="8171946945982532262">"Arxivdan chiqarish"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Barchasini ajratish…"</string> <string name="menu_rename" msgid="1883113442688817554">"Qayta nomlash"</string> <string name="menu_inspect" msgid="7279855349299446224">"Axborot olish"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Yashirin fayllarni chiqarish"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Ayni paytda kontentni yuklab bo‘lmayapti"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Ishga oid ilovalar pauza qilingan"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Ishga oid ilovalarni yoqish"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g> ilovalari pauzada"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"<xliff:g id="PROFILE">%1$s</xliff:g> ilovalarini yoqish"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Ishga oid fayllarni tanlash imkonsiz"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"AT administratoringiz shaxsiy ilovadan ishga oid fayllarga kirishni taqiqlagan"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Shaxsiy fayllar tanlanmadi"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"AT administratoringiz ishga oid ilovadan shaxsiy fayllarga kirishni taqiqlagan"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"<xliff:g id="PROFILE">%1$s</xliff:g> fayllari tanlanmadi"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"AT administratoringiz <xliff:g id="PROFILE_1">%2$s</xliff:g> ilovasidan <xliff:g id="PROFILE_0">%1$s</xliff:g> fayllariga kirishni taqiqlagan"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Ish profiliga saqlash imkonsiz"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"AT administratoringiz shaxsiy fayllarni ish profiliga saqlashni taqiqlagan"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Shaxsiy profilga saqlash imkonsiz"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"AT administratoringiz ishga oid fayllarni shaxsiy profilingizga saqlashni taqiqlagan"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"<xliff:g id="PROFILE">%1$s</xliff:g> profiliga saqlanmadi"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"AT administratoringiz <xliff:g id="PROFILE_1">%2$s</xliff:g> profiliga <xliff:g id="PROFILE_0">%1$s</xliff:g> fayllarini saqlashni taqiqlagan"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Bu amalga ruxsat berilmagan"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Batafsil axborot olish uchun AT administratoringizga murojaat qiling"</string> <string name="root_recent" msgid="1080156975424341623">"Yaqinda"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Yangi nom"</string> <string name="preview_file" msgid="4056622696305432343">"<xliff:g id="FILENAME">%1$s</xliff:g> fayliga nazar solish"</string> <string name="preview_work_file" msgid="4495643735563487273">"<xliff:g id="FILENAME">%1$s</xliff:g> ish fayliga nazar solish"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"<xliff:g id="PROFILE">%1$s</xliff:g> <xliff:g id="FILENAME">%2$s</xliff:g> fayliga nazar solish"</string> <string name="apps_row_title" msgid="3340490016663092925">"Boshqa ilovalardagi fayllarni topish"</string> <string name="anonymous_application" msgid="7633027057951625862">"Anonim"</string> <string name="open_tree_button" msgid="6402871398424497776">"Bu jilddan foydalanish"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Bu jilddan foydalanish imkonsiz"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Maxfiyligingizni muhofaza qilish uchun boshqa jildni tanlang"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Yangi jild yaratish"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Shu telefondan qidirish"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Shu qurilmadan qidirish"</string> <string name="delete_search_history" msgid="2202015025607694515">"Qidiruv tarixini tozalash (<xliff:g id="TEXT">%1$s</xliff:g>)"</string> <string name="personal_tab" msgid="3878576287868528503">"Shaxsiy"</string> <string name="work_tab" msgid="7265359366883747413">"Ish"</string> diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index b52f20aef..f063ad569 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -45,10 +45,11 @@ <string name="menu_move" msgid="2310760789561129882">"Chuyển tới..."</string> <string name="menu_compress" msgid="37539111904724188">"Nén"</string> <string name="menu_extract" msgid="8171946945982532262">"Trích xuất sang…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Trích xuất tất cả…"</string> <string name="menu_rename" msgid="1883113442688817554">"Đổi tên"</string> <string name="menu_inspect" msgid="7279855349299446224">"Xem thông tin"</string> - <string name="menu_show_hidden_files" msgid="5140676344684492769">"Hiển thị các tệp đã ẩn"</string> - <string name="menu_hide_hidden_files" msgid="5654495713350153702">"Không hiển thị các tệp đã ẩn"</string> + <string name="menu_show_hidden_files" msgid="5140676344684492769">"Hiện các tệp bị ẩn"</string> + <string name="menu_hide_hidden_files" msgid="5654495713350153702">"Không hiện các tệp bị ẩn"</string> <string name="menu_view_in_owner" msgid="7228948660557554770">"Xem trong <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="menu_new_window" msgid="2947837751796109126">"Cửa sổ mới"</string> <string name="menu_cut_to_clipboard" msgid="2878752142015026229">"Cắt"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Không thể tải nội dung vào lúc này"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Ứng dụng công việc đã tạm dừng"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Bật ứng dụng công việc"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Các ứng dụng <xliff:g id="PROFILE">%1$s</xliff:g> đang bị tạm dừng"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Bật các ứng dụng <xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Không thể chọn các tệp công việc"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Quản trị viên CNTT không cho phép bạn truy cập vào tệp công việc từ ứng dụng cá nhân"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Không thể chọn các tệp cá nhân"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Quản trị viên CNTT không cho phép bạn truy cập vào tệp cá nhân từ ứng dụng công việc"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Không chọn được tệp <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Quản trị viên CNTT của bạn không cho phép bạn truy cập tệp <xliff:g id="PROFILE_0">%1$s</xliff:g> từ ứng dụng <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Không thể lưu vào hồ sơ công việc"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Quản trị viên CNTT không cho phép bạn lưu tệp cá nhân vào hồ sơ công việc của bạn"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Không thể lưu vào hồ sơ cá nhân"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Quản trị viên CNTT không cho phép bạn lưu tệp công việc vào hồ sơ cá nhân của bạn"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Không lưu được vào hồ sơ <xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Quản trị viên CNTT của bạn không cho phép bạn lưu tệp <xliff:g id="PROFILE_0">%1$s</xliff:g> vào hồ sơ <xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Quản trị viên CNTT không cho phép thực hiện thao tác này"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Hãy liên hệ với quản trị viên CNTT để tìm hiểu thêm"</string> <string name="root_recent" msgid="1080156975424341623">"Gần đây"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Tên mới"</string> <string name="preview_file" msgid="4056622696305432343">"Xem trước tệp <xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Xem trước tệp công việc <xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Xem trước tệp <xliff:g id="PROFILE">%1$s</xliff:g> <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Duyệt qua tệp trong các ứng dụng khác"</string> <string name="anonymous_application" msgid="7633027057951625862">"Ẩn danh"</string> <string name="open_tree_button" msgid="6402871398424497776">"Sử dụng thư mục này"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Không thể dùng thư mục này"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Để bảo vệ quyền riêng tư của bạn, hãy chọn một thư mục khác"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Tạo thư mục mới"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Tìm kiếm trên điện thoại này"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Tìm kiếm trên thiết bị này"</string> <string name="delete_search_history" msgid="2202015025607694515">"Xoá nhật ký tìm kiếm <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Cá nhân"</string> <string name="work_tab" msgid="7265359366883747413">"Công việc"</string> diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 1167256e9..402cb66f8 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"移至…"</string> <string name="menu_compress" msgid="37539111904724188">"压缩"</string> <string name="menu_extract" msgid="8171946945982532262">"解压到…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"提取全部…"</string> <string name="menu_rename" msgid="1883113442688817554">"重命名"</string> <string name="menu_inspect" msgid="7279855349299446224">"获取信息"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"显示隐藏的文件"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"暂时无法加载内容"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"工作应用已暂停"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"开启工作应用"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g>应用已暂停"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"启用<xliff:g id="PROFILE">%1$s</xliff:g>应用"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"无法选择工作文件"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"您的 IT 管理员不允许您通过个人应用访问工作文件"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"无法选择个人文件"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"您的 IT 管理员不允许您通过工作应用访问个人文件"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"无法选择<xliff:g id="PROFILE">%1$s</xliff:g>文件"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"您的 IT 管理员不允许从<xliff:g id="PROFILE_1">%2$s</xliff:g>应用访问<xliff:g id="PROFILE_0">%1$s</xliff:g>文件"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"无法保存到工作资料"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"您的 IT 管理员不允许您将个人文件保存到工作资料"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"无法保存到个人资料"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"您的 IT 管理员不允许您将工作文件保存到个人资料"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"无法保存到<xliff:g id="PROFILE">%1$s</xliff:g>个人资料"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"您的 IT 管理员不允许将<xliff:g id="PROFILE_0">%1$s</xliff:g>文件保存到<xliff:g id="PROFILE_1">%2$s</xliff:g>个人资料"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"不允许执行该操作"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"如需了解详情,请与您的 IT 管理员联系"</string> <string name="root_recent" msgid="1080156975424341623">"最近"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"新名称"</string> <string name="preview_file" msgid="4056622696305432343">"预览“<xliff:g id="FILENAME">%1$s</xliff:g>”文件"</string> <string name="preview_work_file" msgid="4495643735563487273">"预览工作文件“<xliff:g id="FILENAME">%1$s</xliff:g>”"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"预览<xliff:g id="PROFILE">%1$s</xliff:g>文件“<xliff:g id="FILENAME">%2$s</xliff:g>”"</string> <string name="apps_row_title" msgid="3340490016663092925">"浏览其他应用中的文件"</string> <string name="anonymous_application" msgid="7633027057951625862">"匿名"</string> <string name="open_tree_button" msgid="6402871398424497776">"使用此文件夹"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"无法使用此文件夹"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"为保护您的隐私,请选择其他文件夹"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"新建文件夹"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"在此手机内搜索"</string> + <string name="search_bar_hint" msgid="146031513183888721">"在此设备上搜索"</string> <string name="delete_search_history" msgid="2202015025607694515">"删除搜索记录“<xliff:g id="TEXT">%1$s</xliff:g>”"</string> <string name="personal_tab" msgid="3878576287868528503">"个人"</string> <string name="work_tab" msgid="7265359366883747413">"工作"</string> diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml index 7cd2401dd..d69e372fd 100644 --- a/res/values-zh-rHK/strings.xml +++ b/res/values-zh-rHK/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"移至…"</string> <string name="menu_compress" msgid="37539111904724188">"壓縮"</string> <string name="menu_extract" msgid="8171946945982532262">"壓縮至…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"擷取全部…"</string> <string name="menu_rename" msgid="1883113442688817554">"重新命名"</string> <string name="menu_inspect" msgid="7279855349299446224">"顯示資訊"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"顯示已隱藏的檔案"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"目前無法載入內容"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"已暫停工作應用程式"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"開啟工作應用程式"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"已暫停<xliff:g id="PROFILE">%1$s</xliff:g>應用程式"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"開啟<xliff:g id="PROFILE">%1$s</xliff:g>應用程式"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"無法選取工作檔案"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"IT 管理員不允許你透過個人應用程式存取工作檔案"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"無法選取個人檔案"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"IT 管理員不允許你透過工作應用程式存取個人檔案"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"無法選取<xliff:g id="PROFILE">%1$s</xliff:g>檔案"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"IT 管理員不允許你使用<xliff:g id="PROFILE_1">%2$s</xliff:g>應用程式存取<xliff:g id="PROFILE_0">%1$s</xliff:g>檔案"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"無法儲存至工作設定檔"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"IT 管理員不允許你將個人檔案儲存至工作設定檔"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"無法儲存至個人設定檔"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"IT 管理員不允許你將工作檔案儲存至個人設定檔"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"無法儲存至<xliff:g id="PROFILE">%1$s</xliff:g>設定檔"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"IT 管理員不允許你將<xliff:g id="PROFILE_0">%1$s</xliff:g>檔案儲存至<xliff:g id="PROFILE_1">%2$s</xliff:g>設定檔"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"不允許執行這項操作"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"詳情請聯絡 IT 管理員。"</string> <string name="root_recent" msgid="1080156975424341623">"最近項目"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"新名稱"</string> <string name="preview_file" msgid="4056622696305432343">"預覽 <xliff:g id="FILENAME">%1$s</xliff:g> 檔案"</string> <string name="preview_work_file" msgid="4495643735563487273">"預覽工作檔案「<xliff:g id="FILENAME">%1$s</xliff:g>」"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"預覽<xliff:g id="PROFILE">%1$s</xliff:g>檔案 <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"瀏覽其他應用程式中的檔案"</string> <string name="anonymous_application" msgid="7633027057951625862">"匿名"</string> <string name="open_tree_button" msgid="6402871398424497776">"使用此資料夾"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"無法使用此資料夾"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"為保護你的私隱,請選擇其他資料夾"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"建立新資料夾"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"在這部手機中搜尋"</string> + <string name="search_bar_hint" msgid="146031513183888721">"搜尋此裝置"</string> <string name="delete_search_history" msgid="2202015025607694515">"刪除搜尋記錄 <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"個人"</string> <string name="work_tab" msgid="7265359366883747413">"工作"</string> diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index 892a75b17..28318cc89 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"移至…"</string> <string name="menu_compress" msgid="37539111904724188">"壓縮"</string> <string name="menu_extract" msgid="8171946945982532262">"解壓縮到…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"全部解壓縮…"</string> <string name="menu_rename" msgid="1883113442688817554">"重新命名"</string> <string name="menu_inspect" msgid="7279855349299446224">"取得資訊"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"顯示隱藏的檔案"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"目前無法載入內容"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"系統已暫停工作應用程式"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"開啟工作應用程式"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"<xliff:g id="PROFILE">%1$s</xliff:g>應用程式已暫停"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"開啟<xliff:g id="PROFILE">%1$s</xliff:g>應用程式"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"無法選取工作檔案"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"你的 IT 管理員不允許你透過個人應用程式存取工作檔案"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"無法選取個人檔案"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"你的 IT 管理員不允許你透過工作應用程式存取個人檔案"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"無法選取<xliff:g id="PROFILE">%1$s</xliff:g>的檔案"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"IT 管理員不允許你使用<xliff:g id="PROFILE_1">%2$s</xliff:g>應用程式存取<xliff:g id="PROFILE_0">%1$s</xliff:g>檔案"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"無法儲存到工作資料夾"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"你的 IT 管理員不允許你將個人檔案儲存到工作資料夾"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"無法儲存到個人資料夾"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"你的 IT 管理員不允許你將工作檔案儲存到個人資料夾"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"無法儲存到<xliff:g id="PROFILE">%1$s</xliff:g>資料夾"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"IT 管理員不允許你將<xliff:g id="PROFILE_0">%1$s</xliff:g>檔案儲存到<xliff:g id="PROFILE_1">%2$s</xliff:g>資料夾"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"不允許執行這項動作"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"如要瞭解詳情,請與你的 IT 管理員聯絡"</string> <string name="root_recent" msgid="1080156975424341623">"最近"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"新名稱"</string> <string name="preview_file" msgid="4056622696305432343">"預覽 <xliff:g id="FILENAME">%1$s</xliff:g> 檔案"</string> <string name="preview_work_file" msgid="4495643735563487273">"預覽工作檔案「<xliff:g id="FILENAME">%1$s</xliff:g>」"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"預覽<xliff:g id="PROFILE">%1$s</xliff:g>檔案 <xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"瀏覽其他應用程式中的檔案"</string> <string name="anonymous_application" msgid="7633027057951625862">"匿名"</string> <string name="open_tree_button" msgid="6402871398424497776">"使用這個資料夾"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"無法使用這個資料夾"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"為保護你的隱私,請選擇其他資料夾"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"建立新資料夾"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"在手機內搜尋"</string> + <string name="search_bar_hint" msgid="146031513183888721">"搜尋這部裝置"</string> <string name="delete_search_history" msgid="2202015025607694515">"刪除搜尋記錄 <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"個人"</string> <string name="work_tab" msgid="7265359366883747413">"工作"</string> diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml index 3015e209b..1b85d7f00 100644 --- a/res/values-zu/strings.xml +++ b/res/values-zu/strings.xml @@ -45,6 +45,7 @@ <string name="menu_move" msgid="2310760789561129882">"Hambisa ku…"</string> <string name="menu_compress" msgid="37539111904724188">"Cindezela"</string> <string name="menu_extract" msgid="8171946945982532262">"Khiphela ku…"</string> + <string name="menu_extract_all" msgid="7335680068521252718">"Khipha konke…"</string> <string name="menu_rename" msgid="1883113442688817554">"Qamba kabusha"</string> <string name="menu_inspect" msgid="7279855349299446224">"Thola ulwazi"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Bonisa amafayela afihliwe"</string> @@ -94,14 +95,20 @@ <string name="query_error" msgid="6625421453613879336">"Ayikwazanga ukulayisha okuqukethwe okwamanje"</string> <string name="quiet_mode_error_title" msgid="554319751414657910">"Ama-app omsebenzi amisiwe"</string> <string name="quiet_mode_button" msgid="8051436551926677305">"Vula ama-app omsebenzi"</string> + <string name="profile_quiet_mode_error_title" msgid="7126962749634841843">"Ama-app e-<xliff:g id="PROFILE">%1$s</xliff:g> amisiwe"</string> + <string name="profile_quiet_mode_button" msgid="6791235010992920102">"Vula ama-app we-<xliff:g id="PROFILE">%1$s</xliff:g>"</string> <string name="cant_select_work_files_error_title" msgid="6688716319549644354">"Ayikwazi ukukhetha amafayela omsebenzi"</string> <string name="cant_select_work_files_error_message" msgid="683480676150690641">"Umphathi wakho we-IT akakuvumeli ukuba ufinyelele amafayela omsebenzi avela kuhlelo lokusebenza lomuntu siqu"</string> <string name="cant_select_personal_files_error_title" msgid="3200697170148617742">"Ayikwazi ukukhetha amafayela akho siqu"</string> <string name="cant_select_personal_files_error_message" msgid="4105905035459118209">"Umphathi wakho we-IT akakuvumeli ukuba ufinyelele amafayela akho siqu avela ohlelweni lokusebenza lomsebenzi"</string> + <string name="cant_select_cross_profile_files_error_title" msgid="17010948874969413">"Ayikwazi ukukhetha amafayela we-<xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_select_cross_profile_files_error_message" msgid="3815829574883844944">"Umphathi wakho we-IT akakuvumeli ukuthi ufinyelele amafayela we-<xliff:g id="PROFILE_0">%1$s</xliff:g> usebenzisa i-app ye-<xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cant_save_to_work_error_title" msgid="1351323070040641358">"Ayikwazi ukulondoloza kuphrofayela lomsebenzi"</string> <string name="cant_save_to_work_error_message" msgid="4975583233814059890">"Umphathi wakho we-IT akakuvumeli ukuba ulondoloze amafayela akho siqu kwiphrofayela lakho lomsebenzi"</string> <string name="cant_save_to_personal_error_title" msgid="858327493694069780">"Ayikwazi ukulondoloza kuphrofayela lakho siqu"</string> <string name="cant_save_to_personal_error_message" msgid="6991758723736381751">"Umphathi wakho we-IT akakuvumeli ukuba ulondoloze amafayela akho omsebenzi kwiphrofayela lakho"</string> + <string name="cant_save_to_cross_profile_error_title" msgid="5158984057654779022">"Ayikwazi ukulondoloza kuphrofayela ye-<xliff:g id="PROFILE">%1$s</xliff:g>"</string> + <string name="cant_save_to_cross_profile_error_message" msgid="5845240315510422749">"Umphathi wakho we-IT akakuvumeli ukuthi ulondoloze amafayela we-<xliff:g id="PROFILE_0">%1$s</xliff:g> kuphrofayela yakho ye-<xliff:g id="PROFILE_1">%2$s</xliff:g>"</string> <string name="cross_profile_action_not_allowed_title" msgid="6611281348716476478">"Lesi senzo asivunyelwe"</string> <string name="cross_profile_action_not_allowed_message" msgid="7331275433061690947">"Ukuze ufunde kabanzi, xhumana nomphathi wakho we-IT"</string> <string name="root_recent" msgid="1080156975424341623">"Okwakamuva"</string> @@ -266,6 +273,7 @@ <string name="input_hint_rename" msgid="8390711744270994452">"Igama elisha"</string> <string name="preview_file" msgid="4056622696305432343">"Buka kuqala ifayela le-<xliff:g id="FILENAME">%1$s</xliff:g>"</string> <string name="preview_work_file" msgid="4495643735563487273">"Hlola kuqala ifayela lomsebenzi i-<xliff:g id="FILENAME">%1$s</xliff:g>"</string> + <string name="preview_cross_profile_file" msgid="7457849216193029610">"Buka kuqala i-<xliff:g id="PROFILE">%1$s</xliff:g> yefayela le-<xliff:g id="FILENAME">%2$s</xliff:g>"</string> <string name="apps_row_title" msgid="3340490016663092925">"Phequlula amafayela kwezinye izinhlelo zokusebenza"</string> <string name="anonymous_application" msgid="7633027057951625862">"Okungaziwa"</string> <string name="open_tree_button" msgid="6402871398424497776">"Sebenzisa le folda"</string> @@ -274,7 +282,7 @@ <string name="directory_blocked_header_title" msgid="1164584889578740066">"Awukwazi ukusebenzisa le folda"</string> <string name="directory_blocked_header_subtitle" msgid="2829150911849033408">"Ukuvikela ubumfihlo bakho, khetha enye ifolda"</string> <string name="create_new_folder_button" msgid="8859613309559794890">"Dala ifolda entsha"</string> - <string name="search_bar_hint" msgid="4517366509897977321">"Sesha le foni"</string> + <string name="search_bar_hint" msgid="146031513183888721">"Sesha le divayisi"</string> <string name="delete_search_history" msgid="2202015025607694515">"Susa umlando wokusesha <xliff:g id="TEXT">%1$s</xliff:g>"</string> <string name="personal_tab" msgid="3878576287868528503">"Okomuntu siqu"</string> <string name="work_tab" msgid="7265359366883747413">"Umsebenzi"</string> diff --git a/res/values/strings.xml b/res/values/strings.xml index a1d6982fd..5f78c93e7 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -78,6 +78,8 @@ <string name="menu_compress">Compress</string> <!-- Menu item title that extracts the selected documents [CHAR LIMIT=28] --> <string name="menu_extract">Extract to\u2026</string> + <!-- Menu item title that extracts all the documents in the current directory [CHAR LIMIT=28] --> + <string name="menu_extract_all">Extract all\u2026</string> <!-- Menu item that renames the selected document [CHAR LIMIT=28] --> <string name="menu_rename">Rename</string> <!-- Menu item that displays properties about the selected document [CHAR LIMIT=28] --> @@ -189,6 +191,15 @@ <!-- Button text shown on a button when work profile is paused. Tapping the button will switch on the work profile [CHAR LIMIT=48] --> <string name="quiet_mode_button">Turn on work apps</string> + <!-- Title of an error message. This screen is shown when the selected profile is paused. [CHAR LIMIT=72] --> + <string name="profile_quiet_mode_error_title"> + <xliff:g id="profile" example="Work">%1$s</xliff:g> apps are paused + </string> + <!-- Button text shown on a button when selected profile is paused. Tapping the button will switch on the selected profile [CHAR LIMIT=48] --> + <string name="profile_quiet_mode_button"> + Turn on <xliff:g id="profile" example="work">%1$s</xliff:g> apps + </string> + <!-- Error message title shown when a user's IT admin does not allow the user to select work files from a personal app. [CHAR LIMIT=72] --> <string name="cant_select_work_files_error_title">Can\u2019t select work files</string> <!-- Error message that's shown when the user's IT admin doesn't allow the user to select work files from a personal app. [CHAR LIMIT=200] --> @@ -203,6 +214,16 @@ access personal files from a work app </string> + <!-- Error message title shown when a user's cross profile setting does not allow the user to select one profile's files from another profile app. [CHAR LIMIT=72] --> + <string name="cant_select_cross_profile_files_error_title">Can\u2019t select + <xliff:g id="profile" example="work">%1$s</xliff:g> files + </string> + <!-- Error message that's shown when the user's cross profile setting doesn't allow the user to select one profile's files from another profile app. [CHAR LIMIT=200] --> + <string name="cant_select_cross_profile_files_error_message">Your IT admin doesn\u2019t allow + you to access <xliff:g id="profile" example="work">%1$s</xliff:g> files from a + <xliff:g id="profile" example="personal">%2$s</xliff:g> app + </string> + <!-- Error message title shown when the admin does not allow the user to save files from their personal profile to their work profile. [CHAR LIMIT=72] --> <string name="cant_save_to_work_error_title">Can\u2019t save to work profile</string> <!-- Error message shown when the user's IT admin doesn't allow the user to save files from their personal profile to their work profile. [CHAR LIMIT=200] --> @@ -217,6 +238,16 @@ work files to your personal profile </string> + <!-- Error message title shown when the user's cross profile setting does not allow the user to save files from one profile to another profile. [CHAR LIMIT=72] --> + <string name="cant_save_to_cross_profile_error_title">Can\u2019t save to + <xliff:g id="profile" example="work">%1$s</xliff:g> profile + </string> + <!-- Error message shown when the user's cross profile setting doesn't allow the user to save files from one profile to another profile. [CHAR LIMIT=200] --> + <string name="cant_save_to_cross_profile_error_message">Your IT admin doesn\u2019t allow you to + save <xliff:g id="profile" example="personal">%1$s</xliff:g> files to your + <xliff:g id="profile" example="work">%2$s</xliff:g> profile + </string> + <!-- Error message title. This message is shown when a user tries to do something on their work device, but that action isn't allowed by their IT admin. [CHAR LIMIT=72] --> <string name="cross_profile_action_not_allowed_title">This action isn\u2019t allowed</string> <!-- Error message. This message is shown when a user tries to do something on their work device, but that action isn't allowed by their IT admin. [CHAR LIMIT=200] --> @@ -509,6 +540,8 @@ <string name="preview_file">Preview the file <xliff:g id="fileName" example="example.jpg">%1$s</xliff:g></string> <!-- Content description text that's spoken by a screen reader. This text is for previewing a work file before opening it. --> <string name="preview_work_file">Preview the work file <xliff:g id="fileName" example="example.jpg">%1$s</xliff:g></string> + <!-- Content description text that's spoken by a screen reader. This text is for previewing a private file before opening it. --> + <string name="preview_cross_profile_file">Preview the <xliff:g id="profile" example="work">%1$s</xliff:g> file <xliff:g id="fileName" example="example.jpg">%2$s</xliff:g></string> <!-- Apps row title. [CHAR_LIMIT=60] --> <string name="apps_row_title">Browse files in other apps</string> @@ -530,7 +563,7 @@ <!-- Search hint on search view. [CHAR LIMIT=48] --> - <string name="search_bar_hint">Search this phone</string> + <string name="search_bar_hint">Search this device</string> <!-- Content description for deleting search history. [CHAR_LIMIT=60] --> <string name="delete_search_history">Delete search history <xliff:g id="text" example="image">%1$s</xliff:g></string> diff --git a/src/com/android/documentsui/AbstractActionHandler.java b/src/com/android/documentsui/AbstractActionHandler.java index 4407a62b2..9b4d50b36 100644 --- a/src/com/android/documentsui/AbstractActionHandler.java +++ b/src/com/android/documentsui/AbstractActionHandler.java @@ -19,6 +19,8 @@ package com.android.documentsui; import static com.android.documentsui.base.DocumentInfo.getCursorInt; import static com.android.documentsui.base.DocumentInfo.getCursorString; import static com.android.documentsui.base.SharedMinimal.DEBUG; +import static com.android.documentsui.flags.Flags.desktopFileHandling; +import static com.android.documentsui.flags.Flags.useSearchV2; import android.app.PendingIntent; import android.content.ActivityNotFoundException; @@ -37,6 +39,7 @@ import android.util.Log; import android.util.Pair; import android.view.DragEvent; +import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.FragmentActivity; import androidx.loader.app.LoaderManager.LoaderCallbacks; @@ -62,6 +65,9 @@ import com.android.documentsui.dirlist.AnimationView.AnimationType; import com.android.documentsui.dirlist.FocusHandler; import com.android.documentsui.files.LauncherActivity; import com.android.documentsui.files.QuickViewIntentBuilder; +import com.android.documentsui.loaders.FolderLoader; +import com.android.documentsui.loaders.QueryOptions; +import com.android.documentsui.loaders.SearchLoader; import com.android.documentsui.queries.SearchViewManager; import com.android.documentsui.roots.GetRootDocumentTask; import com.android.documentsui.roots.LoadFirstRootTask; @@ -72,10 +78,14 @@ import com.android.documentsui.sorting.SortListFragment; import com.android.documentsui.ui.DialogController; import com.android.documentsui.ui.Snackbars; +import java.time.Duration; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import java.util.function.Consumer; @@ -119,6 +129,7 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA public void registerDisplayStateChangedListener(Runnable l) { mDisplayStateChangedListener = l; } + @Override public void unregisterDisplayStateChangedListener(Runnable l) { if (mDisplayStateChangedListener == l) { @@ -135,12 +146,12 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA Lookup<String, Executor> executors, Injector<?> injector) { - assert(activity != null); - assert(state != null); - assert(providers != null); - assert(searchMgr != null); - assert(docs != null); - assert(injector != null); + assert (activity != null); + assert (state != null); + assert (providers != null); + assert (searchMgr != null); + assert (docs != null); + assert (injector != null); mActivity = activity; mState = state; @@ -250,7 +261,12 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA } @Override - public void showInspector(DocumentInfo doc) { + public void openDocumentViewOnly(DocumentInfo doc) { + throw new UnsupportedOperationException("Open doc not supported!"); + } + + @Override + public void showPreview(DocumentInfo doc) { throw new UnsupportedOperationException("Can't open properties."); } @@ -359,7 +375,7 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA @Override public void openContainerDocument(DocumentInfo doc) { - assert(doc.isContainer()); + assert (doc.isContainer()); if (mSearchMgr.isSearching()) { loadDocument( @@ -372,6 +388,7 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA } // TODO: Make this private and make tests call interface method instead. + /** * Behavior when a document is opened. */ @@ -558,6 +575,15 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA if (doc.isWriteSupported()) { flags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION; } + // On desktop users expect files to open in a new window. + if (desktopFileHandling()) { + // The combination of NEW_DOCUMENT and MULTIPLE_TASK allows multiple instances of the + // same activity to open in separate windows. + flags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK; + // If the activity has documentLaunchMode="never", NEW_TASK forces the activity to still + // open in a new window. + flags |= Intent.FLAG_ACTIVITY_NEW_TASK; + } intent.setFlags(flags); return intent; @@ -620,7 +646,7 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA currentDoc = mDocs.getArchiveDocument(doc.derivedUri, doc.userId); } - assert(currentDoc != null); + assert (currentDoc != null); if (currentDoc.equals(mState.stack.peek())) { Log.w(TAG, "This DocumentInfo is already in current DocumentsStack"); return; @@ -676,8 +702,8 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA ComponentName component = new ComponentName( mActivity.getPackageName(), Shared.LAUNCHER_TARGET_CLASS); pm.setComponentEnabledSetting(component, enalbled - ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED - : PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED + : PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); } } @@ -714,7 +740,7 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA mDocs, userId, callback - ).executeOnExecutor(mExecutors.lookup(uri.getAuthority()), uri); + ).executeOnExecutor(mExecutors.lookup(uri.getAuthority()), uri); } @Override @@ -826,8 +852,8 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA private void onRootLoaded(@Nullable RootInfo root) { boolean invalidRootForAction = (root != null - && !root.supportsChildren() - && mState.action == State.ACTION_OPEN_TREE); + && !root.supportsChildren() + && mState.action == State.ACTION_OPEN_TREE); if (invalidRootForAction) { loadDeviceRoot(); @@ -877,8 +903,26 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA private final class LoaderBindings implements LoaderCallbacks<DirectoryResult> { + private ExecutorService mExecutorService = null; + private static final long MAX_SEARCH_TIME_MS = 3000; + private static final int MAX_RESULTS = 500; + + @NonNull @Override public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) { + // If document stack is not initialized, i.e. if the root is null, create "Recents" root + // with the selected user. + if (!mState.stack.isInitialized()) { + mState.stack.changeRoot(mActivity.getCurrentRoot()); + } + + if (useSearchV2()) { + return onCreateLoaderV2(id, args); + } + return onCreateLoaderV1(id, args); + } + + private Loader<DirectoryResult> onCreateLoaderV1(int id, Bundle args) { Context context = mActivity; if (mState.stack.isRecents()) { @@ -942,8 +986,8 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA if (DEBUG) { Log.d(TAG, - "Creating new directory loader for: " - + DocumentInfo.debugString(mState.stack.peek())); + "Creating new directory loader for: " + + DocumentInfo.debugString(mState.stack.peek())); } return new DirectoryLoader( @@ -957,13 +1001,76 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA } } + private Loader<DirectoryResult> onCreateLoaderV2(int id, Bundle args) { + if (mExecutorService == null) { + // TODO(b:388130971): Fine tune the size of the thread pool. + mExecutorService = Executors.newFixedThreadPool( + GlobalSearchLoader.MAX_OUTSTANDING_TASK); + } + DocumentStack stack = mState.stack; + RootInfo root = stack.getRoot(); + List<UserId> userIdList = DocumentsApplication.getUserIdManager(mActivity).getUserIds(); + + Duration lastModifiedDelta = stack.isRecents() + ? Duration.ofMillis(RecentsLoader.REJECT_OLDER_THAN) + : null; + int maxResults = (root == null || root.isRecents()) + ? RecentsLoader.MAX_DOCS_FROM_ROOT : MAX_RESULTS; + QueryOptions options = new QueryOptions( + maxResults, lastModifiedDelta, Duration.ofMillis(MAX_SEARCH_TIME_MS), + mState.showHiddenFiles, mState.acceptMimes); + + if (stack.isRecents() || mSearchMgr.isSearching()) { + Log.d(TAG, "Creating search loader V2"); + // For search and recent we create an observer that restart the loader every time + // one of the searched content providers reports a change. + final LockingContentObserver observer = new LockingContentObserver( + mContentLock, AbstractActionHandler.this::loadDocumentsForCurrentStack); + Collection<RootInfo> rootList = new ArrayList<>(); + if (root == null || root.isRecents()) { + // TODO(b:381346575): Pass roots based on user selection. + rootList.addAll(mProviders.getMatchingRootsBlocking(mState).stream().filter( + r -> r.supportsSearch() && r.authority != null + && r.rootId != null).toList()); + } else { + rootList.add(root); + } + return new SearchLoader( + mActivity, + userIdList, + mInjector.fileTypeLookup, + observer, + rootList, + mSearchMgr.getCurrentSearch(), + options, + mState.sortModel, + mExecutorService + ); + } + Log.d(TAG, "Creating folder loader V2"); + // For folder scan we pass the content lock to the loader so that it can register + // an a callback to its internal method that forces a reload of the folder, every + // time the content provider reports a change. + return new FolderLoader( + mActivity, + userIdList, + mInjector.fileTypeLookup, + mContentLock, + root, + stack.peek(), + options, + mState.sortModel + ); + + } + @Override public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) { if (DEBUG) { Log.d(TAG, "Loader has finished for: " - + DocumentInfo.debugString(mState.stack.peek())); + + DocumentInfo.debugString(mState.stack.peek())); } - assert(result != null); + assert (result != null); mInjector.getModel().update(result); mLoaderSemaphore.release(); @@ -974,24 +1081,34 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA mLoaderSemaphore.release(); } } + /** * A class primarily for the support of isolating our tests * from our concrete activity implementations. */ public interface CommonAddons { void restoreRootAndDirectory(); + void refreshCurrentRootAndDirectory(@AnimationType int anim); + void onRootPicked(RootInfo root); + // TODO: Move this to PickAddons as multi-document picking is exclusive to that activity. void onDocumentsPicked(List<DocumentInfo> docs); + void onDocumentPicked(DocumentInfo doc); + RootInfo getCurrentRoot(); + DocumentInfo getCurrentDirectory(); + UserId getSelectedUser(); + /** * Check whether current directory is root of recent. */ boolean isInRecents(); + void setRootsDrawerOpen(boolean open); /** diff --git a/src/com/android/documentsui/ActionHandler.java b/src/com/android/documentsui/ActionHandler.java index 15124eb33..190f5d960 100644 --- a/src/com/android/documentsui/ActionHandler.java +++ b/src/com/android/documentsui/ActionHandler.java @@ -118,7 +118,7 @@ public interface ActionHandler { void showCreateDirectoryDialog(); - void showInspector(DocumentInfo doc); + void showPreview(DocumentInfo doc); @Nullable DocumentInfo renameDocument(String name, DocumentInfo document); @@ -129,6 +129,12 @@ public interface ActionHandler { boolean openItem(ItemDetails<String> doc, @ViewType int type, @ViewType int fallback); /** + * Similar to openItem but takes DocumentInfo instead of DocumentItemDetails and uses + * VIEW_TYPE_VIEW with no fallback. + */ + void openDocumentViewOnly(DocumentInfo doc); + + /** * This is called when user hovers over a doc for enough time during a drag n' drop, to open a * folder that accepts drop. We should only open a container that's not an archive, since archives * do not accept dropping. diff --git a/src/com/android/documentsui/ActionModeController.java b/src/com/android/documentsui/ActionModeController.java index 89b8ff383..39a50abf9 100644 --- a/src/com/android/documentsui/ActionModeController.java +++ b/src/com/android/documentsui/ActionModeController.java @@ -17,6 +17,7 @@ package com.android.documentsui; import static com.android.documentsui.base.SharedMinimal.DEBUG; +import static com.android.documentsui.flags.Flags.useMaterial3; import android.app.Activity; import android.util.Log; @@ -79,7 +80,8 @@ public class ActionModeController extends SelectionObserver<String> Log.d(TAG, "Starting action mode."); } mActionMode = mActivity.startActionMode(this); - final View closeButton = mActivity.findViewById(R.id.action_mode_close_button); + final View closeButton = + mActivity.findViewById(androidx.appcompat.R.id.action_mode_close_button); if (closeButton != null) { closeButton.setContentDescription(mActivity.getString(android.R.string.cancel)); } @@ -133,8 +135,12 @@ public class ActionModeController extends SelectionObserver<String> mActivity.getWindow().setTitle(mActivity.getTitle()); // Re-enable TalkBack for the toolbars, as they are no longer covered by action mode. + int[] toolbarIds = + useMaterial3() + ? new int[] {R.id.toolbar} + : new int[] {R.id.toolbar, R.id.roots_toolbar}; mScope.accessibilityImportanceSetter.setAccessibilityImportance( - View.IMPORTANT_FOR_ACCESSIBILITY_AUTO, R.id.toolbar, R.id.roots_toolbar); + View.IMPORTANT_FOR_ACCESSIBILITY_AUTO, toolbarIds); mNavigator.setActionModeActivated(false); } @@ -150,10 +156,13 @@ public class ActionModeController extends SelectionObserver<String> // Hide the toolbars if action mode is enabled, so TalkBack doesn't navigate to // these controls when using linear navigation. + int[] toolbarIds = + useMaterial3() + ? new int[] {R.id.toolbar} + : new int[] {R.id.toolbar, R.id.roots_toolbar}; mScope.accessibilityImportanceSetter.setAccessibilityImportance( View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, - R.id.toolbar, - R.id.roots_toolbar); + toolbarIds); return true; } diff --git a/src/com/android/documentsui/BaseActivity.java b/src/com/android/documentsui/BaseActivity.java index 5af331439..41fc5182f 100644 --- a/src/com/android/documentsui/BaseActivity.java +++ b/src/com/android/documentsui/BaseActivity.java @@ -19,6 +19,7 @@ package com.android.documentsui; import static com.android.documentsui.base.Shared.EXTRA_BENCHMARK; import static com.android.documentsui.base.SharedMinimal.DEBUG; import static com.android.documentsui.base.State.MODE_GRID; +import static com.android.documentsui.flags.Flags.useMaterial3; import android.content.Context; import android.content.Intent; @@ -54,6 +55,7 @@ import com.android.documentsui.AbstractActionHandler.CommonAddons; import com.android.documentsui.Injector.Injected; import com.android.documentsui.NavigationViewManager.Breadcrumb; import com.android.documentsui.base.DocumentInfo; +import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.EventHandler; import com.android.documentsui.base.RootInfo; import com.android.documentsui.base.Shared; @@ -76,8 +78,8 @@ import com.android.documentsui.sorting.SortController; import com.android.documentsui.sorting.SortModel; import com.android.modules.utils.build.SdkLevel; -import com.android.documentsui.util.VersionUtils; import com.google.android.material.appbar.AppBarLayout; +import com.google.android.material.color.DynamicColors; import java.util.ArrayList; import java.util.Date; @@ -89,10 +91,12 @@ public abstract class BaseActivity extends AppCompatActivity implements CommonAddons, NavigationViewManager.Environment { private static final String BENCHMARK_TESTING_PACKAGE = "com.android.documentsui.appperftests"; + private static final String TAG = "BaseActivity"; protected SearchViewManager mSearchManager; protected AppsRowManager mAppsRowManager; protected UserIdManager mUserIdManager; + protected UserManagerState mUserManagerState; protected State mState; @Injected @@ -104,6 +108,7 @@ public abstract class BaseActivity protected NavigationViewManager mNavigator; protected SortController mSortController; + protected ConfigStore mConfigStore; private final List<EventListener> mEventListeners = new ArrayList<>(); private final String mTag; @@ -118,18 +123,51 @@ public abstract class BaseActivity private PreferencesMonitor mPreferencesMonitor; + private final DocumentStack mInitialStack = new DocumentStack(); + private UserId mLastSelectedUser = null; + + protected void setInitialStack(DocumentStack stack) { + if (mInitialStack.isInitialized()) { + if (DEBUG) { + Log.d(TAG, "Initial stack already initialised. " + mInitialStack.isInitialized()); + } + return; + } + mInitialStack.reset(stack); + } + + public DocumentStack getInitialStack() { + return mInitialStack; + } + + public UserId getLastSelectedUser() { + return mLastSelectedUser; + } + public BaseActivity(@LayoutRes int layoutId, String tag) { mLayoutId = layoutId; mTag = tag; } protected abstract void refreshDirectory(int anim); + /** Allows sub-classes to include information in a newly created State instance. */ protected abstract void includeState(State initialState); + protected abstract void onDirectoryCreated(DocumentInfo doc); public abstract Injector<?> getInjector(); + @VisibleForTesting + protected void initConfigStore() { + mConfigStore = DocumentsApplication.getConfigStore(); + } + + @VisibleForTesting + public void setConfigStore(ConfigStore configStore) { + mConfigStore = configStore; + } + @CallSuper @Override public void onCreate(Bundle savedInstanceState) { @@ -142,9 +180,13 @@ public abstract class BaseActivity // ToDo Create tool to check resource version before applyStyle for the theme // If version code is not match, we should reset overlay package to default, - // in case Activity continueusly encounter resource not found exception + // in case Activity continuously encounter resource not found exception. getTheme().applyStyle(R.style.DocumentsDefaultTheme, false); + if (useMaterial3() && SdkLevel.isAtLeastS()) { + DynamicColors.applyToActivityIfAvailable(this); + } + super.onCreate(savedInstanceState); final Intent intent = getIntent(); @@ -155,6 +197,8 @@ public abstract class BaseActivity setContainer(); + initConfigStore(); + mInjector = getInjector(); mState = getState(savedInstanceState); mDrawer = DrawerController.create(this, mInjector.config); @@ -167,12 +211,11 @@ public abstract class BaseActivity setSupportActionBar(toolbar); Breadcrumb breadcrumb = findViewById(R.id.horizontal_breadcrumb); - assert(breadcrumb != null); + assert (breadcrumb != null); View profileTabsContainer = findViewById(R.id.tabs_container); assert (profileTabsContainer != null); - mNavigator = new NavigationViewManager(this, mDrawer, mState, this, breadcrumb, - profileTabsContainer, DocumentsApplication.getUserIdManager(this)); + mNavigator = getNavigationViewManager(breadcrumb, profileTabsContainer); AppBarLayout appBarLayout = findViewById(R.id.app_bar); if (appBarLayout != null) { appBarLayout.addOnOffsetChangedListener(mNavigator); @@ -231,11 +274,11 @@ public abstract class BaseActivity @Override public void onSearchViewFocusChanged(boolean hasFocus) { - final boolean isInitailSearch + final boolean isInitialSearch = !TextUtils.isEmpty(mSearchManager.getCurrentSearch()) && TextUtils.isEmpty(mSearchManager.getSearchViewText()); if (hasFocus) { - if (!isInitailSearch) { + if (!isInitialSearch) { SearchFragment.showFragment(getSupportFragmentManager(), mSearchManager.getSearchViewText()); } @@ -269,7 +312,15 @@ public abstract class BaseActivity cmdInterceptor); ViewGroup chipGroup = findViewById(R.id.search_chip_group); + mUserIdManager = DocumentsApplication.getUserIdManager(this); + mUserManagerState = DocumentsApplication.getUserManagerState(this); + // If private space feature flag is enabled, we should store the intent that launched docsUi + // so that we can use this intent to get CrossProfileResolveInfo when ever we want to, + // for example when ACTION_PROFILE_AVAILABLE intent is received + if (mUserManagerState != null && SdkLevel.isAtLeastS()) { + mUserManagerState.setCurrentStateIntent(intent); + } mSearchManager = new SearchViewManager(searchListener, queryInterceptor, chipGroup, savedInstanceState); // initialize the chip sets by accept mime types @@ -307,6 +358,14 @@ public abstract class BaseActivity if (roots != null) { roots.onSelectedUserChanged(); } + if (useMaterial3()) { + final RootsFragment navRailRoots = + RootsFragment.getNavRail(getSupportFragmentManager()); + if (navRailRoots != null) { + navRailRoots.onSelectedUserChanged(); + } + } + if (mState.stack.size() <= 1) { // We do not load cross-profile root if the stack contains two documents. The @@ -319,6 +378,9 @@ public abstract class BaseActivity // The activity will clear search on root picked. If we don't clear the search, // user may see the search result screen show up briefly and then get cleared. mSearchManager.cancelSearch(); + // When a profile with user property SHOW_IN_QUIET_MODE_HIDDEN is currently + // selected, and it becomes unavailable, we reset the roots to recents. + // We do not reset it to recents when pick activity is due to ACTION_CREATE_DOCUMENT mInjector.actions.loadCrossProfileRoot(getCurrentRoot(), userId); } }); @@ -333,6 +395,19 @@ public abstract class BaseActivity // Base classes must update result in their onCreate. setResult(AppCompatActivity.RESULT_CANCELED); + updateRecentsSetting(); + } + + private NavigationViewManager getNavigationViewManager(Breadcrumb breadcrumb, + View profileTabsContainer) { + if (mConfigStore.isPrivateSpaceInDocsUIEnabled()) { + return new NavigationViewManager(this, mDrawer, mState, this, breadcrumb, + profileTabsContainer, DocumentsApplication.getUserManagerState(this), + mConfigStore); + } + return new NavigationViewManager(this, mDrawer, mState, this, breadcrumb, + profileTabsContainer, DocumentsApplication.getUserIdManager(this), + mConfigStore); } public void onPreferenceChanged(String pref) { @@ -358,6 +433,12 @@ public abstract class BaseActivity } @Override + protected void onPause() { + super.onPause(); + mLastSelectedUser = getSelectedUser(); + } + + @Override public boolean onCreateOptionsMenu(Menu menu) { boolean showMenu = super.onCreateOptionsMenu(menu); @@ -367,9 +448,10 @@ public abstract class BaseActivity boolean showSearchBar = getResources().getBoolean(R.bool.show_search_bar); mSearchManager.install(menu, fullBarSearch, showSearchBar); + // Remove the subMenu when material3 is launched b/379776735. final ActionMenuView subMenuView = findViewById(R.id.sub_menu); // If size is 0, it means the menu has not inflated and it should only do once. - if (subMenuView.getMenu().size() == 0) { + if (subMenuView != null && subMenuView.getMenu().size() == 0) { subMenuView.setOnMenuItemClickListener(this::onOptionsItemSelected); getMenuInflater().inflate(R.menu.sub_menu, subMenuView.getMenu()); } @@ -382,8 +464,14 @@ public abstract class BaseActivity public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); mSearchManager.showMenu(mState.stack); - final ActionMenuView subMenuView = findViewById(R.id.sub_menu); - mInjector.menuManager.updateSubMenu(subMenuView.getMenu()); + // Remove the subMenu when material3 is launched b/379776735. + if (useMaterial3()) { + mInjector.menuManager.updateSubMenu(null); + } else { + final ActionMenuView subMenuView = findViewById(R.id.sub_menu); + mInjector.menuManager.updateSubMenu(subMenuView.getMenu()); + } + return true; } @@ -392,6 +480,7 @@ public abstract class BaseActivity mRootsMonitor.stop(); mPreferencesMonitor.stop(); mSortController.destroy(); + DocumentsApplication.invalidateUserManagerState(this); super.onDestroy(); } @@ -417,6 +506,7 @@ public abstract class BaseActivity getApplicationContext() .getResources() .getBoolean(R.bool.show_hidden_files_by_default)); + state.configStore = mConfigStore; includeState(state); @@ -435,11 +525,16 @@ public abstract class BaseActivity root.setPadding(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), 0); - View saveContainer = findViewById(R.id.container_save); - saveContainer.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom()); + // in M3, no additional bottom gap in full screen mode. + if (!useMaterial3()) { + View saveContainer = findViewById(R.id.container_save); + saveContainer.setPadding( + 0, 0, 0, insets.getSystemWindowInsetBottom()); - View rootsContainer = findViewById(R.id.container_roots); - rootsContainer.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom()); + View rootsContainer = findViewById(R.id.container_roots); + rootsContainer.setPadding( + 0, 0, 0, insets.getSystemWindowInsetBottom()); + } return insets.consumeSystemWindowInsets(); }); @@ -509,50 +604,39 @@ public abstract class BaseActivity @Override public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - onBackPressed(); - return true; - - case R.id.option_menu_create_dir: - getInjector().actions.showCreateDirectoryDialog(); - return true; - - case R.id.option_menu_search: - // SearchViewManager listens for this directly. - return false; - - case R.id.option_menu_select_all: - getInjector().actions.selectAllFiles(); - return true; - - case R.id.option_menu_debug: - getInjector().actions.showDebugMessage(); - return true; - - case R.id.option_menu_sort: - getInjector().actions.showSortDialog(); - return true; - - case R.id.option_menu_launcher: - getInjector().actions.switchLauncherIcon(); - return true; - - case R.id.option_menu_show_hidden_files: - onClickedShowHiddenFiles(); - return true; - - case R.id.sub_menu_grid: - setViewMode(State.MODE_GRID); - return true; - - case R.id.sub_menu_list: - setViewMode(State.MODE_LIST); - return true; - - default: - return super.onOptionsItemSelected(item); + final int id = item.getItemId(); + if (id == android.R.id.home) { + onBackPressed(); + return true; + } else if (id == R.id.option_menu_create_dir) { + getInjector().actions.showCreateDirectoryDialog(); + return true; + } else if (id == R.id.option_menu_search) { + // SearchViewManager listens for this directly. + return false; + } else if (id == R.id.option_menu_select_all) { + getInjector().actions.selectAllFiles(); + return true; + } else if (id == R.id.option_menu_debug) { + getInjector().actions.showDebugMessage(); + return true; + } else if (id == R.id.option_menu_sort) { + getInjector().actions.showSortDialog(); + return true; + } else if (id == R.id.option_menu_launcher) { + getInjector().actions.switchLauncherIcon(); + return true; + } else if (id == R.id.option_menu_show_hidden_files) { + onClickedShowHiddenFiles(); + return true; + } else if (id == R.id.sub_menu_grid) { + setViewMode(MODE_GRID); + return true; + } else if (id == R.id.sub_menu_list) { + setViewMode(State.MODE_LIST); + return true; } + return super.onOptionsItemSelected(item); } protected final @Nullable DirectoryFragment getDirectoryFragment() { @@ -561,7 +645,6 @@ public abstract class BaseActivity /** * Returns true if a directory can be created in the current location. - * @return */ protected boolean canCreateDirectory() { final RootInfo root = getCurrentRoot(); @@ -599,7 +682,6 @@ public abstract class BaseActivity /** * Refreshes the content of the director and the menu/action bar. * The current directory name and selection will get updated. - * @param anim */ @Override public final void refreshCurrentRootAndDirectory(int anim) { @@ -621,6 +703,13 @@ public abstract class BaseActivity if (roots != null) { roots.onCurrentRootChanged(); } + if (useMaterial3()) { + final RootsFragment navRailRoots = + RootsFragment.getNavRail(getSupportFragmentManager()); + if (navRailRoots != null) { + navRailRoots.onCurrentRootChanged(); + } + } String appName = getString(R.string.files_label); String currentTitle = getTitle() != null ? getTitle().toString() : ""; @@ -649,7 +738,7 @@ public abstract class BaseActivity try { PackageInfo pkgInfo = getPackageManager().getPackageInfo(packageName, PackageManager.GET_PROVIDERS); - for (ProviderInfo provider: pkgInfo.providers) { + for (ProviderInfo provider : pkgInfo.providers) { authorities.add(provider.authority); } } catch (PackageManager.NameNotFoundException e) { @@ -697,8 +786,13 @@ public abstract class BaseActivity LocalPreferences.setViewMode(this, getCurrentRoot(), mode); mState.derivedMode = mode; - final ActionMenuView subMenuView = findViewById(R.id.sub_menu); - mInjector.menuManager.updateSubMenu(subMenuView.getMenu()); + // Remove the subMenu when material3 is launched b/379776735. + if (useMaterial3()) { + mInjector.menuManager.updateSubMenu(null); + } else { + final ActionMenuView subMenuView = findViewById(R.id.sub_menu); + mInjector.menuManager.updateSubMenu(subMenuView.getMenu()); + } DirectoryFragment dir = getDirectoryFragment(); if (dir != null) { @@ -725,9 +819,15 @@ public abstract class BaseActivity } } - public void updateHeader(boolean shouldHideHeader){ + /** + * Updates headerContainer by setting its visibility + * + * @param shouldHideHeader whether to hide header container or not + */ + public void updateHeader(boolean shouldHideHeader) { + // Remove headContainer when material3 is launched. b/379776735. View headerContainer = findViewById(R.id.header_container); - if(headerContainer == null){ + if (headerContainer == null) { updateHeaderTitle(); return; } @@ -773,8 +873,11 @@ public abstract class BaseActivity break; } + // Remove the headerTitle when material3 is launched b/379776735. TextView headerTitle = findViewById(R.id.header_title); - headerTitle.setText(result); + if (headerTitle != null) { + headerTitle.setText(result); + } } private String getHeaderRecentTitle() { @@ -796,7 +899,7 @@ public abstract class BaseActivity private String getHeaderDownloadsTitle() { return getString(mState.isPhotoPicking() - ? R.string.root_info_header_image_downloads : R.string.root_info_header_downloads); + ? R.string.root_info_header_image_downloads : R.string.root_info_header_downloads); } private String getHeaderStorageTitle(String rootTitle) { @@ -826,6 +929,7 @@ public abstract class BaseActivity /** * Get title string equal to the string action bar displayed. + * * @return current directory title name */ public String getCurrentTitle() { @@ -989,4 +1093,28 @@ public abstract class BaseActivity */ void onDirectoryLoaded(@Nullable Uri uri); } + + /** + * Updates the Recents preview settings based on presence of hidden profiles. Used not to leak + * Private profile existence when it was locked after the app was moved to the Recents. + */ + public void updateRecentsSetting() { + if (!SdkLevel.isAtLeastV()) { + return; + } + + if (mUserManagerState == null) { + Log.e(TAG, "Can't update Recents screenshot setting: User manager state is null."); + return; + } + + if (DEBUG) { + Log.d( + TAG, + "Set recents screenshot to " + + (!mUserManagerState.areHiddenInQuietModeProfilesPresent() ? "enabled" + : "disabled")); + } + setRecentsScreenshotEnabled(!mUserManagerState.areHiddenInQuietModeProfilesPresent()); + } } diff --git a/src/com/android/documentsui/ChangeIds.java b/src/com/android/documentsui/ChangeIds.java new file mode 100644 index 000000000..5ddf40f8e --- /dev/null +++ b/src/com/android/documentsui/ChangeIds.java @@ -0,0 +1,32 @@ +/* + * 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.documentsui; + +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledAfter; +import android.os.Build; + +public final class ChangeIds { + /** + * We support restrict Storage Access Framework from {@link Build.VERSION_CODES#R}. + * App Compatibility flag that indicates whether the app should be restricted or not. + * This flag is turned on by default for all apps targeting > + * {@link Build.VERSION_CODES#Q}. + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) + public static final long RESTRICT_STORAGE_ACCESS_FRAMEWORK = 141600225L; +} diff --git a/src/com/android/documentsui/ConfigStore.java b/src/com/android/documentsui/ConfigStore.java new file mode 100644 index 000000000..49dac511c --- /dev/null +++ b/src/com/android/documentsui/ConfigStore.java @@ -0,0 +1,42 @@ +/* + * 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.documentsui; + +import com.android.modules.utils.build.SdkLevel; + +public interface ConfigStore { + boolean DEFAULT_PICKER_PRIVATE_SPACE_ENABLED = true; + + /** + * @return if the Private-Space-in-DocsUI is enabled + */ + default boolean isPrivateSpaceInDocsUIEnabled() { + return DEFAULT_PICKER_PRIVATE_SPACE_ENABLED; + } + + /** + * Implementation of the {@link ConfigStore} that reads "real" configs from + * {@link android.provider.DeviceConfig}. Meant to be used by the "production" code. + */ + class ConfigStoreImpl implements ConfigStore { + @Override + public boolean isPrivateSpaceInDocsUIEnabled() { + return SdkLevel.isAtLeastS(); + } + + } +} diff --git a/src/com/android/documentsui/DirectoryLoader.java b/src/com/android/documentsui/DirectoryLoader.java index 816144758..15b3ce5e5 100644 --- a/src/com/android/documentsui/DirectoryLoader.java +++ b/src/com/android/documentsui/DirectoryLoader.java @@ -48,6 +48,7 @@ import com.android.documentsui.base.State; import com.android.documentsui.base.UserId; import com.android.documentsui.roots.RootCursorWrapper; import com.android.documentsui.sorting.SortModel; +import com.android.modules.utils.build.SdkLevel; import java.util.ArrayList; import java.util.List; @@ -129,8 +130,7 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> { if (mSearchMode) { queryArgs.putAll(mQueryArgs); if (shouldSearchAcrossProfile()) { - for (UserId userId : DocumentsApplication.getUserIdManager( - getContext()).getUserIds()) { + for (UserId userId : getUserIds()) { if (mState.canInteractWith(userId)) { userIds.add(userId); } @@ -330,4 +330,11 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> { } return false; } + + private List<UserId> getUserIds() { + if (mState.configStore.isPrivateSpaceInDocsUIEnabled() && SdkLevel.isAtLeastS()) { + return DocumentsApplication.getUserManagerState(getContext()).getUserIds(); + } + return DocumentsApplication.getUserIdManager(getContext()).getUserIds(); + } } diff --git a/src/com/android/documentsui/DocumentsAccess.java b/src/com/android/documentsui/DocumentsAccess.java index e3b6abde3..fcd3471fc 100644 --- a/src/com/android/documentsui/DocumentsAccess.java +++ b/src/com/android/documentsui/DocumentsAccess.java @@ -69,7 +69,6 @@ public interface DocumentsAccess { public final class RuntimeDocumentAccess implements DocumentsAccess { private static final String TAG = "DocumentAccess"; - private final Context mContext; private final State mState; diff --git a/src/com/android/documentsui/DocumentsApplication.java b/src/com/android/documentsui/DocumentsApplication.java index c576851b7..ffaa5d740 100644 --- a/src/com/android/documentsui/DocumentsApplication.java +++ b/src/com/android/documentsui/DocumentsApplication.java @@ -28,9 +28,11 @@ import android.content.IntentFilter; import android.content.om.OverlayManager; import android.net.Uri; import android.os.RemoteException; +import android.os.UserHandle; import android.text.format.DateUtils; import android.util.Log; +import androidx.annotation.Nullable; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import com.android.documentsui.base.Lookup; @@ -41,11 +43,14 @@ import com.android.documentsui.clipping.DocumentClipper; import com.android.documentsui.queries.SearchHistoryManager; import com.android.documentsui.roots.ProvidersCache; import com.android.documentsui.theme.ThemeOverlayManager; +import com.android.modules.utils.build.SdkLevel; import com.google.common.collect.Lists; import java.util.List; +import javax.annotation.concurrent.GuardedBy; + public class DocumentsApplication extends Application { private static final String TAG = "DocumentsApplication"; private static final long PROVIDER_ANR_TIMEOUT = 20 * DateUtils.SECOND_IN_MILLIS; @@ -57,19 +62,24 @@ public class DocumentsApplication extends Application { Intent.ACTION_PACKAGE_DATA_CLEARED ); - private static final List<String> MANAGED_PROFILE_FILTER_ACTIONS = Lists.newArrayList( + private static final List<String> PROFILE_FILTER_ACTIONS = Lists.newArrayList( Intent.ACTION_MANAGED_PROFILE_ADDED, Intent.ACTION_MANAGED_PROFILE_REMOVED, Intent.ACTION_MANAGED_PROFILE_UNLOCKED, Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE ); + @GuardedBy("DocumentsApplication.class") + @Nullable + private static volatile ConfigStore sConfigStore; + private ProvidersCache mProviders; private ThumbnailCache mThumbnailCache; private ClipStorage mClipStore; private DocumentClipper mClipper; private DragAndDropManager mDragAndDropManager; private UserIdManager mUserIdManager; + private UserManagerState mUserManagerState; private Lookup<String, String> mFileTypeLookup; public static ProvidersCache getProvidersCache(Context context) { @@ -101,7 +111,29 @@ public class DocumentsApplication extends Application { } public static UserIdManager getUserIdManager(Context context) { - return ((DocumentsApplication) context.getApplicationContext()).mUserIdManager; + UserIdManager userIdManager = + ((DocumentsApplication) context.getApplicationContext()).mUserIdManager; + if (userIdManager == null) { + userIdManager = UserIdManager.create(context); + ((DocumentsApplication) context.getApplicationContext()).mUserIdManager = userIdManager; + } + return userIdManager; + } + + /** + * UserManagerState class is used to maintain the list of userIds and other details like + * cross profile access, label and badge associated with these userIds. + */ + public static UserManagerState getUserManagerState(Context context) { + UserManagerState userManagerState = + ((DocumentsApplication) context.getApplicationContext()).mUserManagerState; + if (userManagerState == null && getConfigStore().isPrivateSpaceInDocsUIEnabled() + && SdkLevel.isAtLeastS()) { + userManagerState = UserManagerState.create(context); + ((DocumentsApplication) context.getApplicationContext()).mUserManagerState = + userManagerState; + } + return userManagerState; } public static DragAndDropManager getDragAndDropManager(Context context) { @@ -112,6 +144,24 @@ public class DocumentsApplication extends Application { return ((DocumentsApplication) context.getApplicationContext()).mFileTypeLookup; } + /** + * Retrieve {@link ConfigStore} instance to access feature flags in production code. + */ + public static synchronized ConfigStore getConfigStore() { + if (sConfigStore == null) { + sConfigStore = new ConfigStore.ConfigStoreImpl(); + } + return sConfigStore; + } + + /** + * Set {@link #mUserManagerState} as null onDestroy of BaseActivity so that new session uses new + * instance of {@link #mUserManagerState} + */ + public static void invalidateUserManagerState(Context context) { + ((DocumentsApplication) context.getApplicationContext()).mUserManagerState = null; + } + private void onApplyOverlayFinish(boolean result) { Log.d(TAG, "OverlayManager.setEnabled() result: " + result); } @@ -120,6 +170,11 @@ public class DocumentsApplication extends Application { @Override public void onCreate() { super.onCreate(); + synchronized (DocumentsApplication.class) { + if (sConfigStore == null) { + sConfigStore = new ConfigStore.ConfigStoreImpl(); + } + } final ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); final OverlayManager om = getSystemService(OverlayManager.class); @@ -132,9 +187,15 @@ public class DocumentsApplication extends Application { Log.w(TAG, "Can't obtain OverlayManager from System Service!"); } - mUserIdManager = UserIdManager.create(this); + if (getConfigStore().isPrivateSpaceInDocsUIEnabled()) { + mUserManagerState = UserManagerState.create(this); + mUserIdManager = null; + } else { + mUserManagerState = null; + mUserIdManager = UserIdManager.create(this); + } + mProviders = new ProvidersCache(this); - mProviders = new ProvidersCache(this, mUserIdManager); mProviders.updateAsync(/* forceRefreshAll= */ false, /* callback= */ null); mThumbnailCache = new ThumbnailCache(memoryClassBytes / 4); @@ -159,11 +220,19 @@ public class DocumentsApplication extends Application { localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED); registerReceiver(mCacheReceiver, localeFilter); - final IntentFilter managedProfileFilter = new IntentFilter(); - for (String managedProfileAction : MANAGED_PROFILE_FILTER_ACTIONS) { - managedProfileFilter.addAction(managedProfileAction); + if (SdkLevel.isAtLeastV()) { + PROFILE_FILTER_ACTIONS.addAll(Lists.newArrayList( + Intent.ACTION_PROFILE_ADDED, + Intent.ACTION_PROFILE_REMOVED, + Intent.ACTION_PROFILE_AVAILABLE, + Intent.ACTION_PROFILE_UNAVAILABLE + )); + } + final IntentFilter profileFilter = new IntentFilter(); + for (String profileAction : PROFILE_FILTER_ACTIONS) { + profileFilter.addAction(profileAction); } - registerReceiver(mCacheReceiver, managedProfileFilter); + registerReceiver(mCacheReceiver, profileFilter); SearchHistoryManager.getInstance(getApplicationContext()); } @@ -183,7 +252,14 @@ public class DocumentsApplication extends Application { if (PACKAGE_FILTER_ACTIONS.contains(action) && data != null) { final String packageName = data.getSchemeSpecificPart(); mProviders.updatePackageAsync(UserId.DEFAULT_USER, packageName); - } else if (MANAGED_PROFILE_FILTER_ACTIONS.contains(action)) { + } else if (PROFILE_FILTER_ACTIONS.contains(action)) { + // Make the changes to UserManagerState object before calling providers updateAsync + // so that providers for all the users are loaded + if (getConfigStore().isPrivateSpaceInDocsUIEnabled() && SdkLevel.isAtLeastV()) { + UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER); + UserId userId = UserId.of(userHandle); + getUserManagerState(context).onProfileActionStatusChange(action, userId); + } // After we have reloaded roots. Resend the broadcast locally so the other // components can reload properly after roots are updated. mProviders.updateAsync(/* forceRefreshAll= */ true, diff --git a/src/com/android/documentsui/DrawerController.java b/src/com/android/documentsui/DrawerController.java index 56b3a879f..88c41b3f2 100644 --- a/src/com/android/documentsui/DrawerController.java +++ b/src/com/android/documentsui/DrawerController.java @@ -17,6 +17,7 @@ package com.android.documentsui; import static com.android.documentsui.base.SharedMinimal.DEBUG; +import static com.android.documentsui.flags.Flags.useMaterial3; import android.app.Activity; import android.util.Log; @@ -59,6 +60,8 @@ public abstract class DrawerController implements DrawerListener { } View drawer = activity.findViewById(R.id.drawer_roots); + // This will be null in M3, we will check the flag when it's used in + // RuntimeDrawerController. Toolbar toolbar = (Toolbar) activity.findViewById(R.id.roots_toolbar); drawer.getLayoutParams().width = calculateDrawerWidth(activity); @@ -124,7 +127,10 @@ public abstract class DrawerController implements DrawerListener { if (activityConfig.dragAndDropEnabled()) { View edge = layout.findViewById(R.id.drawer_edge); - edge.setOnDragListener(new ItemDragListener<>(this, SPRING_TIMEOUT)); + // nav_rail_layout also uses DrawerLayout, but it doesn't have drawer edge. + if (edge != null) { + edge.setOnDragListener(new ItemDragListener<>(this, SPRING_TIMEOUT)); + } } } @@ -202,7 +208,9 @@ public abstract class DrawerController implements DrawerListener { @Override void setTitle(String title) { - mToolbar.setTitle(title); + if (!useMaterial3()) { + mToolbar.setTitle(title); + } } @Override diff --git a/src/com/android/documentsui/MenuManager.java b/src/com/android/documentsui/MenuManager.java index 405533a00..126a777da 100644 --- a/src/com/android/documentsui/MenuManager.java +++ b/src/com/android/documentsui/MenuManager.java @@ -16,6 +16,8 @@ package com.android.documentsui; +import static com.android.documentsui.flags.Flags.useMaterial3; + import android.view.KeyboardShortcutGroup; import android.view.Menu; import android.view.MenuInflater; @@ -25,11 +27,13 @@ import android.view.View; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; +import com.android.documentsui.archives.ArchivesProvider; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.Menus; import com.android.documentsui.base.RootInfo; import com.android.documentsui.base.State; import com.android.documentsui.dirlist.DirectoryFragment; +import com.android.documentsui.flags.Flags; import com.android.documentsui.queries.SearchViewManager; import com.android.documentsui.sidebar.RootsFragment; @@ -89,6 +93,9 @@ public abstract class MenuManager { return; } updateCreateDir(mOptionMenu.findItem(R.id.option_menu_create_dir)); + if (Flags.zipNg()) { + updateExtractAll(mOptionMenu.findItem(R.id.option_menu_extract_all)); + } updateSettings(mOptionMenu.findItem(R.id.option_menu_settings)); updateSelectAll(mOptionMenu.findItem(R.id.option_menu_select_all)); updateNewWindow(mOptionMenu.findItem(R.id.option_menu_new_window)); @@ -98,12 +105,25 @@ public abstract class MenuManager { updateLauncher(mOptionMenu.findItem(R.id.option_menu_launcher)); updateShowHiddenFiles(mOptionMenu.findItem(R.id.option_menu_show_hidden_files)); + if (useMaterial3()) { + updateModePicker(mOptionMenu.findItem(R.id.sub_menu_grid), + mOptionMenu.findItem(R.id.sub_menu_list)); + } + Menus.disableHiddenItems(mOptionMenu); mSearchManager.updateMenu(); } public void updateSubMenu(Menu menu) { + // Remove the subMenu when material3 is launched b/379776735. + if (useMaterial3()) { + menu = mOptionMenu; + if (menu == null) { + return; + } + } updateModePicker(menu.findItem(R.id.sub_menu_grid), menu.findItem(R.id.sub_menu_list)); + } public void updateModel(Model model) {} @@ -213,6 +233,8 @@ public abstract class MenuManager { Menus.setEnabledAndVisible(delete, canDelete); Menus.setEnabledAndVisible(inspect, selectionDetails.size() == 1); + + updateCompress(menu.findItem(R.id.dir_menu_compress), selectionDetails); } /** @@ -377,6 +399,10 @@ public abstract class MenuManager { Menus.setEnabledAndVisible(launcher, false); } + protected void updateExtractAll(MenuItem it) { + Menus.setEnabledAndVisible(it, false); + } + protected abstract void updateSelectAll(MenuItem selectAll); protected abstract void updateSelectAll(MenuItem selectAll, SelectionDetails selectionDetails); protected abstract void updateDeselectAll( @@ -407,7 +433,7 @@ public abstract class MenuManager { boolean canExtract(); - boolean canOpenWith(); + boolean canOpen(); boolean canViewInOwner(); } @@ -435,6 +461,12 @@ public abstract class MenuManager { return mActivity.isInRecents(); } + /** Is the current directory showing the contents of an archive? */ + public boolean isInArchive() { + final DocumentInfo dir = mActivity.getCurrentDirectory(); + return dir != null && ArchivesProvider.AUTHORITY.equals(dir.authority); + } + public boolean canCreateDirectory() { return mActivity.canCreateDirectory(); } diff --git a/src/com/android/documentsui/MultiRootDocumentsLoader.java b/src/com/android/documentsui/MultiRootDocumentsLoader.java index 7668b0693..1213a6711 100644 --- a/src/com/android/documentsui/MultiRootDocumentsLoader.java +++ b/src/com/android/documentsui/MultiRootDocumentsLoader.java @@ -59,7 +59,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; -/* +/** * The abstract class to query multiple roots from {@link android.provider.DocumentsProvider} * and return the combined result. */ @@ -71,7 +71,7 @@ public abstract class MultiRootDocumentsLoader extends AsyncTaskLoader<Directory // previously returned cursors for filtering/sorting; this currently races // with the UI thread. - private static final int MAX_OUTSTANDING_TASK = 4; + public static final int MAX_OUTSTANDING_TASK = 4; private static final int MAX_OUTSTANDING_TASK_SVELTE = 2; /** @@ -88,7 +88,7 @@ public abstract class MultiRootDocumentsLoader extends AsyncTaskLoader<Directory private LockingContentObserver mObserver; @GuardedBy("mTasks") - /** A authority -> QueryTask map */ + /* A authority -> QueryTask map */ private final Map<String, QueryTask> mTasks = new HashMap<>(); private CountDownLatch mFirstPassLatch; @@ -96,7 +96,7 @@ public abstract class MultiRootDocumentsLoader extends AsyncTaskLoader<Directory private DirectoryResult mResult; - /* + /** * Create the loader to query roots from {@link android.provider.DocumentsProvider}. * * @param context the context @@ -196,11 +196,11 @@ public abstract class MultiRootDocumentsLoader extends AsyncTaskLoader<Directory final FilteringCursorWrapper filteredCursor = new FilteringCursorWrapper(cursor) { - @Override - public void close() { - // Ignored, since we manage cursor lifecycle internally - } - }; + @Override + public void close() { + // Ignored, since we manage cursor lifecycle internally + } + }; filteredCursor.filterHiddenFiles(mState.showHiddenFiles); filteredCursor.filterMimes(mState.acceptMimes, getRejectMimes()); filteredCursor.filterLastModified(rejectBefore); diff --git a/src/com/android/documentsui/NavigationViewManager.java b/src/com/android/documentsui/NavigationViewManager.java index a9dec9e5b..c376c86db 100644 --- a/src/com/android/documentsui/NavigationViewManager.java +++ b/src/com/android/documentsui/NavigationViewManager.java @@ -68,9 +68,11 @@ public class NavigationViewManager implements AppBarLayout.OnOffsetChangedListen private final ViewOutlineProvider mDefaultOutlineProvider; private final ViewOutlineProvider mSearchBarOutlineProvider; private final boolean mShowSearchBar; + private final ConfigStore mConfigStore; private boolean mIsActionModeActivated = false; - private @ColorRes int mDefaultStatusBarColorResId; + @ColorRes + private int mDefaultStatusBarColorResId; public NavigationViewManager( BaseActivity activity, @@ -79,7 +81,35 @@ public class NavigationViewManager implements AppBarLayout.OnOffsetChangedListen NavigationViewManager.Environment env, Breadcrumb breadcrumb, View tabLayoutContainer, - UserIdManager userIdManager) { + UserIdManager userIdManager, + ConfigStore configStore) { + this(activity, drawer, state, env, breadcrumb, tabLayoutContainer, userIdManager, null, + configStore); + } + + public NavigationViewManager( + BaseActivity activity, + DrawerController drawer, + State state, + NavigationViewManager.Environment env, + Breadcrumb breadcrumb, + View tabLayoutContainer, + UserManagerState userManagerState, + ConfigStore configStore) { + this(activity, drawer, state, env, breadcrumb, tabLayoutContainer, null, userManagerState, + configStore); + } + + public NavigationViewManager( + BaseActivity activity, + DrawerController drawer, + State state, + NavigationViewManager.Environment env, + Breadcrumb breadcrumb, + View tabLayoutContainer, + UserIdManager userIdManager, + UserManagerState userManagerState, + ConfigStore configStore) { mActivity = activity; mToolbar = activity.findViewById(R.id.toolbar); @@ -89,7 +119,9 @@ public class NavigationViewManager implements AppBarLayout.OnOffsetChangedListen mEnv = env; mBreadcrumb = breadcrumb; mBreadcrumb.setup(env, state, this::onNavigationItemSelected); - mProfileTabs = new ProfileTabs(tabLayoutContainer, mState, userIdManager, mEnv, activity); + mConfigStore = configStore; + mProfileTabs = + getProfileTabs(tabLayoutContainer, userIdManager, userManagerState, activity); mToolbar.setNavigationOnClickListener( new View.OnClickListener() { @@ -128,6 +160,15 @@ public class NavigationViewManager implements AppBarLayout.OnOffsetChangedListen }; } + private ProfileTabs getProfileTabs(View tabLayoutContainer, UserIdManager userIdManager, + UserManagerState userManagerState, BaseActivity activity) { + return mConfigStore.isPrivateSpaceInDocsUIEnabled() + ? new ProfileTabs(tabLayoutContainer, mState, userManagerState, mEnv, activity, + mConfigStore) + : new ProfileTabs(tabLayoutContainer, mState, userIdManager, mEnv, activity, + mConfigStore); + } + @Override public void onOffsetChanged(AppBarLayout appBarLayout, int offset) { if (!VersionUtils.isAtLeastS()) { @@ -141,7 +182,8 @@ public class NavigationViewManager implements AppBarLayout.OnOffsetChangedListen // move directory_header out of the AppBarLayout. Window window = mActivity.getWindow(); - View actionBar = window.getDecorView().findViewById(R.id.action_mode_bar); + View actionBar = + window.getDecorView().findViewById(androidx.appcompat.R.id.action_mode_bar); int dynamicHeaderColor = ContextCompat.getColor(mActivity, offset == 0 ? mDefaultStatusBarColorResId : R.color.color_surface_header); if (actionBar != null) { diff --git a/src/com/android/documentsui/PreBootReceiver.java b/src/com/android/documentsui/PreBootReceiver.java index 2bdbee555..afb32dd54 100644 --- a/src/com/android/documentsui/PreBootReceiver.java +++ b/src/com/android/documentsui/PreBootReceiver.java @@ -95,8 +95,11 @@ public class PreBootReceiver extends BroadcastReceiver { if (resId != 0) { final ComponentName component = new ComponentName(packageName, className); boolean enabled = overlayRes.getBoolean(resId); - if (VersionUtils.isAtLeastS() && CONFIG_IS_LAUNCHER_ENABLED.equals(config)) { - enabled = false; // Do not allow LauncherActivity to be enabled for S+. + if (VersionUtils.isAtLeastS() && !pm.hasSystemFeature(PackageManager.FEATURE_PC) + && CONFIG_IS_LAUNCHER_ENABLED.equals(config)) { + // Devices using S+ that don't support the `FEATURE_PC` system feature should not + // show Files in the launcher. + enabled = false; } if (DEBUG) { Log.i(TAG, diff --git a/src/com/android/documentsui/ProfileTabs.java b/src/com/android/documentsui/ProfileTabs.java index 59a94e62b..9fbae8bae 100644 --- a/src/com/android/documentsui/ProfileTabs.java +++ b/src/com/android/documentsui/ProfileTabs.java @@ -20,9 +20,11 @@ import static androidx.core.util.Preconditions.checkNotNull; import static com.android.documentsui.DevicePolicyResources.Strings.PERSONAL_TAB; import static com.android.documentsui.DevicePolicyResources.Strings.WORK_TAB; +import static com.android.documentsui.flags.Flags.useMaterial3; import android.app.admin.DevicePolicyManager; import android.os.Build; +import android.os.UserManager; import android.view.View; import android.view.ViewGroup; @@ -37,8 +39,10 @@ import com.android.modules.utils.build.SdkLevel; import com.google.android.material.tabs.TabLayout; import com.google.common.base.Objects; +import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; /** * A manager class to control UI on a {@link TabLayout} for cross-profile purpose. @@ -51,7 +55,11 @@ public class ProfileTabs implements ProfileTabsAddons { private final State mState; private final NavigationViewManager.Environment mEnv; private final AbstractActionHandler.CommonAddons mCommonAddons; + @Nullable private final UserIdManager mUserIdManager; + @Nullable + private final UserManagerState mUserManagerState; + private final ConfigStore mConfigStore; private List<UserId> mUserIds; @Nullable private Listener mListener; @@ -60,13 +68,32 @@ public class ProfileTabs implements ProfileTabsAddons { public ProfileTabs(View tabLayoutContainer, State state, UserIdManager userIdManager, NavigationViewManager.Environment env, - AbstractActionHandler.CommonAddons commonAddons) { + AbstractActionHandler.CommonAddons commonAddons, ConfigStore configStore) { + this(tabLayoutContainer, state, userIdManager, null, env, commonAddons, configStore); + } + + public ProfileTabs(View tabLayoutContainer, State state, UserManagerState userManagerState, + NavigationViewManager.Environment env, + AbstractActionHandler.CommonAddons commonAddons, ConfigStore configStore) { + this(tabLayoutContainer, state, null, userManagerState, env, commonAddons, configStore); + } + + public ProfileTabs(View tabLayoutContainer, State state, @Nullable UserIdManager userIdManager, + @Nullable UserManagerState userManagerState, NavigationViewManager.Environment env, + AbstractActionHandler.CommonAddons commonAddons, ConfigStore configStore) { mTabsContainer = checkNotNull(tabLayoutContainer); mTabs = tabLayoutContainer.findViewById(R.id.tabs); mState = checkNotNull(state); mEnv = checkNotNull(env); mCommonAddons = checkNotNull(commonAddons); - mUserIdManager = checkNotNull(userIdManager); + mConfigStore = configStore; + if (mConfigStore.isPrivateSpaceInDocsUIEnabled()) { + mUserIdManager = userIdManager; + mUserManagerState = checkNotNull(userManagerState); + } else { + mUserIdManager = checkNotNull(userIdManager); + mUserManagerState = userManagerState; + } mTabs.removeAllTabs(); mUserIds = Collections.singletonList(UserId.CURRENT_USER); mTabSeparator = tabLayoutContainer.findViewById(R.id.tab_separator); @@ -92,7 +119,7 @@ public class ProfileTabs implements ProfileTabsAddons { } /** - * Update the tab layout based on conditions. + * Update the tab layout based on status of availability of the hidden profile. */ public void updateView() { updateTabsIfNeeded(); @@ -110,13 +137,13 @@ public class ProfileTabs implements ProfileTabsAddons { // Material next changes apply only for version S or greater if (SdkLevel.isAtLeastS()) { mTabSeparator.setVisibility(View.GONE); - int tabContainerHeightInDp = (int)mTabsContainer.getContext().getResources(). - getDimension(R.dimen.tab_container_height); + int tabContainerHeightInDp = (int) mTabsContainer.getContext().getResources() + .getDimension(R.dimen.tab_container_height); mTabsContainer.getLayoutParams().height = tabContainerHeightInDp; ViewGroup.MarginLayoutParams tabContainerMarginLayoutParams = - (ViewGroup.MarginLayoutParams) mTabsContainer.getLayoutParams(); - int tabContainerMarginTop = (int)mTabsContainer.getContext().getResources(). - getDimension(R.dimen.profile_tab_margin_top); + (ViewGroup.MarginLayoutParams) mTabsContainer.getLayoutParams(); + int tabContainerMarginTop = (int) mTabsContainer.getContext().getResources() + .getDimension(R.dimen.profile_tab_margin_top); tabContainerMarginLayoutParams.setMargins(0, tabContainerMarginTop, 0, 0); mTabsContainer.requestLayout(); for (int i = 0; i < mTabs.getTabCount(); i++) { @@ -127,11 +154,18 @@ public class ProfileTabs implements ProfileTabsAddons { // Get individual tab to set the style ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) tab.getLayoutParams(); - int tabMarginSide = (int)mTabsContainer.getContext().getResources(). - getDimension(R.dimen.profile_tab_margin_side); - marginLayoutParams.setMargins(tabMarginSide, 0, tabMarginSide, 0); - int tabHeightInDp = (int)mTabsContainer.getContext().getResources(). - getDimension(R.dimen.tab_height); + int tabMarginSide = (int) mTabsContainer.getContext().getResources() + .getDimension(R.dimen.profile_tab_margin_side); + if (useMaterial3()) { + // M3 uses the margin value as the right margin, except for the last child. + if (i != mTabs.getTabCount() - 1) { + marginLayoutParams.setMargins(0, 0, tabMarginSide, 0); + } + } else { + marginLayoutParams.setMargins(tabMarginSide, 0, tabMarginSide, 0); + } + int tabHeightInDp = (int) mTabsContainer.getContext().getResources() + .getDimension(R.dimen.tab_height); tab.getLayoutParams().height = tabHeightInDp; tab.requestLayout(); tab.setBackgroundResource(R.drawable.tab_border_rounded); @@ -145,25 +179,56 @@ public class ProfileTabs implements ProfileTabsAddons { } private void updateTabsIfNeeded() { - List<UserId> userIds = mUserIdManager.getUserIds(); + List<UserId> userIds = getUserIds(); // Add tabs if the userIds is not equals to cached mUserIds. // Given that mUserIds was initialized with only the current user, if getUserIds() // returns just the current user, we don't need to do anything on the tab layout. if (!userIds.equals(mUserIds)) { - mUserIds = userIds; + mUserIds = new ArrayList<>(); + mUserIds.addAll(userIds); mTabs.removeAllTabs(); if (mUserIds.size() > 1) { - // set setSelected to false otherwise it will trigger callback. - mTabs.addTab(createTab( - getEnterpriseString(PERSONAL_TAB, R.string.personal_tab), - mUserIdManager.getSystemUser()), /* setSelected= */false); - mTabs.addTab(createTab( - getEnterpriseString(WORK_TAB, R.string.work_tab), - mUserIdManager.getManagedUser()), /* setSelected= */false); + if (mConfigStore.isPrivateSpaceInDocsUIEnabled() && SdkLevel.isAtLeastS()) { + addTabsPrivateSpaceEnabled(); + } else { + addTabsPrivateSpaceDisabled(); + } } } } + private List<UserId> getUserIds() { + if (mConfigStore.isPrivateSpaceInDocsUIEnabled() && SdkLevel.isAtLeastS()) { + assert mUserManagerState != null; + return mUserManagerState.getUserIds(); + } + assert mUserIdManager != null; + return mUserIdManager.getUserIds(); + } + + @RequiresApi(Build.VERSION_CODES.S) + private void addTabsPrivateSpaceEnabled() { + // set setSelected to false otherwise it will trigger callback. + assert mUserManagerState != null; + Map<UserId, String> userIdToLabelMap = mUserManagerState.getUserIdToLabelMap(); + UserManager userManager = mTabsContainer.getContext().getSystemService(UserManager.class); + assert userManager != null; + for (UserId userId : mUserIds) { + mTabs.addTab(createTab(userIdToLabelMap.get(userId), userId), /* setSelected= */false); + } + } + + private void addTabsPrivateSpaceDisabled() { + // set setSelected to false otherwise it will trigger callback. + assert mUserIdManager != null; + mTabs.addTab(createTab( + getEnterpriseString(PERSONAL_TAB, R.string.personal_tab), + mUserIdManager.getSystemUser()), /* setSelected= */false); + mTabs.addTab(createTab( + getEnterpriseString(WORK_TAB, R.string.work_tab), + mUserIdManager.getManagedUser()), /* setSelected= */false); + } + private String getEnterpriseString(String updatableStringId, int defaultStringId) { if (SdkLevel.isAtLeastT()) { return getUpdatableEnterpriseString(updatableStringId, defaultStringId); diff --git a/src/com/android/documentsui/RecentsLoader.java b/src/com/android/documentsui/RecentsLoader.java index 62ea6d05f..9a3e06fba 100644 --- a/src/com/android/documentsui/RecentsLoader.java +++ b/src/com/android/documentsui/RecentsLoader.java @@ -35,14 +35,15 @@ import java.util.concurrent.Executor; public class RecentsLoader extends MultiRootDocumentsLoader { + private static final String TAG = "RecentsLoader"; /** Ignore documents older than this age. */ - private static final long REJECT_OLDER_THAN = 45 * DateUtils.DAY_IN_MILLIS; + public static final long REJECT_OLDER_THAN = 45 * DateUtils.DAY_IN_MILLIS; - /** MIME types that should always be excluded from recents. */ + /** MIME types that should always be excluded from the Recents view. */ private static final String[] REJECT_MIMES = new String[]{Document.MIME_TYPE_DIR}; /** Maximum documents from a single root. */ - private static final int MAX_DOCS_FROM_ROOT = 64; + public static final int MAX_DOCS_FROM_ROOT = 64; private final UserId mUserId; diff --git a/src/com/android/documentsui/UserManagerState.java b/src/com/android/documentsui/UserManagerState.java new file mode 100644 index 000000000..b1c1a0d59 --- /dev/null +++ b/src/com/android/documentsui/UserManagerState.java @@ -0,0 +1,665 @@ +/* + * 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.documentsui; + +import static androidx.core.util.Preconditions.checkNotNull; + +import static com.android.documentsui.DevicePolicyResources.Drawables.Style.SOLID_COLORED; +import static com.android.documentsui.DevicePolicyResources.Drawables.WORK_PROFILE_ICON; +import static com.android.documentsui.DevicePolicyResources.Strings.PERSONAL_TAB; +import static com.android.documentsui.DevicePolicyResources.Strings.WORK_TAB; +import static com.android.documentsui.base.SharedMinimal.DEBUG; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.ActivityManager; +import android.app.admin.DevicePolicyManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.UserProperties; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.UserHandle; +import android.os.UserManager; +import android.util.Log; + +import androidx.annotation.GuardedBy; +import androidx.annotation.RequiresApi; +import androidx.annotation.VisibleForTesting; + +import com.android.documentsui.base.Features; +import com.android.documentsui.base.UserId; +import com.android.documentsui.util.CrossProfileUtils; +import com.android.documentsui.util.VersionUtils; +import com.android.modules.utils.build.SdkLevel; + +import com.google.common.base.Objects; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RequiresApi(Build.VERSION_CODES.S) +public interface UserManagerState { + + /** + * Returns the {@link UserId} of each profile which should be queried for documents. This will + * always + * include {@link UserId#CURRENT_USER}. + */ + List<UserId> getUserIds(); + + /** + * Returns mapping between the {@link UserId} and the label for the profile + */ + Map<UserId, String> getUserIdToLabelMap(); + + /** + * Returns mapping between the {@link UserId} and the drawable badge for the profile + * + * returns {@code null} for non-profile userId + */ + Map<UserId, Drawable> getUserIdToBadgeMap(); + + /** + * Returns a map of {@link UserId} to boolean value indicating whether + * the {@link UserId}.CURRENT_USER can forward {@link Intent} to that {@link UserId} + */ + Map<UserId, Boolean> getCanForwardToProfileIdMap(Intent intent); + + /** + * Updates the state of the list of userIds and all the associated maps according the intent + * received in broadcast + * + * @param userId {@link UserId} for the profile for which the availability status changed + * @param action {@link Intent}.ACTION_PROFILE_UNAVAILABLE and {@link + * Intent}.ACTION_PROFILE_AVAILABLE, {@link Intent}.ACTION_PROFILE_ADDED} and {@link + * Intent}.ACTION_PROFILE_REMOVED} + */ + void onProfileActionStatusChange(String action, UserId userId); + + /** + * Sets the intent that triggered the launch of the DocsUI + */ + void setCurrentStateIntent(Intent intent); + + /** Returns true if there are hidden profiles */ + boolean areHiddenInQuietModeProfilesPresent(); + + /** + * Creates an implementation of {@link UserManagerState}. + */ + // TODO: b/314746383 Make this class a singleton + static UserManagerState create(Context context) { + return new RuntimeUserManagerState(context); + } + + /** + * Implementation of {@link UserManagerState} + */ + final class RuntimeUserManagerState implements UserManagerState { + + private static final String TAG = "UserManagerState"; + private final Context mContext; + private final UserId mCurrentUser; + private final boolean mIsDeviceSupported; + private final UserManager mUserManager; + private final ConfigStore mConfigStore; + /** + * List of all the {@link UserId} that have the {@link UserProperties.ShowInSharingSurfaces} + * set as `SHOW_IN_SHARING_SURFACES_SEPARATE` OR it is a system/personal user + */ + @GuardedBy("mUserIds") + private final List<UserId> mUserIds = new ArrayList<>(); + /** + * Mapping between the {@link UserId} to the corresponding profile label + */ + @GuardedBy("mUserIdToLabelMap") + private final Map<UserId, String> mUserIdToLabelMap = new HashMap<>(); + /** + * Mapping between the {@link UserId} to the corresponding profile badge + */ + @GuardedBy("mUserIdToBadgeMap") + private final Map<UserId, Drawable> mUserIdToBadgeMap = new HashMap<>(); + /** + * Map containing {@link UserId}, other than that of the current user, as key and boolean + * denoting whether it is accessible by the current user or not as value + */ + @GuardedBy("mCanFrowardToProfileIdMap") + private final Map<UserId, Boolean> mCanFrowardToProfileIdMap = new HashMap<>(); + + private Intent mCurrentStateIntent; + + private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + synchronized (mUserIds) { + mUserIds.clear(); + } + synchronized (mUserIdToLabelMap) { + mUserIdToLabelMap.clear(); + } + synchronized (mUserIdToBadgeMap) { + mUserIdToBadgeMap.clear(); + } + synchronized (mCanFrowardToProfileIdMap) { + mCanFrowardToProfileIdMap.clear(); + } + } + }; + + + private RuntimeUserManagerState(Context context) { + this(context, UserId.CURRENT_USER, + Features.CROSS_PROFILE_TABS && isDeviceSupported(context), + DocumentsApplication.getConfigStore()); + } + + @VisibleForTesting + RuntimeUserManagerState(Context context, UserId currentUser, boolean isDeviceSupported, + ConfigStore configStore) { + mContext = context.getApplicationContext(); + mCurrentUser = checkNotNull(currentUser); + mIsDeviceSupported = isDeviceSupported; + mUserManager = mContext.getSystemService(UserManager.class); + mConfigStore = configStore; + + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); + filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); + if (SdkLevel.isAtLeastV() && mConfigStore.isPrivateSpaceInDocsUIEnabled()) { + filter.addAction(Intent.ACTION_PROFILE_ADDED); + filter.addAction(Intent.ACTION_PROFILE_REMOVED); + } + mContext.registerReceiver(mIntentReceiver, filter); + } + + @Override + public List<UserId> getUserIds() { + synchronized (mUserIds) { + if (mUserIds.isEmpty()) { + mUserIds.addAll(getUserIdsInternal()); + } + return mUserIds; + } + } + + @Override + public Map<UserId, String> getUserIdToLabelMap() { + synchronized (mUserIdToLabelMap) { + if (mUserIdToLabelMap.isEmpty()) { + getUserIdToLabelMapInternal(); + } + return mUserIdToLabelMap; + } + } + + @Override + public Map<UserId, Drawable> getUserIdToBadgeMap() { + synchronized (mUserIdToBadgeMap) { + if (mUserIdToBadgeMap.isEmpty()) { + getUserIdToBadgeMapInternal(); + } + return mUserIdToBadgeMap; + } + } + + @Override + public Map<UserId, Boolean> getCanForwardToProfileIdMap(Intent intent) { + synchronized (mCanFrowardToProfileIdMap) { + if (mCanFrowardToProfileIdMap.isEmpty()) { + getCanForwardToProfileIdMapInternal(intent); + } + return mCanFrowardToProfileIdMap; + } + } + + @Override + @SuppressLint("NewApi") + public void onProfileActionStatusChange(String action, UserId userId) { + if (!SdkLevel.isAtLeastV()) return; + UserProperties userProperties = mUserManager.getUserProperties( + UserHandle.of(userId.getIdentifier())); + if (userProperties.getShowInQuietMode() != UserProperties.SHOW_IN_QUIET_MODE_HIDDEN) { + return; + } + if (Intent.ACTION_PROFILE_UNAVAILABLE.equals(action) + || Intent.ACTION_PROFILE_REMOVED.equals(action)) { + synchronized (mUserIds) { + mUserIds.remove(userId); + } + } else if (Intent.ACTION_PROFILE_AVAILABLE.equals(action) + || Intent.ACTION_PROFILE_ADDED.equals(action)) { + synchronized (mUserIds) { + if (!mUserIds.contains(userId)) { + mUserIds.add(userId); + } + } + synchronized (mUserIdToLabelMap) { + if (!mUserIdToLabelMap.containsKey(userId)) { + mUserIdToLabelMap.put(userId, getProfileLabel(userId)); + } + } + synchronized (mUserIdToBadgeMap) { + if (!mUserIdToBadgeMap.containsKey(userId)) { + mUserIdToBadgeMap.put(userId, getProfileBadge(userId)); + } + } + synchronized (mCanFrowardToProfileIdMap) { + if (!mCanFrowardToProfileIdMap.containsKey(userId)) { + if (userId.getIdentifier() == ActivityManager.getCurrentUser() + || isCrossProfileContentSharingStrategyDelegatedFromParent( + UserHandle.of(userId.getIdentifier())) + || CrossProfileUtils.getCrossProfileResolveInfo(mCurrentUser, + mContext.getPackageManager(), mCurrentStateIntent, mContext, + mConfigStore.isPrivateSpaceInDocsUIEnabled()) != null) { + mCanFrowardToProfileIdMap.put(userId, true); + } else { + mCanFrowardToProfileIdMap.put(userId, false); + } + + } + } + } else { + Log.e(TAG, "Unexpected action received: " + action); + } + } + + @Override + public void setCurrentStateIntent(Intent intent) { + mCurrentStateIntent = intent; + } + + @Override + public boolean areHiddenInQuietModeProfilesPresent() { + if (!SdkLevel.isAtLeastV()) { + return false; + } + + for (UserId userId : getUserIds()) { + if (mUserManager + .getUserProperties(UserHandle.of(userId.getIdentifier())) + .getShowInQuietMode() + == UserProperties.SHOW_IN_QUIET_MODE_HIDDEN) { + return true; + } + } + return false; + } + + private List<UserId> getUserIdsInternal() { + final List<UserId> result = new ArrayList<>(); + + if (!mIsDeviceSupported) { + result.add(mCurrentUser); + return result; + } + + if (mUserManager == null) { + Log.e(TAG, "cannot obtain user manager"); + result.add(mCurrentUser); + return result; + } + + final List<UserHandle> userProfiles = mUserManager.getUserProfiles(); + if (userProfiles.size() < 2) { + result.add(mCurrentUser); + return result; + } + + if (SdkLevel.isAtLeastV()) { + getUserIdsInternalPostV(userProfiles, result); + } else { + getUserIdsInternalPreV(userProfiles, result); + } + return result; + } + + @SuppressLint("NewApi") + private void getUserIdsInternalPostV(List<UserHandle> userProfiles, List<UserId> result) { + for (UserHandle userHandle : userProfiles) { + if (userHandle.getIdentifier() == ActivityManager.getCurrentUser()) { + result.add(UserId.of(userHandle)); + } else { + // Out of all the profiles returned by user manager the profiles that are + // returned should satisfy both the following conditions: + // 1. It has user property SHOW_IN_SHARING_SURFACES_SEPARATE + // 2. Quite mode is not enabled, if it is enabled then the profile's user + // property is not SHOW_IN_QUIET_MODE_HIDDEN + if (isProfileAllowed(userHandle)) { + result.add(UserId.of(userHandle)); + } + } + } + if (result.isEmpty()) { + result.add(mCurrentUser); + } + } + + @SuppressLint("NewApi") + private boolean isProfileAllowed(UserHandle userHandle) { + final UserProperties userProperties = + mUserManager.getUserProperties(userHandle); + if (userProperties.getShowInSharingSurfaces() + == UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE) { + return !UserId.of(userHandle).isQuietModeEnabled(mContext) + || userProperties.getShowInQuietMode() + != UserProperties.SHOW_IN_QUIET_MODE_HIDDEN; + } + return false; + } + + private void getUserIdsInternalPreV(List<UserHandle> userProfiles, List<UserId> result) { + result.add(mCurrentUser); + UserId systemUser = null; + UserId managedUser = null; + for (UserHandle userHandle : userProfiles) { + if (userHandle.isSystem()) { + systemUser = UserId.of(userHandle); + } else if (mUserManager.isManagedProfile(userHandle.getIdentifier())) { + managedUser = UserId.of(userHandle); + } + } + if (mCurrentUser.isSystem() && managedUser != null) { + result.add(managedUser); + } else if (mCurrentUser.isManagedProfile(mUserManager) && systemUser != null) { + result.add(0, systemUser); + } else { + if (DEBUG) { + Log.w(TAG, "The current user " + UserId.CURRENT_USER + + " is neither system nor managed user. has system user: " + + (systemUser != null)); + } + } + } + + private void getUserIdToLabelMapInternal() { + if (SdkLevel.isAtLeastV()) { + getUserIdToLabelMapInternalPostV(); + } else { + getUserIdToLabelMapInternalPreV(); + } + } + + @SuppressLint("NewApi") + private void getUserIdToLabelMapInternalPostV() { + if (mUserManager == null) { + Log.e(TAG, "cannot obtain user manager"); + return; + } + List<UserId> userIds = getUserIds(); + for (UserId userId : userIds) { + synchronized (mUserIdToLabelMap) { + mUserIdToLabelMap.put(userId, getProfileLabel(userId)); + } + } + } + + private void getUserIdToLabelMapInternalPreV() { + if (mUserManager == null) { + Log.e(TAG, "cannot obtain user manager"); + return; + } + List<UserId> userIds = getUserIds(); + for (UserId userId : userIds) { + if (mUserManager.isManagedProfile(userId.getIdentifier())) { + synchronized (mUserIdToLabelMap) { + mUserIdToLabelMap.put(userId, + getEnterpriseString(WORK_TAB, R.string.work_tab)); + } + } else { + synchronized (mUserIdToLabelMap) { + mUserIdToLabelMap.put(userId, + getEnterpriseString(PERSONAL_TAB, R.string.personal_tab)); + } + } + } + } + + @SuppressLint("NewApi") + private String getProfileLabel(UserId userId) { + if (userId.getIdentifier() == ActivityManager.getCurrentUser()) { + return getEnterpriseString(PERSONAL_TAB, R.string.personal_tab); + } + try { + Context userContext = mContext.createContextAsUser( + UserHandle.of(userId.getIdentifier()), 0 /* flags */); + UserManager userManagerAsUser = userContext.getSystemService(UserManager.class); + if (userManagerAsUser == null) { + Log.e(TAG, "cannot obtain user manager"); + return null; + } + return userManagerAsUser.getProfileLabel(); + } catch (Exception e) { + Log.e(TAG, "Exception occurred while trying to get profile label:\n" + e); + return null; + } + } + + private String getEnterpriseString(String updatableStringId, int defaultStringId) { + if (SdkLevel.isAtLeastT()) { + return getUpdatableEnterpriseString(updatableStringId, defaultStringId); + } else { + return mContext.getString(defaultStringId); + } + } + + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + private String getUpdatableEnterpriseString(String updatableStringId, int defaultStringId) { + DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class); + if (Objects.equal(dpm, null)) { + Log.e(TAG, "can not get device policy manager"); + return mContext.getString(defaultStringId); + } + return dpm.getResources().getString( + updatableStringId, + () -> mContext.getString(defaultStringId)); + } + + private void getUserIdToBadgeMapInternal() { + if (SdkLevel.isAtLeastV()) { + getUserIdToBadgeMapInternalPostV(); + } else { + getUserIdToBadgeMapInternalPreV(); + } + } + + @SuppressLint("NewApi") + private void getUserIdToBadgeMapInternalPostV() { + if (mUserManager == null) { + Log.e(TAG, "cannot obtain user manager"); + return; + } + List<UserId> userIds = getUserIds(); + for (UserId userId : userIds) { + synchronized (mUserIdToBadgeMap) { + mUserIdToBadgeMap.put(userId, getProfileBadge(userId)); + } + } + } + + private void getUserIdToBadgeMapInternalPreV() { + if (!SdkLevel.isAtLeastR()) return; + if (mUserManager == null) { + Log.e(TAG, "cannot obtain user manager"); + return; + } + List<UserId> userIds = getUserIds(); + for (UserId userId : userIds) { + if (mUserManager.isManagedProfile(userId.getIdentifier())) { + synchronized (mUserIdToBadgeMap) { + mUserIdToBadgeMap.put(userId, + SdkLevel.isAtLeastT() ? getWorkProfileBadge() + : mContext.getDrawable(R.drawable.ic_briefcase)); + } + } + } + } + + @SuppressLint("NewApi") + private Drawable getProfileBadge(UserId userId) { + if (userId.getIdentifier() == ActivityManager.getCurrentUser()) { + return null; + } + try { + Context userContext = mContext.createContextAsUser( + UserHandle.of(userId.getIdentifier()), 0 /* flags */); + UserManager userManagerAsUser = userContext.getSystemService(UserManager.class); + if (userManagerAsUser == null) { + Log.e(TAG, "cannot obtain user manager"); + return null; + } + return userManagerAsUser.getUserBadge(); + } catch (Exception e) { + Log.e(TAG, "Exception occurred while trying to get profile badge:\n" + e); + return null; + } + } + + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + private Drawable getWorkProfileBadge() { + DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class); + Drawable drawable = dpm.getResources().getDrawable(WORK_PROFILE_ICON, SOLID_COLORED, + () -> + mContext.getDrawable(R.drawable.ic_briefcase)); + return drawable; + } + + private void getCanForwardToProfileIdMapInternal(Intent intent) { + // Versions less than V will not have the user properties required to determine whether + // cross profile check is delegated from parent or not + if (!SdkLevel.isAtLeastV()) { + getCanForwardToProfileIdMapPreV(intent); + return; + } + if (mUserManager == null) { + Log.e(TAG, "can not get user manager"); + return; + } + + List<UserId> parentOrDelegatedFromParent = new ArrayList<>(); + List<UserId> canForwardToProfileIds = new ArrayList<>(); + List<UserId> noDelegation = new ArrayList<>(); + + List<UserId> userIds = getUserIds(); + for (UserId userId : userIds) { + final UserHandle userHandle = UserHandle.of(userId.getIdentifier()); + // Parent (personal) profile and all the child profiles that delegate cross profile + // content sharing check to parent can share among each other + if (userId.getIdentifier() == ActivityManager.getCurrentUser() + || isCrossProfileContentSharingStrategyDelegatedFromParent(userHandle)) { + parentOrDelegatedFromParent.add(userId); + } else { + noDelegation.add(userId); + } + } + + if (noDelegation.size() > 1) { + Log.e(TAG, "There cannot be more than one profile delegating cross profile " + + "content sharing check from self."); + } + + /* + * Cross profile resolve info need to be checked in the following 2 cases: + * 1. current user is either parent or delegates check to parent and the target user + * does not delegate to parent + * 2. current user does not delegate check to the parent and the target user is the + * parent profile + */ + UserId needToCheck = null; + if (parentOrDelegatedFromParent.contains(mCurrentUser) + && !noDelegation.isEmpty()) { + needToCheck = noDelegation.get(0); + } else if (mCurrentUser.getIdentifier() != ActivityManager.getCurrentUser()) { + final UserHandle parentProfile = mUserManager.getProfileParent( + UserHandle.of(mCurrentUser.getIdentifier())); + needToCheck = UserId.of(parentProfile); + } + + if (needToCheck != null && CrossProfileUtils.getCrossProfileResolveInfo(mCurrentUser, + mContext.getPackageManager(), intent, mContext, + mConfigStore.isPrivateSpaceInDocsUIEnabled()) != null) { + if (parentOrDelegatedFromParent.contains(needToCheck)) { + canForwardToProfileIds.addAll(parentOrDelegatedFromParent); + } else { + canForwardToProfileIds.add(needToCheck); + } + } + + if (parentOrDelegatedFromParent.contains(mCurrentUser)) { + canForwardToProfileIds.addAll(parentOrDelegatedFromParent); + } + + for (UserId userId : userIds) { + synchronized (mCanFrowardToProfileIdMap) { + if (userId.equals(mCurrentUser)) { + mCanFrowardToProfileIdMap.put(userId, true); + continue; + } + mCanFrowardToProfileIdMap.put(userId, canForwardToProfileIds.contains(userId)); + } + } + } + + @SuppressLint("NewApi") + private boolean isCrossProfileContentSharingStrategyDelegatedFromParent( + UserHandle userHandle) { + if (mUserManager == null) { + Log.e(TAG, "can not obtain user manager"); + return false; + } + UserProperties userProperties = mUserManager.getUserProperties(userHandle); + if (java.util.Objects.equals(userProperties, null)) { + Log.e(TAG, "can not obtain user properties"); + return false; + } + + return userProperties.getCrossProfileContentSharingStrategy() + == UserProperties.CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT; + } + + private void getCanForwardToProfileIdMapPreV(Intent intent) { + // There only two profiles pre V + List<UserId> userIds = getUserIds(); + for (UserId userId : userIds) { + synchronized (mCanFrowardToProfileIdMap) { + if (mCurrentUser.equals(userId)) { + mCanFrowardToProfileIdMap.put(userId, true); + } else { + mCanFrowardToProfileIdMap.put(userId, + CrossProfileUtils.getCrossProfileResolveInfo( + mCurrentUser, mContext.getPackageManager(), intent, + mContext, mConfigStore.isPrivateSpaceInDocsUIEnabled()) + != null); + } + } + } + } + + private static boolean isDeviceSupported(Context context) { + // The feature requires Android R DocumentsContract APIs and INTERACT_ACROSS_USERS_FULL + // permission. + return VersionUtils.isAtLeastR() + && context.checkSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS) + == PackageManager.PERMISSION_GRANTED; + } + } +} diff --git a/src/com/android/documentsui/archives/Archive.java b/src/com/android/documentsui/archives/Archive.java index 7c0f47147..9889631ea 100644 --- a/src/com/android/documentsui/archives/Archive.java +++ b/src/com/android/documentsui/archives/Archive.java @@ -16,6 +16,8 @@ package com.android.documentsui.archives; +import static com.android.documentsui.base.SharedMinimal.DEBUG; + import android.content.Context; import android.content.res.AssetFileDescriptor; import android.database.Cursor; @@ -29,23 +31,23 @@ import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; import android.text.TextUtils; +import android.util.Log; import android.webkit.MimeTypeMap; import androidx.annotation.GuardedBy; import androidx.annotation.Nullable; -import androidx.core.util.Preconditions; + +import org.apache.commons.compress.archivers.ArchiveEntry; import java.io.Closeable; import java.io.File; import java.io.FileNotFoundException; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; - /** * Provides basic implementation for creating, extracting and accessing * files within archives exposed by a document provider. @@ -55,7 +57,7 @@ import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; public abstract class Archive implements Closeable { private static final String TAG = "Archive"; - public static final String[] DEFAULT_PROJECTION = new String[] { + public static final String[] DEFAULT_PROJECTION = new String[]{ Document.COLUMN_DOCUMENT_ID, Document.COLUMN_DISPLAY_NAME, Document.COLUMN_MIME_TYPE, @@ -90,28 +92,85 @@ public abstract class Archive implements Closeable { mEntries = new HashMap<>(); } - /** - * Returns a valid, normalized path for an entry. - */ + /** Returns a valid, normalized path for an entry. */ public static String getEntryPath(ArchiveEntry entry) { - if (entry instanceof ZipArchiveEntry) { - /** - * Some of archive entry doesn't have the same naming rule. - * For example: The name of 7 zip directory entry doesn't end with '/'. - * Only check for Zip archive. - */ - Preconditions.checkArgument(entry.isDirectory() == entry.getName().endsWith("/"), - "Ill-formated ZIP-file."); + final List<String> parts = new ArrayList<String>(); + boolean isDir = true; + + // Get the path that will be decomposed and normalized + final String in = entry.getName(); + + decompose: + for (int i = 0; i < in.length(); ) { + // Skip separators + if (in.charAt(i) == '/') { + isDir = true; + do { + if (++i == in.length()) break decompose; + } while (in.charAt(i) == '/'); + } + + // Found the beginning of a part + final int b = i; + assert (b < in.length()); + assert (in.charAt(b) != '/'); + + // Find the end of the part + do { + ++i; + } while (i < in.length() && in.charAt(i) != '/'); + + // Extract part + final String part = in.substring(b, i); + assert (!part.isEmpty()); + + // Special case if part is "." + if (part.equals(".")) { + isDir = true; + continue; + } + + // Special case if part is ".." + if (part.equals("..")) { + isDir = true; + if (!parts.isEmpty()) parts.remove(parts.size() - 1); + continue; + } + + // The part is either a directory or a file name + isDir = false; + parts.add(part); } - if (entry.getName().startsWith("/")) { - return entry.getName(); - } else { - return "/" + entry.getName(); + + // If the decomposed path looks like a directory but the archive entry says that it is not + // a directory entry, append "?" for the file name + if (isDir && !entry.isDirectory()) { + isDir = false; + parts.add("?"); } + + if (parts.isEmpty()) return "/"; + + // Construct the normalized path + final StringBuilder sb = new StringBuilder(in.length() + 3); + + for (final String part : parts) { + sb.append('/'); + sb.append(part); + } + + if (entry.isDirectory()) { + sb.append('/'); + } + + final String out = sb.toString(); + if (DEBUG) Log.d(TAG, "getEntryPath(" + in + ") -> " + out); + return out; } /** * Returns true if the file descriptor is seekable. + * * @param descriptor File descriptor to check. */ public static boolean canSeek(ParcelFileDescriptor descriptor) { diff --git a/src/com/android/documentsui/archives/ReadableArchive.java b/src/com/android/documentsui/archives/ReadableArchive.java index 302f582f5..ad9c8242e 100644 --- a/src/com/android/documentsui/archives/ReadableArchive.java +++ b/src/com/android/documentsui/archives/ReadableArchive.java @@ -105,10 +105,10 @@ public class ReadableArchive extends Archive { continue; } entryPath = getEntryPath(entry); - if (mEntries.containsKey(entryPath)) { - throw new IOException("Multiple entries with the same name are not supported."); + if (mEntries.putIfAbsent(entryPath, entry) != null) { + if (DEBUG) Log.d(TAG, "Ignored conflicting entry for '" + entryPath + "'"); + continue; } - mEntries.put(entryPath, entry); if (entry.isDirectory()) { mTree.put(entryPath, new ArrayList<ArchiveEntry>()); } diff --git a/src/com/android/documentsui/base/Menus.java b/src/com/android/documentsui/base/Menus.java index eba240c83..6ceea3269 100644 --- a/src/com/android/documentsui/base/Menus.java +++ b/src/com/android/documentsui/base/Menus.java @@ -19,6 +19,8 @@ package com.android.documentsui.base; import android.view.Menu; import android.view.MenuItem; +import androidx.annotation.NonNull; + public final class Menus { private Menus() {} @@ -41,7 +43,7 @@ public final class Menus { } /** Set enabled/disabled state of a menuItem, and updates its visibility. */ - public static void setEnabledAndVisible(MenuItem item, boolean enabled) { + public static void setEnabledAndVisible(@NonNull MenuItem item, boolean enabled) { item.setEnabled(enabled); item.setVisible(enabled); } diff --git a/src/com/android/documentsui/base/Shared.java b/src/com/android/documentsui/base/Shared.java index 5ac9de4d7..ac089999f 100644 --- a/src/com/android/documentsui/base/Shared.java +++ b/src/com/android/documentsui/base/Shared.java @@ -17,11 +17,10 @@ package com.android.documentsui.base; import static com.android.documentsui.base.SharedMinimal.TAG; +import static com.android.documentsui.ChangeIds.RESTRICT_STORAGE_ACCESS_FRAMEWORK; import android.app.Activity; import android.app.compat.CompatChanges; -import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledAfter; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -143,16 +142,6 @@ public final class Shared { private static final Collator sCollator; - /** - * We support restrict Storage Access Framework from {@link android.os.Build.VERSION_CODES#R}. - * App Compatibility flag that indicates whether the app should be restricted or not. - * This flag is turned on by default for all apps targeting > - * {@link android.os.Build.VERSION_CODES#Q}. - */ - @ChangeId - @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.Q) - private static final long RESTRICT_STORAGE_ACCESS_FRAMEWORK = 141600225L; - static { sCollator = Collator.getInstance(); sCollator.setStrength(Collator.SECONDARY); diff --git a/src/com/android/documentsui/base/State.java b/src/com/android/documentsui/base/State.java index cff5ce480..a3d0f9ddc 100644 --- a/src/com/android/documentsui/base/State.java +++ b/src/com/android/documentsui/base/State.java @@ -23,6 +23,7 @@ import android.util.SparseArray; import androidx.annotation.IntDef; +import com.android.documentsui.ConfigStore; import com.android.documentsui.services.FileOperationService; import com.android.documentsui.services.FileOperationService.OpType; import com.android.documentsui.sorting.SortModel; @@ -33,6 +34,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.Map; public class State implements android.os.Parcelable { @@ -47,7 +49,9 @@ public class State implements android.os.Parcelable { ACTION_OPEN_TREE }) @Retention(RetentionPolicy.SOURCE) - public @interface ActionType {} + public @interface ActionType { + } + // File manager and related private picking activity. public static final int ACTION_BROWSE = 1; public static final int ACTION_PICK_COPY_DESTINATION = 2; @@ -63,7 +67,9 @@ public class State implements android.os.Parcelable { MODE_GRID }) @Retention(RetentionPolicy.SOURCE) - public @interface ViewMode {} + public @interface ViewMode { + } + public static final int MODE_UNKNOWN = 0; public static final int MODE_LIST = 1; public static final int MODE_GRID = 2; @@ -85,6 +91,7 @@ public class State implements android.os.Parcelable { public boolean openableOnly; public boolean restrictScopeStorage; public boolean showHiddenFiles; + public ConfigStore configStore = new ConfigStore.ConfigStoreImpl(); /** * Represents whether the state supports cross-profile file picking. @@ -100,10 +107,22 @@ public class State implements android.os.Parcelable { * Returns true if we are allowed to interact with the user. */ public boolean canInteractWith(UserId userId) { + if (configStore.isPrivateSpaceInDocsUIEnabled()) { + if (canForwardToProfileIdMap.isEmpty() && UserId.CURRENT_USER.equals(userId)) { + return true; + } + return canForwardToProfileIdMap.getOrDefault(userId, false); + } return canShareAcrossProfile || UserId.CURRENT_USER.equals(userId); } /** + * Represents whether the intent can be forwarded to the {@link UserId} in the map + */ + public Map<UserId, Boolean> canForwardToProfileIdMap = new HashMap<>(); + + + /** * This is basically a sub-type for the copy operation. It can be either COPY, * COMPRESS, EXTRACT or MOVE. * The only legal values, if set, are: OPERATION_COPY, OPERATION_COMPRESS, @@ -125,12 +144,13 @@ public class State implements android.os.Parcelable { if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) { acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES); } else { - acceptMimes = new String[] { defaultAcceptMimeType }; + acceptMimes = new String[]{defaultAcceptMimeType}; } } /** * Check current action should have preview function or not. + * * @return True, if the action should have preview. */ public boolean shouldShowPreview() { @@ -141,6 +161,7 @@ public class State implements android.os.Parcelable { /** * Check the action is file picking and acceptMimes are all images type or not. + * * @return True, if acceptMimes are all image type and action is file picking. */ public boolean isPhotoPicking() { diff --git a/src/com/android/documentsui/base/UserId.java b/src/com/android/documentsui/base/UserId.java index 642ebe636..21842917a 100644 --- a/src/com/android/documentsui/base/UserId.java +++ b/src/com/android/documentsui/base/UserId.java @@ -149,8 +149,8 @@ public final class UserId { * Returns true if the this user is in quiet mode. */ public boolean isQuietModeEnabled(Context context) { - final UserManager userManager = - (UserManager) context.getSystemService(Context.USER_SERVICE); + final UserManager userManager = context.getSystemService(UserManager.class); + assert userManager != null; return userManager.isQuietModeEnabled(mUserHandle); } diff --git a/src/com/android/documentsui/dirlist/AppsRowManager.java b/src/com/android/documentsui/dirlist/AppsRowManager.java index 60138f69e..53e9bd44d 100644 --- a/src/com/android/documentsui/dirlist/AppsRowManager.java +++ b/src/com/android/documentsui/dirlist/AppsRowManager.java @@ -16,7 +16,8 @@ package com.android.documentsui.dirlist; -import android.os.UserManager; +import static com.android.documentsui.flags.Flags.useMaterial3; + import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; @@ -26,8 +27,10 @@ import android.widget.TextView; import com.android.documentsui.ActionHandler; import com.android.documentsui.BaseActivity; +import com.android.documentsui.ConfigStore; import com.android.documentsui.R; import com.android.documentsui.UserIdManager; +import com.android.documentsui.UserManagerState; import com.android.documentsui.base.State; import com.android.documentsui.base.UserId; import com.android.documentsui.dirlist.AppsRowItemData.AppData; @@ -35,6 +38,7 @@ import com.android.documentsui.dirlist.AppsRowItemData.RootData; import com.android.documentsui.sidebar.AppItem; import com.android.documentsui.sidebar.Item; import com.android.documentsui.sidebar.RootItem; +import com.android.modules.utils.build.SdkLevel; import java.util.ArrayList; import java.util.HashMap; @@ -43,6 +47,7 @@ import java.util.Map; /** * A manager class stored apps row chip data list. Data will be synced by RootsFragment. + * TODO(b/379776735): Remove this after M3 uplift. */ public class AppsRowManager { @@ -50,13 +55,27 @@ public class AppsRowManager { private final List<AppsRowItemData> mDataList; private final boolean mMaybeShowBadge; private final UserIdManager mUserIdManager; + private final UserManagerState mUserManagerState; + private final ConfigStore mConfigStore; public AppsRowManager(ActionHandler handler, boolean maybeShowBadge, - UserIdManager userIdManager) { + UserIdManager userIdManager, ConfigStore configStore) { mDataList = new ArrayList<>(); mActionHandler = handler; mMaybeShowBadge = maybeShowBadge; mUserIdManager = userIdManager; + mUserManagerState = null; + mConfigStore = configStore; + } + + public AppsRowManager(ActionHandler handler, boolean maybeShowBadge, + UserManagerState userManagerState, ConfigStore configStore) { + mDataList = new ArrayList<>(); + mActionHandler = handler; + mMaybeShowBadge = maybeShowBadge; + mUserIdManager = null; + mUserManagerState = userManagerState; + mConfigStore = configStore; } public List<AppsRowItemData> updateList(List<Item> itemList) { @@ -86,10 +105,14 @@ public class AppsRowManager { } private boolean shouldShow(State state, boolean isSearchExpanded) { + if (useMaterial3()) { + return false; + } + boolean isHiddenAction = state.action == State.ACTION_CREATE || state.action == State.ACTION_OPEN_TREE || state.action == State.ACTION_PICK_COPY_DESTINATION; - boolean isSearchExpandedAcrossProfile = mUserIdManager.getUserIds().size() > 1 + boolean isSearchExpandedAcrossProfile = getUserIds().size() > 1 && state.supportsCrossProfile() && isSearchExpanded; @@ -134,4 +157,11 @@ public class AppsRowManager { summary.setVisibility(data.getSummary() != null ? View.VISIBLE : View.GONE); view.setOnClickListener(v -> data.onClicked()); } + + private List<UserId> getUserIds() { + if (mConfigStore.isPrivateSpaceInDocsUIEnabled() && SdkLevel.isAtLeastS()) { + return mUserManagerState.getUserIds(); + } + return mUserIdManager.getUserIds(); + } } diff --git a/src/com/android/documentsui/dirlist/DirectoryAddonsAdapter.java b/src/com/android/documentsui/dirlist/DirectoryAddonsAdapter.java index 7bccbac4e..8989853a0 100644 --- a/src/com/android/documentsui/dirlist/DirectoryAddonsAdapter.java +++ b/src/com/android/documentsui/dirlist/DirectoryAddonsAdapter.java @@ -16,19 +16,24 @@ package com.android.documentsui.dirlist; +import android.os.UserManager; import android.view.ViewGroup; +import androidx.annotation.Nullable; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver; +import com.android.documentsui.ConfigStore; import com.android.documentsui.Model; import com.android.documentsui.Model.Update; import com.android.documentsui.base.EventListener; import com.android.documentsui.base.State; +import com.android.documentsui.base.UserId; import com.android.documentsui.dirlist.Message.HeaderMessage; import com.android.documentsui.dirlist.Message.InflateMessage; import java.util.List; +import java.util.Map; /** * Adapter wrapper that embellishes the directory list by inserting Holder views inbetween @@ -47,14 +52,30 @@ final class DirectoryAddonsAdapter extends DocumentsAdapter { // now. private final Message mHeaderMessage; private final Message mInflateMessage; + private final ConfigStore mConfigStore; - DirectoryAddonsAdapter(Environment environment, DocumentsAdapter delegate) { + DirectoryAddonsAdapter(Environment environment, DocumentsAdapter delegate, + ConfigStore configStore) { + this(environment, delegate, null, null, null, null, configStore); + } + + DirectoryAddonsAdapter(Environment environment, DocumentsAdapter delegate, + @Nullable UserId sourceUserId, @Nullable UserId selectedUserId, + @Nullable Map<UserId, String> userIdLabelMap, @Nullable UserManager userManager, + ConfigStore configStore) { mEnv = environment; mDelegate = delegate; + mConfigStore = configStore; // TODO: We should not instantiate the messages here, but rather instantiate them // when we get an update event. - mHeaderMessage = new HeaderMessage(environment, this::onDismissHeaderMessage); - mInflateMessage = new InflateMessage(environment, this::onDismissHeaderMessage); + mHeaderMessage = new HeaderMessage(environment, this::onDismissHeaderMessage, mConfigStore); + if (mConfigStore.isPrivateSpaceInDocsUIEnabled()) { + mInflateMessage = new InflateMessage(environment, this::onDismissHeaderMessage, + sourceUserId, selectedUserId, userIdLabelMap, userManager, mConfigStore); + } else { + mInflateMessage = new InflateMessage(environment, this::onDismissHeaderMessage, + mConfigStore); + } // Relay events published by our delegate to our listeners (presumably RecyclerView) // with adjusted positions. @@ -98,15 +119,15 @@ final class DirectoryAddonsAdapter extends DocumentsAdapter { DocumentHolder holder = null; switch (viewType) { case ITEM_TYPE_SECTION_BREAK: - holder = new TransparentDividerDocumentHolder(mEnv.getContext()); + holder = new TransparentDividerDocumentHolder(mEnv.getContext(), mConfigStore); mEnv.initDocumentHolder(holder); break; case ITEM_TYPE_HEADER_MESSAGE: - holder = new HeaderMessageDocumentHolder(mEnv.getContext(), parent); + holder = new HeaderMessageDocumentHolder(mEnv.getContext(), parent, mConfigStore); mEnv.initDocumentHolder(holder); break; case ITEM_TYPE_INFLATED_MESSAGE: - holder = new InflateMessageDocumentHolder(mEnv.getContext(), parent); + holder = new InflateMessageDocumentHolder(mEnv.getContext(), parent, mConfigStore); mEnv.initDocumentHolder(holder); break; default: @@ -295,13 +316,13 @@ final class DirectoryAddonsAdapter extends DocumentsAdapter { @Override public void onItemRangeChanged(int positionStart, int itemCount, Object payload) { - assert(itemCount == 1); + assert (itemCount == 1); notifyItemRangeChanged(toViewPosition(positionStart), itemCount, payload); } @Override public void onItemRangeInserted(int positionStart, int itemCount) { - assert(itemCount == 1); + assert (itemCount == 1); if (positionStart < mBreakPosition) { mBreakPosition++; } @@ -310,7 +331,7 @@ final class DirectoryAddonsAdapter extends DocumentsAdapter { @Override public void onItemRangeRemoved(int positionStart, int itemCount) { - assert(itemCount == 1); + assert (itemCount == 1); if (positionStart < mBreakPosition) { mBreakPosition--; } diff --git a/src/com/android/documentsui/dirlist/DirectoryFragment.java b/src/com/android/documentsui/dirlist/DirectoryFragment.java index a5306bd97..ffa912c51 100644 --- a/src/com/android/documentsui/dirlist/DirectoryFragment.java +++ b/src/com/android/documentsui/dirlist/DirectoryFragment.java @@ -21,6 +21,7 @@ import static com.android.documentsui.base.SharedMinimal.DEBUG; import static com.android.documentsui.base.SharedMinimal.VERBOSE; import static com.android.documentsui.base.State.MODE_GRID; import static com.android.documentsui.base.State.MODE_LIST; +import static com.android.documentsui.flags.Flags.desktopFileHandling; import android.app.ActivityManager; import android.content.BroadcastReceiver; @@ -28,6 +29,7 @@ import android.content.ContentProviderClient; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.UserProperties; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; @@ -35,6 +37,7 @@ import android.os.Handler; import android.os.Looper; import android.os.Parcelable; import android.os.UserHandle; +import android.os.UserManager; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; import android.util.Log; @@ -110,8 +113,9 @@ import com.android.documentsui.services.FileOperationService.OpType; import com.android.documentsui.services.FileOperations; import com.android.documentsui.sorting.SortDimension; import com.android.documentsui.sorting.SortModel; - import com.android.documentsui.util.VersionUtils; +import com.android.modules.utils.build.SdkLevel; + import com.google.common.base.Objects; import java.io.IOException; @@ -132,7 +136,8 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On REQUEST_COPY_DESTINATION }) @Retention(RetentionPolicy.SOURCE) - public @interface RequestCode {} + public @interface RequestCode { + } public static final int REQUEST_COPY_DESTINATION = 1; @@ -236,33 +241,90 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); - if (isManagedProfileAction(action)) { - UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER); - UserId userId = UserId.of(userHandle); - if (Objects.equal(mActivity.getSelectedUser(), userId)) { - // We only need to refresh the layout when the selected user is equal to the - // received profile user. - if (Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) { - // If the managed profile is turned off, we need to refresh the directory - // to update the UI to show an appropriate error message. - if (mProviderTestRunnable != null) { - mHandler.removeCallbacks(mProviderTestRunnable); - mProviderTestRunnable = null; - } - onRefresh(); - return; - } + if (SdkLevel.isAtLeastV() + && mState.configStore.isPrivateSpaceInDocsUIEnabled()) { + profileStatusReceiverPostV(intent, action); + } else { + profileStatusReceiverPreV(intent, action); + } + } - // When the managed profile becomes available, the provider may not be available - // immediately, we need to check if it is ready before we reload the content. - if (Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action)) { - checkUriAndScheduleCheckIfNeeded(userId); - } + private void profileStatusReceiverPostV(Intent intent, String action) { + if (!SdkLevel.isAtLeastV()) return; + if (!isProfileStatusAction(action)) return; + UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER); + UserId userId = UserId.of(userHandle); + UserManager userManager = mActivity.getSystemService(UserManager.class); + if (userManager == null) { + Log.e(TAG, "cannot obtain user manager"); + return; + } + UserProperties userProperties = userManager.getUserProperties(userHandle); + if (userProperties.getShowInQuietMode() + == UserProperties.SHOW_IN_QUIET_MODE_PAUSED) { + if (Objects.equal(mActivity.getSelectedUser(), userId)) { + // We only need to refresh the layout when the selected user is equal to + // the received profile user. + onPausedProfileStatusChange(action, userId); } + return; + } + if (userProperties.getShowInQuietMode() + == UserProperties.SHOW_IN_QUIET_MODE_HIDDEN) { + onHiddenProfileStatusChange(action, userId); + } + } + + private void profileStatusReceiverPreV(Intent intent, String action) { + if (!isManagedProfileAction(action)) return; + UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER); + UserId userId = UserId.of(userHandle); + if (Objects.equal(mActivity.getSelectedUser(), userId)) { + // We only need to refresh the layout when the selected user is equal to the + // received profile user. + onPausedProfileStatusChange(action, userId); } } }; + private void onPausedProfileStatusChange(String action, UserId userId) { + if (Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action) + || (SdkLevel.isAtLeastV() && Intent.ACTION_PROFILE_UNAVAILABLE.equals(action))) { + // If the managed/paused profile is turned off, we need to refresh the directory + // to update the UI to show an appropriate error message. + if (mProviderTestRunnable != null) { + mHandler.removeCallbacks(mProviderTestRunnable); + mProviderTestRunnable = null; + } + onRefresh(); + return; + } + + // When the managed/paused profile becomes available, the provider may not be available + // immediately, we need to check if it is ready before we reload the content. + if (Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action) + || (SdkLevel.isAtLeastV() && Intent.ACTION_PROFILE_AVAILABLE.equals(action))) { + checkUriAndScheduleCheckIfNeeded(userId); + } + } + + private void onHiddenProfileStatusChange(String action, UserId userId) { + mActivity.updateRecentsSetting(); + if (Intent.ACTION_PROFILE_UNAVAILABLE.equals(action)) { + if (mProviderTestRunnable != null) { + mHandler.removeCallbacks(mProviderTestRunnable); + mProviderTestRunnable = null; + } + if (!mActivity.isSearchExpanded()) { + if (mActivity.getLastSelectedUser() != null + && mActivity.getLastSelectedUser().equals(userId)) { + mState.stack.reset(mActivity.getInitialStack()); + } + mActivity.refreshCurrentRootAndDirectory(AnimationView.ANIM_NONE); + } + } + } + private final BroadcastReceiver mSdCardBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -288,7 +350,7 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On mHandler.removeCallbacks(mProviderTestRunnable); mProviderTestRunnable = null; } - mHandler.post(() -> onRefresh()); + mHandler.post(this::onRefresh); } else { checkUriWithDelay(/* numOfRetries= */1, uri, userId); } @@ -326,8 +388,8 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On private boolean isProviderAvailable(Uri uri, UserId userId) { try (ContentProviderClient userClient = - DocumentsApplication.acquireUnstableProviderOrThrow( - userId.getContentResolver(mActivity), uri.getAuthority())) { + DocumentsApplication.acquireUnstableProviderOrThrow( + userId.getContentResolver(mActivity), uri.getAuthority())) { Cursor testCursor = userClient.query(uri, /* projection= */ null, /* queryArgs= */null, /* cancellationSignal= */ null); if (testCursor != null) { @@ -339,6 +401,14 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On return false; } + private boolean isProfileStatusAction(String action) { + if (!SdkLevel.isAtLeastV()) return isManagedProfileAction(action); + return Intent.ACTION_PROFILE_AVAILABLE.equals(action) + || Intent.ACTION_PROFILE_UNAVAILABLE.equals(action) + || Intent.ACTION_PROFILE_ADDED.equals(action) + || Intent.ACTION_PROFILE_REMOVED.equals(action); + } + private static boolean isManagedProfileAction(String action) { return Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action) || Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action); @@ -445,12 +515,10 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On mLocalState.mSelectionId = Integer.toHexString(System.identityHashCode(mRecView)); } - mIconHelper = new IconHelper(mActivity, MODE_GRID, mState.supportsCrossProfile()); + mIconHelper = new IconHelper(mActivity, MODE_GRID, mState.supportsCrossProfile(), + mState.configStore); - mAdapter = new DirectoryAddonsAdapter( - mAdapterEnv, - new ModelBackedDocumentsAdapter(mAdapterEnv, mIconHelper, mInjector.fileTypeLookup) - ); + mAdapter = getModelBackedDocumentsAdapter(); mRecView.setAdapter(mAdapter); @@ -486,14 +554,14 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On DragStartListener dragStartListener = mInjector.config.dragAndDropEnabled() ? DragStartListener.create( - mIconHelper, - mModel, - mSelectionMgr, - mSelectionMetadata, - mState, - this::getModelId, - mRecView::findChildViewUnder, - DocumentsApplication.getDragAndDropManager(mActivity)) + mIconHelper, + mModel, + mSelectionMgr, + mSelectionMetadata, + mState, + this::getModelId, + mRecView::findChildViewUnder, + DocumentsApplication.getDragAndDropManager(mActivity)) : DragStartListener.STUB; { @@ -505,16 +573,16 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On new DocsStableIdProvider(mAdapter), mDetailsLookup, StorageStrategy.createStringStorage()) - .withBandOverlay(R.drawable.band_select_overlay) - .withFocusDelegate(mFocusManager) - .withOnDragInitiatedListener(dragStartListener::onDragEvent) - .withOnContextClickListener(this::onContextMenuClick) - .withOnItemActivatedListener(this::onItemActivated) - .withOperationMonitor(mContentLock.getMonitor()) - .withSelectionPredicate(selectionPredicate) - .withGestureTooltypes(MotionEvent.TOOL_TYPE_FINGER, - MotionEvent.TOOL_TYPE_STYLUS) - .build(); + .withBandOverlay(R.drawable.band_select_overlay) + .withFocusDelegate(mFocusManager) + .withOnDragInitiatedListener(dragStartListener::onDragEvent) + .withOnContextClickListener(this::onContextMenuClick) + .withOnItemActivatedListener(this::onItemActivated) + .withOperationMonitor(mContentLock.getMonitor()) + .withSelectionPredicate(selectionPredicate) + .withGestureTooltypes(MotionEvent.TOOL_TYPE_FINGER, + MotionEvent.TOOL_TYPE_STYLUS) + .build(); mInjector.updateSharedSelectionTracker(localTracker); } @@ -573,6 +641,12 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On final IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED); filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); + if (SdkLevel.isAtLeastV()) { + filter.addAction(Intent.ACTION_PROFILE_AVAILABLE); + filter.addAction(Intent.ACTION_PROFILE_UNAVAILABLE); + filter.addAction(Intent.ACTION_PROFILE_ADDED); + filter.addAction(Intent.ACTION_PROFILE_REMOVED); + } // DocumentsApplication will resend the broadcast locally after roots are updated. // Register to a local broadcast manager to avoid this fragment from updating before // roots are updated. @@ -581,6 +655,23 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On getContext().registerReceiver(mSdCardBroadcastReceiver, getSdCardStateChangeFilter()); } + private DocumentsAdapter getModelBackedDocumentsAdapter() { + if (SdkLevel.isAtLeastS() && mState.configStore.isPrivateSpaceInDocsUIEnabled()) { + return new DirectoryAddonsAdapter( + mAdapterEnv, new ModelBackedDocumentsAdapter(mAdapterEnv, mIconHelper, + mInjector.fileTypeLookup, mState.configStore), + UserId.CURRENT_USER, + mActivity.getSelectedUser(), + DocumentsApplication.getUserManagerState(getContext()).getUserIdToLabelMap(), + getContext().getSystemService(UserManager.class), mState.configStore); + } + return new DirectoryAddonsAdapter( + mAdapterEnv, + new ModelBackedDocumentsAdapter(mAdapterEnv, mIconHelper, + mInjector.fileTypeLookup, mState.configStore), + mState.configStore); + } + @Override public void onStart() { super.onStart(); @@ -737,7 +828,7 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On /** * Updates the layout after the view mode switches. * - * @param mode The new view mode. + * @param scale The new view mode. */ private void scaleLayout(float scale) { assert DEBUG; @@ -833,127 +924,111 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On MutableSelection<String> selection = new MutableSelection<>(); mSelectionMgr.copySelection(selection); - switch (item.getItemId()) { - case R.id.action_menu_select: - case R.id.dir_menu_open: - openDocuments(selection); - mActionModeController.finishActionMode(); - return true; - - case R.id.action_menu_open_with: - case R.id.dir_menu_open_with: - showChooserForDoc(selection); - return true; - - case R.id.dir_menu_open_in_new_window: - mActions.openSelectedInNewWindow(); - return true; - - case R.id.action_menu_share: - case R.id.dir_menu_share: - mActions.shareSelectedDocuments(); - return true; - - case R.id.action_menu_delete: - case R.id.dir_menu_delete: - // deleteDocuments will end action mode if the documents are deleted. - // It won't end action mode if user cancels the delete. - mActions.showDeleteDialog(); - return true; - - case R.id.action_menu_copy_to: - transferDocuments(selection, null, FileOperationService.OPERATION_COPY); - // TODO: Only finish selection mode if copy-to is not canceled. - // Need to plum down into handling the way we do with deleteDocuments. - mActionModeController.finishActionMode(); - return true; - - case R.id.action_menu_compress: - transferDocuments(selection, mState.stack, - FileOperationService.OPERATION_COMPRESS); - // TODO: Only finish selection mode if compress is not canceled. - // Need to plum down into handling the way we do with deleteDocuments. - mActionModeController.finishActionMode(); - return true; + final int id = item.getItemId(); + if (desktopFileHandling() && id == R.id.dir_menu_open) { + // On desktop, "open" is displayed in file management mode (i.e. `files.MenuManager`). + // This menu item behaves the same as double click on the menu item which is handled by + // onItemActivated but since onItemActivated requires a RecylcerView ItemDetails, we're + // using viewDocument that takes a Selection. + viewDocument(selection); + return true; + } else if (id == R.id.action_menu_select || id == R.id.dir_menu_open) { + // Note: this code path is never executed for `dir_menu_open`. The menu item is always + // hidden unless the desktopFileHandling flag is enabled, in which case the menu item + // will be handled by the condition above. + openDocuments(selection); + mActionModeController.finishActionMode(); + return true; + } else if (id == R.id.action_menu_open_with || id == R.id.dir_menu_open_with) { + showChooserForDoc(selection); + return true; + } else if (id == R.id.dir_menu_open_in_new_window) { + mActions.openSelectedInNewWindow(); + return true; + } else if (id == R.id.action_menu_share || id == R.id.dir_menu_share) { + mActions.shareSelectedDocuments(); + return true; + } else if (id == R.id.action_menu_delete || id == R.id.dir_menu_delete) { + // deleteDocuments will end action mode if the documents are deleted. + // It won't end action mode if user cancels the delete. + mActions.showDeleteDialog(); + return true; + } else if (id == R.id.action_menu_copy_to) { + transferDocuments(selection, null, FileOperationService.OPERATION_COPY); + // TODO: Only finish selection mode if copy-to is not canceled. + // Need to plum down into handling the way we do with deleteDocuments. + mActionModeController.finishActionMode(); + return true; + } else if (id == R.id.action_menu_compress || id == R.id.dir_menu_compress) { + transferDocuments(selection, mState.stack, + FileOperationService.OPERATION_COMPRESS); + // TODO: Only finish selection mode if compress is not canceled. + // Need to plum down into handling the way we do with deleteDocuments. + mActionModeController.finishActionMode(); + return true; // TODO: Implement extract (to the current directory). - case R.id.action_menu_extract_to: - transferDocuments(selection, null, FileOperationService.OPERATION_EXTRACT); - // TODO: Only finish selection mode if compress-to is not canceled. - // Need to plum down into handling the way we do with deleteDocuments. - mActionModeController.finishActionMode(); - return true; - - case R.id.action_menu_move_to: - if (mModel.hasDocuments(selection, DocumentFilters.NOT_MOVABLE)) { - mInjector.dialogs.showOperationUnsupported(); - return true; - } - // Exit selection mode first, so we avoid deselecting deleted documents. - mActionModeController.finishActionMode(); - transferDocuments(selection, null, FileOperationService.OPERATION_MOVE); - return true; - - case R.id.action_menu_inspect: - case R.id.dir_menu_inspect: - mActionModeController.finishActionMode(); - assert selection.size() <= 1; - DocumentInfo doc = selection.isEmpty() - ? mActivity.getCurrentDirectory() - : mModel.getDocuments(selection).get(0); - - mActions.showInspector(doc); - return true; - - case R.id.dir_menu_cut_to_clipboard: - mActions.cutToClipboard(); - return true; - - case R.id.dir_menu_copy_to_clipboard: - mActions.copyToClipboard(); - return true; - - case R.id.dir_menu_paste_from_clipboard: - pasteFromClipboard(); - return true; - - case R.id.dir_menu_paste_into_folder: - pasteIntoFolder(); - return true; - - case R.id.action_menu_select_all: - case R.id.dir_menu_select_all: - mActions.selectAllFiles(); - return true; - - case R.id.action_menu_deselect_all: - case R.id.dir_menu_deselect_all: - mActions.deselectAllFiles(); - return true; - - case R.id.action_menu_rename: - case R.id.dir_menu_rename: - renameDocuments(selection); - return true; - - case R.id.dir_menu_create_dir: - mActions.showCreateDirectoryDialog(); - return true; - - case R.id.dir_menu_view_in_owner: - mActions.viewInOwner(); - return true; - - case R.id.action_menu_sort: - mActions.showSortDialog(); + } else if (id == R.id.action_menu_extract_to || id == R.id.option_menu_extract_all) { + transferDocuments(selection, null, FileOperationService.OPERATION_EXTRACT); + // TODO: Only finish selection mode if compress-to is not canceled. + // Need to plum down into handling the way we do with deleteDocuments. + mActionModeController.finishActionMode(); + return true; + } else if (id == R.id.action_menu_move_to) { + if (mModel.hasDocuments(selection, DocumentFilters.NOT_MOVABLE)) { + mInjector.dialogs.showOperationUnsupported(); return true; + } + // Exit selection mode first, so we avoid deselecting deleted documents. + mActionModeController.finishActionMode(); + transferDocuments(selection, null, FileOperationService.OPERATION_MOVE); + return true; + } else if (id == R.id.action_menu_inspect || id == R.id.dir_menu_inspect) { + mActionModeController.finishActionMode(); + assert selection.size() <= 1; + DocumentInfo doc = selection.isEmpty() + ? mActivity.getCurrentDirectory() + : mModel.getDocuments(selection).get(0); + + mActions.showPreview(doc); + return true; + } else if (id == R.id.dir_menu_cut_to_clipboard) { + mActions.cutToClipboard(); + return true; + } else if (id == R.id.dir_menu_copy_to_clipboard) { + mActions.copyToClipboard(); + return true; + } else if (id == R.id.dir_menu_paste_from_clipboard) { + pasteFromClipboard(); + return true; + } else if (id == R.id.dir_menu_paste_into_folder) { + pasteIntoFolder(); + return true; + } else if (id == R.id.action_menu_select_all || id == R.id.dir_menu_select_all) { + mActions.selectAllFiles(); + return true; + } else if (id == R.id.action_menu_deselect_all || id == R.id.dir_menu_deselect_all) { + mActions.deselectAllFiles(); + return true; + } else if (id == R.id.action_menu_rename || id == R.id.dir_menu_rename) { + renameDocuments(selection); + return true; + } else if (id == R.id.dir_menu_create_dir) { + mActions.showCreateDirectoryDialog(); + return true; + } else if (id == R.id.dir_menu_view_in_owner) { + mActions.viewInOwner(); + return true; + } else if (id == R.id.action_menu_sort) { + mActions.showSortDialog(); + return true; + } - default: - if (DEBUG) { - Log.d(TAG, "Unhandled menu item selected: " + item); - } - return false; + if (DEBUG) { + Log.d(TAG, "Cannot handle unexpected menu item " + id); } + + return false; } private boolean onAccessibilityClick(View child) { @@ -1018,6 +1093,20 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On mActions.showChooserForDoc(doc); } + private void viewDocument(final Selection<String> selected) { + Metrics.logUserAction(MetricConsts.USER_ACTION_OPEN); + + if (selected.isEmpty()) { + return; + } + + assert selected.size() == 1; + DocumentInfo doc = + DocumentInfo.fromDirectoryCursor(mModel.getItem(selected.iterator().next())); + + mActions.openDocumentViewOnly(doc); + } + private void transferDocuments( final Selection<String> selected, @Nullable DocumentStack destination, final @OpType int mode) { @@ -1109,7 +1198,7 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On intent.putExtra(FileOperationService.EXTRA_OPERATION_TYPE, mode); // This just identifies the type of request...we'll check it - // when we reveive a response. + // when we receive a response. startActivityForResult(intent, REQUEST_COPY_DESTINATION); } @@ -1323,11 +1412,16 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On // Remove thumbnail cache. We do this not because we're worried about stale thumbnails as it // should be covered by last modified value we store in thumbnail cache, but rather to give // the user a greater sense that contents are being reloaded. - ThumbnailCache cache = DocumentsApplication.getThumbnailCache(getContext()); - String[] ids = mModel.getModelIds(); - int numOfEvicts = Math.min(ids.length, CACHE_EVICT_LIMIT); - for (int i = 0; i < numOfEvicts; ++i) { - cache.removeUri(mModel.getItemUri(ids[i]), mModel.getItemUserId(ids[i])); + Context context = getContext(); + if (context == null) { + Log.w(TAG, "Fragment is not attached to an activity."); + } else { + ThumbnailCache cache = DocumentsApplication.getThumbnailCache(context); + String[] ids = mModel.getModelIds(); + int numOfEvicts = Math.min(ids.length, CACHE_EVICT_LIMIT); + for (int i = 0; i < numOfEvicts; ++i) { + cache.removeUri(mModel.getItemUri(ids[i]), mModel.getItemUserId(ids[i])); + } } final DocumentInfo doc = mActivity.getCurrentDirectory(); @@ -1358,7 +1452,6 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On mRefreshLayout.setRefreshing(false); if (rootDoc != null && mActivity.getCurrentDirectory() == null) { // Make sure the stack does not change during task was running. - Log.d(TAG, "Root doc is retrieved. Pushing to the stack"); mState.stack.push(rootDoc); mActivity.updateNavigator(); mActions.loadDocumentsForCurrentStack(); diff --git a/src/com/android/documentsui/dirlist/DocumentHolder.java b/src/com/android/documentsui/dirlist/DocumentHolder.java index 5e38b4882..69058fb5a 100644 --- a/src/com/android/documentsui/dirlist/DocumentHolder.java +++ b/src/com/android/documentsui/dirlist/DocumentHolder.java @@ -18,6 +18,7 @@ package com.android.documentsui.dirlist; import static com.android.documentsui.DevicePolicyResources.Strings.PREVIEW_WORK_FILE_ACCESSIBILITY; import static com.android.documentsui.DevicePolicyResources.Strings.UNDEFINED; +import static com.android.documentsui.flags.Flags.useMaterial3; import android.app.admin.DevicePolicyManager; import android.content.Context; @@ -36,9 +37,13 @@ import androidx.annotation.RequiresApi; import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; import androidx.recyclerview.widget.RecyclerView; +import com.android.documentsui.ConfigStore; +import com.android.documentsui.DocumentsApplication; import com.android.documentsui.R; +import com.android.documentsui.UserManagerState; import com.android.documentsui.base.Shared; import com.android.documentsui.base.State; +import com.android.documentsui.base.UserId; import com.android.modules.utils.build.SdkLevel; import java.util.function.Function; @@ -51,37 +56,36 @@ import javax.annotation.Nullable; public abstract class DocumentHolder extends RecyclerView.ViewHolder implements View.OnKeyListener { - static final float DISABLED_ALPHA = 0.3f; + static final float DISABLED_ALPHA = useMaterial3() ? 0.6f : 0.3f; protected final Context mContext; protected @Nullable String mModelId; protected @State.ActionType int mAction; + protected final ConfigStore mConfigStore; // See #addKeyEventListener for details on the need for this field. private KeyboardEventListener<DocumentItemDetails> mKeyEventListener; private final DocumentItemDetails mDetails; - public DocumentHolder(Context context, ViewGroup parent, int layout) { - this(context, inflateLayout(context, parent, layout)); + public DocumentHolder(Context context, ViewGroup parent, int layout, ConfigStore configStore) { + this(context, inflateLayout(context, parent, layout), configStore); } - public DocumentHolder(Context context, View item) { + public DocumentHolder(Context context, View item, ConfigStore configStore) { super(item); itemView.setOnKeyListener(this); mContext = context; mDetails = new DocumentItemDetails(this); + mConfigStore = configStore; } /** * Binds the view to the given item data. - * @param cursor - * @param modelId - * @param state */ public abstract void bind(Cursor cursor, String modelId); @@ -95,10 +99,10 @@ public abstract class DocumentHolder * TODO: Use the DirectoryItemAnimator instead of manually controlling animation using a boolean * flag. * - * @param selected * @param animate Whether or not to animate the change. Only selection changes initiated by the - * selection manager should be animated. See - * {@link ModelBackedDocumentsAdapter#onBindViewHolder(DocumentHolder, int, java.util.List)} + * selection manager should be animated. See + * {@link ModelBackedDocumentsAdapter#onBindViewHolder(DocumentHolder, int, + * java.util.List)} */ public void setSelected(boolean selected, boolean animate) { itemView.setActivated(selected); @@ -113,13 +117,31 @@ public abstract class DocumentHolder mAction = action; } - public void bindPreviewIcon(boolean show, Function<View, Boolean> clickCallback) {} + /** + * @param show boolean denoting whether the current profile is non-personal + * @param clickCallback call back function + */ + public void bindPreviewIcon(boolean show, Function<View, Boolean> clickCallback) { + } + + /** + * @param show boolean denoting whether the current profile is managed + */ + public void bindBriefcaseIcon(boolean show) { + } - public void bindBriefcaseIcon(boolean show) {} + /** + * Binds profile badge icon to the documents thumbnail + * + * @param show boolean denoting whether the current profile is non-personal/parent + * @param userIdIdentifier user id of the profile the document belongs to + */ + public void bindProfileIcon(boolean show, int userIdIdentifier) { + } @Override public boolean onKey(View v, int keyCode, KeyEvent event) { - assert(mKeyEventListener != null); + assert (mKeyEventListener != null); DocumentItemDetails details = getItemDetails(); return (details == null) ? false @@ -135,7 +157,7 @@ public abstract class DocumentHolder * <p>Ideally we'd not involve DocumentHolder in propagation of events like this. */ public void addKeyEventListener(KeyboardEventListener<DocumentItemDetails> listener) { - assert(mKeyEventListener == null); + assert (mKeyEventListener == null); mKeyEventListener = listener; } @@ -179,12 +201,22 @@ public abstract class DocumentHolder return view.animate().setDuration(Shared.CHECK_ANIMATION_DURATION).alpha(alpha); } - protected String getPreviewIconContentDescription(boolean isWorkProfile, String fileName) { + protected String getPreviewIconContentDescription(boolean isNonPersonalProfile, + String fileName, UserId userId) { + if (mConfigStore.isPrivateSpaceInDocsUIEnabled() && SdkLevel.isAtLeastS()) { + UserManagerState userManagerState = DocumentsApplication.getUserManagerState(mContext); + String profileLabel = userManagerState.getUserIdToLabelMap().get(userId); + return isNonPersonalProfile + ? itemView.getResources().getString(R.string.preview_cross_profile_file, + profileLabel, fileName) + : itemView.getResources().getString(R.string.preview_file, fileName); + } if (SdkLevel.isAtLeastT()) { - return getUpdatablePreviewIconContentDescription(isWorkProfile, fileName); + return getUpdatablePreviewIconContentDescription(isNonPersonalProfile, fileName); } else { return itemView.getResources().getString( - isWorkProfile ? R.string.preview_work_file : R.string.preview_file, fileName); + isNonPersonalProfile ? R.string.preview_work_file : R.string.preview_file, + fileName); } } diff --git a/src/com/android/documentsui/dirlist/DocumentsSwipeRefreshLayout.java b/src/com/android/documentsui/dirlist/DocumentsSwipeRefreshLayout.java index 4b66b857f..92faee198 100644 --- a/src/com/android/documentsui/dirlist/DocumentsSwipeRefreshLayout.java +++ b/src/com/android/documentsui/dirlist/DocumentsSwipeRefreshLayout.java @@ -16,10 +16,13 @@ package com.android.documentsui.dirlist; +import static com.android.documentsui.flags.Flags.useMaterial3; + import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.util.Log; +import android.util.TypedValue; import android.view.MotionEvent; import androidx.annotation.ColorRes; @@ -42,20 +45,37 @@ public class DocumentsSwipeRefreshLayout extends SwipeRefreshLayout { public DocumentsSwipeRefreshLayout(Context context, AttributeSet attrs) { super(context, attrs); - final int[] styledAttrs = {android.R.attr.colorAccent}; + if (useMaterial3()) { + TypedValue spinnerColor = new TypedValue(); + context.getTheme() + .resolveAttribute( + com.google.android.material.R.attr.colorOnPrimaryContainer, + spinnerColor, + true); + setColorSchemeResources(spinnerColor.resourceId); + TypedValue spinnerBackgroundColor = new TypedValue(); + context.getTheme() + .resolveAttribute( + com.google.android.material.R.attr.colorPrimaryContainer, + spinnerBackgroundColor, + true); + setProgressBackgroundColorSchemeResource(spinnerBackgroundColor.resourceId); + } else { + final int[] styledAttrs = {android.R.attr.colorAccent}; - TypedArray a = context.obtainStyledAttributes(styledAttrs); - @ColorRes int colorId = a.getResourceId(0, -1); - if (colorId == -1) { - Log.w(TAG, "Retrieve colorAccent colorId from theme fail, assign R.color.primary"); - colorId = R.color.primary; + TypedArray a = context.obtainStyledAttributes(styledAttrs); + @ColorRes int colorId = a.getResourceId(0, -1); + if (colorId == -1) { + Log.w(TAG, "Retrieve colorAccent colorId from theme fail, assign R.color.primary"); + colorId = R.color.primary; + } + a.recycle(); + setColorSchemeResources(colorId); } - a.recycle(); - setColorSchemeResources(colorId); } @Override public boolean onInterceptTouchEvent(MotionEvent e) { return false; } -}
\ No newline at end of file +} diff --git a/src/com/android/documentsui/dirlist/GridDirectoryHolder.java b/src/com/android/documentsui/dirlist/GridDirectoryHolder.java index 744b0c9d9..7e9a32df2 100644 --- a/src/com/android/documentsui/dirlist/GridDirectoryHolder.java +++ b/src/com/android/documentsui/dirlist/GridDirectoryHolder.java @@ -35,33 +35,41 @@ import android.widget.TextView; import androidx.annotation.RequiresApi; +import com.android.documentsui.ConfigStore; +import com.android.documentsui.DocumentsApplication; import com.android.documentsui.IconUtils; import com.android.documentsui.R; import com.android.documentsui.base.State; +import com.android.documentsui.base.UserId; import com.android.documentsui.ui.Views; import com.android.modules.utils.build.SdkLevel; -final class GridDirectoryHolder extends DocumentHolder { +import java.util.Map; +final class GridDirectoryHolder extends DocumentHolder { final TextView mTitle; private final ImageView mIconCheck; private final ImageView mIconMime; - private final ImageView mIconBriefcase; + private final ImageView mIconBadge; private final View mIconLayout; - public GridDirectoryHolder(Context context, ViewGroup parent) { - super(context, parent, R.layout.item_dir_grid); + private final IconHelper mIconHelper; + + GridDirectoryHolder( + Context context, ViewGroup parent, IconHelper iconHelper, ConfigStore configStore) { + super(context, parent, R.layout.item_dir_grid, configStore); mIconLayout = itemView.findViewById(R.id.icon); mTitle = (TextView) itemView.findViewById(android.R.id.title); mIconMime = (ImageView) itemView.findViewById(R.id.icon_mime_sm); mIconCheck = (ImageView) itemView.findViewById(R.id.icon_check); - mIconBriefcase = (ImageView) itemView.findViewById(R.id.icon_briefcase); + mIconBadge = (ImageView) itemView.findViewById(R.id.icon_profile_badge); mIconMime.setImageDrawable( IconUtils.loadMimeIcon(context, DocumentsContract.Document.MIME_TYPE_DIR)); + mIconHelper = iconHelper; - if (SdkLevel.isAtLeastT()) { + if (SdkLevel.isAtLeastT() && !mConfigStore.isPrivateSpaceInDocsUIEnabled()) { setUpdatableWorkProfileIcon(context); } } @@ -71,7 +79,7 @@ final class GridDirectoryHolder extends DocumentHolder { DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); Drawable drawable = dpm.getResources().getDrawable(WORK_PROFILE_ICON, SOLID_COLORED, () -> context.getDrawable(R.drawable.ic_briefcase)); - mIconBriefcase.setImageDrawable(drawable); + mIconBadge.setImageDrawable(drawable); } @Override @@ -90,7 +98,18 @@ final class GridDirectoryHolder extends DocumentHolder { @Override public void bindBriefcaseIcon(boolean show) { - mIconBriefcase.setVisibility(show ? View.VISIBLE : View.GONE); + mIconBadge.setVisibility(show ? View.VISIBLE : View.GONE); + } + + @Override + @RequiresApi(Build.VERSION_CODES.S) + public void bindProfileIcon(boolean show, int userIdIdentifier) { + Map<UserId, Drawable> userIdToBadgeMap = DocumentsApplication.getUserManagerState( + mContext).getUserIdToBadgeMap(); + Drawable drawable = userIdToBadgeMap.get(UserId.of(userIdIdentifier)); + mIconBadge.setImageDrawable(drawable); + mIconBadge.setVisibility(show ? View.VISIBLE : View.GONE); + mIconBadge.setContentDescription(mIconHelper.getProfileLabel(userIdIdentifier)); } @Override @@ -107,12 +126,13 @@ final class GridDirectoryHolder extends DocumentHolder { /** * Bind this view to the given document for display. - * @param cursor Pointing to the item to be bound. + * + * @param cursor Pointing to the item to be bound. * @param modelId The model ID of the item. */ @Override public void bind(Cursor cursor, String modelId) { - assert(cursor != null); + assert (cursor != null); this.mModelId = modelId; diff --git a/src/com/android/documentsui/dirlist/GridDocumentHolder.java b/src/com/android/documentsui/dirlist/GridDocumentHolder.java index 2da538203..eb35b1a5f 100644 --- a/src/com/android/documentsui/dirlist/GridDocumentHolder.java +++ b/src/com/android/documentsui/dirlist/GridDocumentHolder.java @@ -37,6 +37,8 @@ import android.widget.TextView; import androidx.annotation.RequiresApi; +import com.android.documentsui.ConfigStore; +import com.android.documentsui.DocumentsApplication; import com.android.documentsui.R; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.Shared; @@ -45,6 +47,7 @@ import com.android.documentsui.roots.RootCursorWrapper; import com.android.documentsui.ui.Views; import com.android.modules.utils.build.SdkLevel; +import java.util.Map; import java.util.function.Function; final class GridDocumentHolder extends DocumentHolder { @@ -56,7 +59,7 @@ final class GridDocumentHolder extends DocumentHolder { final ImageView mIconMimeSm; final ImageView mIconThumb; final ImageView mIconCheck; - final ImageView mIconBriefcase; + final ImageView mIconBadge; final IconHelper mIconHelper; final View mIconLayout; final View mPreviewIcon; @@ -64,8 +67,9 @@ final class GridDocumentHolder extends DocumentHolder { // This is used in as a convenience in our bind method. private final DocumentInfo mDoc = new DocumentInfo(); - public GridDocumentHolder(Context context, ViewGroup parent, IconHelper iconHelper) { - super(context, parent, R.layout.item_doc_grid); + GridDocumentHolder(Context context, ViewGroup parent, IconHelper iconHelper, + ConfigStore configStore) { + super(context, parent, R.layout.item_doc_grid, configStore); mIconLayout = itemView.findViewById(R.id.icon); mTitle = (TextView) itemView.findViewById(android.R.id.title); @@ -75,12 +79,12 @@ final class GridDocumentHolder extends DocumentHolder { mIconMimeSm = (ImageView) itemView.findViewById(R.id.icon_mime_sm); mIconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb); mIconCheck = (ImageView) itemView.findViewById(R.id.icon_check); - mIconBriefcase = (ImageView) itemView.findViewById(R.id.icon_briefcase); + mIconBadge = (ImageView) itemView.findViewById(R.id.icon_profile_badge); mPreviewIcon = itemView.findViewById(R.id.preview_icon); mIconHelper = iconHelper; - if (SdkLevel.isAtLeastT()) { + if (SdkLevel.isAtLeastT() && !mConfigStore.isPrivateSpaceInDocsUIEnabled()) { setUpdatableWorkProfileIcon(context); } } @@ -90,7 +94,7 @@ final class GridDocumentHolder extends DocumentHolder { DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); Drawable drawable = dpm.getResources().getDrawable(WORK_PROFILE_ICON, SOLID_COLORED, () -> context.getDrawable(R.drawable.ic_briefcase)); - mIconBriefcase.setImageDrawable(drawable); + mIconBadge.setImageDrawable(drawable); } @Override @@ -108,7 +112,7 @@ final class GridDocumentHolder extends DocumentHolder { // But it should be an error to be set to selected && be disabled. if (!itemView.isEnabled()) { - assert(!selected); + assert (!selected); } super.setSelected(selected, animate); @@ -138,19 +142,30 @@ final class GridDocumentHolder extends DocumentHolder { mPreviewIcon.setContentDescription( getPreviewIconContentDescription( mIconHelper.shouldShowBadge(mDoc.userId.getIdentifier()), - mDoc.displayName)); + mDoc.displayName, mDoc.userId)); mPreviewIcon.setAccessibilityDelegate(new PreviewAccessibilityDelegate(clickCallback)); } } @Override public void bindBriefcaseIcon(boolean show) { - mIconBriefcase.setVisibility(show ? View.VISIBLE : View.GONE); + mIconBadge.setVisibility(show ? View.VISIBLE : View.GONE); + } + + @Override + @RequiresApi(Build.VERSION_CODES.S) + public void bindProfileIcon(boolean show, int userIdIdentifier) { + Map<UserId, Drawable> userIdToBadgeMap = DocumentsApplication.getUserManagerState( + mContext).getUserIdToBadgeMap(); + Drawable drawable = userIdToBadgeMap.get(UserId.of(userIdIdentifier)); + mIconBadge.setImageDrawable(drawable); + mIconBadge.setVisibility(show ? View.VISIBLE : View.GONE); + mIconBadge.setContentDescription(mIconHelper.getProfileLabel(userIdIdentifier)); } @Override public boolean inDragRegion(MotionEvent event) { - // Entire grid box should be draggable + // Entire grid box should be draggable return true; } @@ -166,12 +181,13 @@ final class GridDocumentHolder extends DocumentHolder { /** * Bind this view to the given document for display. - * @param cursor Pointing to the item to be bound. + * + * @param cursor Pointing to the item to be bound. * @param modelId The model ID of the item. */ @Override public void bind(Cursor cursor, String modelId) { - assert(cursor != null); + assert (cursor != null); mModelId = modelId; diff --git a/src/com/android/documentsui/dirlist/GridPhotoHolder.java b/src/com/android/documentsui/dirlist/GridPhotoHolder.java index 06185068d..e86d3131f 100644 --- a/src/com/android/documentsui/dirlist/GridPhotoHolder.java +++ b/src/com/android/documentsui/dirlist/GridPhotoHolder.java @@ -36,6 +36,8 @@ import android.widget.ImageView; import androidx.annotation.RequiresApi; +import com.android.documentsui.ConfigStore; +import com.android.documentsui.DocumentsApplication; import com.android.documentsui.R; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.Shared; @@ -44,6 +46,7 @@ import com.android.documentsui.roots.RootCursorWrapper; import com.android.documentsui.ui.Views; import com.android.modules.utils.build.SdkLevel; +import java.util.Map; import java.util.function.Function; final class GridPhotoHolder extends DocumentHolder { @@ -53,23 +56,24 @@ final class GridPhotoHolder extends DocumentHolder { private final ImageView mIconCheck; private final IconHelper mIconHelper; private final View mPreviewIcon; - private final View mIconBriefcase; + private final View mIconBadge; // This is used in as a convenience in our bind method. private final DocumentInfo mDoc = new DocumentInfo(); - public GridPhotoHolder(Context context, ViewGroup parent, IconHelper iconHelper) { - super(context, parent, R.layout.item_photo_grid); + GridPhotoHolder(Context context, ViewGroup parent, IconHelper iconHelper, + ConfigStore configStore) { + super(context, parent, R.layout.item_photo_grid, configStore); mIconMimeLg = (ImageView) itemView.findViewById(R.id.icon_mime_lg); mIconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb); mIconCheck = (ImageView) itemView.findViewById(R.id.icon_check); - mIconBriefcase = itemView.findViewById(R.id.icon_briefcase); + mIconBadge = itemView.findViewById(R.id.icon_profile_badge); mPreviewIcon = itemView.findViewById(R.id.preview_icon); mIconHelper = iconHelper; - if (SdkLevel.isAtLeastT()) { + if (SdkLevel.isAtLeastT() && !mConfigStore.isPrivateSpaceInDocsUIEnabled()) { setUpdatableWorkProfileIcon(context); } } @@ -80,7 +84,7 @@ final class GridPhotoHolder extends DocumentHolder { Drawable drawable = dpm.getResources().getDrawable( WORK_PROFILE_ICON, SOLID_NOT_COLORED, () -> context.getDrawable(R.drawable.ic_briefcase)); - ImageView icon = (ImageView) mIconBriefcase.findViewById(R.id.icon_id); + ImageView icon = (ImageView) mIconBadge.findViewById(R.id.icon_id); icon.setImageDrawable(drawable); } @@ -123,14 +127,26 @@ final class GridPhotoHolder extends DocumentHolder { mPreviewIcon.setContentDescription( getPreviewIconContentDescription( mIconHelper.shouldShowBadge(mDoc.userId.getIdentifier()), - mDoc.displayName)); + mDoc.displayName, mDoc.userId)); mPreviewIcon.setAccessibilityDelegate(new PreviewAccessibilityDelegate(clickCallback)); } } @Override public void bindBriefcaseIcon(boolean show) { - mIconBriefcase.setVisibility(show ? View.VISIBLE : View.GONE); + mIconBadge.setVisibility(show ? View.VISIBLE : View.GONE); + } + + @Override + @RequiresApi(Build.VERSION_CODES.S) + public void bindProfileIcon(boolean show, int userIdIdentifier) { + Map<UserId, Drawable> userIdToBadgeMap = DocumentsApplication.getUserManagerState( + mContext).getUserIdToBadgeMap(); + Drawable drawable = userIdToBadgeMap.get(UserId.of(userIdIdentifier)); + ImageView icon = mIconBadge.findViewById(R.id.icon_id); + icon.setImageDrawable(drawable); + mIconBadge.setVisibility(show ? View.VISIBLE : View.GONE); + mIconBadge.setContentDescription(mIconHelper.getProfileLabel(userIdIdentifier)); } @Override @@ -152,7 +168,8 @@ final class GridPhotoHolder extends DocumentHolder { /** * Bind this view to the given document for display. - * @param cursor Pointing to the item to be bound. + * + * @param cursor Pointing to the item to be bound. * @param modelId The model ID of the item. */ @Override @@ -178,8 +195,14 @@ final class GridPhotoHolder extends DocumentHolder { Formatter.formatFileSize(mContext, getCursorLong(cursor, Document.COLUMN_SIZE)); final String docDate = Shared.formatTime(mContext, mDoc.lastModified); if (mIconHelper.shouldShowBadge(mDoc.userId.getIdentifier())) { - itemView.setContentDescription((mContext.getText(R.string.a11y_work) + ", ") - + mDoc.displayName + ", " + docSize + ", " + docDate); + itemView.setContentDescription( + mIconHelper.getProfileLabel(mDoc.userId.getIdentifier()) + + ", " + + mDoc.displayName + + ", " + + docSize + + ", " + + docDate); } else { itemView.setContentDescription(mDoc.displayName + ", " + docSize + ", " + docDate); } diff --git a/src/com/android/documentsui/dirlist/HeaderMessageDocumentHolder.java b/src/com/android/documentsui/dirlist/HeaderMessageDocumentHolder.java index bb98894a3..aa4170882 100644 --- a/src/com/android/documentsui/dirlist/HeaderMessageDocumentHolder.java +++ b/src/com/android/documentsui/dirlist/HeaderMessageDocumentHolder.java @@ -26,6 +26,7 @@ import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; +import com.android.documentsui.ConfigStore; import com.android.documentsui.R; import com.android.documentsui.base.State.ViewMode; @@ -45,8 +46,8 @@ final class HeaderMessageDocumentHolder extends MessageHolder { private final Button mActionButton; private Message mMessage; - public HeaderMessageDocumentHolder(Context context, ViewGroup parent) { - super(context, parent, R.layout.item_doc_header_message); + HeaderMessageDocumentHolder(Context context, ViewGroup parent, ConfigStore configStore) { + super(context, parent, R.layout.item_doc_header_message, configStore); mRoot = itemView.findViewById(R.id.item_root); mIcon = (ImageView) itemView.findViewById(R.id.message_icon); diff --git a/src/com/android/documentsui/dirlist/IconHelper.java b/src/com/android/documentsui/dirlist/IconHelper.java index e2c990583..44d1d95d3 100644 --- a/src/com/android/documentsui/dirlist/IconHelper.java +++ b/src/com/android/documentsui/dirlist/IconHelper.java @@ -20,6 +20,7 @@ import static com.android.documentsui.base.SharedMinimal.VERBOSE; import static com.android.documentsui.base.State.MODE_GRID; import static com.android.documentsui.base.State.MODE_LIST; +import android.app.ActivityManager; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Point; @@ -34,6 +35,7 @@ import android.widget.ImageView; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import com.android.documentsui.ConfigStore; import com.android.documentsui.DocumentsApplication; import com.android.documentsui.IconUtils; import com.android.documentsui.ProviderExecutor; @@ -41,11 +43,13 @@ import com.android.documentsui.R; import com.android.documentsui.ThumbnailCache; import com.android.documentsui.ThumbnailCache.Result; import com.android.documentsui.ThumbnailLoader; +import com.android.documentsui.UserManagerState; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.MimeTypes; import com.android.documentsui.base.State; import com.android.documentsui.base.State.ViewMode; import com.android.documentsui.base.UserId; +import com.android.modules.utils.build.SdkLevel; import java.util.function.BiConsumer; @@ -66,31 +70,37 @@ public class IconHelper { private final boolean mMaybeShowBadge; @Nullable private final UserId mManagedUser; + private final UserManagerState mUserManagerState; + private final ConfigStore mConfigStore; /** - * @param context * @param mode MODE_GRID or MODE_LIST */ - public IconHelper(Context context, int mode, boolean maybeShowBadge) { + public IconHelper(Context context, int mode, boolean maybeShowBadge, ConfigStore configStore) { this(context, mode, maybeShowBadge, DocumentsApplication.getThumbnailCache(context), - DocumentsApplication.getUserIdManager(context).getManagedUser()); + configStore.isPrivateSpaceInDocsUIEnabled() ? null + : DocumentsApplication.getUserIdManager(context).getManagedUser(), + configStore.isPrivateSpaceInDocsUIEnabled() + ? DocumentsApplication.getUserManagerState(context) : null, + configStore); } @VisibleForTesting IconHelper(Context context, int mode, boolean maybeShowBadge, ThumbnailCache thumbnailCache, - @Nullable UserId managedUser) { + @Nullable UserId managedUser, @Nullable UserManagerState userManagerState, + ConfigStore configStore) { mContext = context; setViewMode(mode); mThumbnailCache = thumbnailCache; mManagedUser = managedUser; mMaybeShowBadge = maybeShowBadge; + mUserManagerState = userManagerState; + mConfigStore = configStore; } /** * Enables or disables thumbnails. When thumbnails are disabled, mime icons (or custom icons, if * specified by the document) are used instead. - * - * @param enabled */ public void setThumbnailsEnabled(boolean enabled) { mThumbnailsEnabled = enabled; @@ -99,7 +109,7 @@ public class IconHelper { /** * Sets the current display mode. This affects the thumbnail sizes that are loaded. * - * @param mode See {@link State.MODE_LIST} and {@link State.MODE_GRID}. + * @param mode See {@link State#MODE_LIST} and {@link State#MODE_GRID}. */ public void setViewMode(@ViewMode int mode) { mMode = mode; @@ -125,8 +135,6 @@ public class IconHelper { /** * Cancels any ongoing load operations associated with the given ImageView. - * - * @param icon */ public void stopLoading(ImageView icon) { final ThumbnailLoader oldTask = (ThumbnailLoader) icon.getTag(); @@ -139,11 +147,10 @@ public class IconHelper { /** * Load thumbnails for a directory list item. * - * @param doc The document - * @param iconThumb The itemview's thumbnail icon. - * @param iconMime The itemview's mime icon. Hidden when iconThumb is shown. + * @param doc The document + * @param iconThumb The itemview's thumbnail icon. + * @param iconMime The itemview's mime icon. Hidden when iconThumb is shown. * @param subIconMime The second itemview's mime icon. Always visible. - * @return */ public void load( DocumentInfo doc, @@ -157,15 +164,14 @@ public class IconHelper { /** * Load thumbnails for a directory list item. * - * @param uri The URI for the file being represented. - * @param mimeType The mime type of the file being represented. - * @param docFlags Flags for the file being represented. - * @param docIcon Custom icon (if any) for the file being requested. + * @param uri The URI for the file being represented. + * @param mimeType The mime type of the file being represented. + * @param docFlags Flags for the file being represented. + * @param docIcon Custom icon (if any) for the file being requested. * @param docLastModified the last modified value of the file being requested. - * @param iconThumb The itemview's thumbnail icon. - * @param iconMime The itemview's mime icon. Hidden when iconThumb is shown. - * @param subIconMime The second itemview's mime icon. Always visible. - * @return + * @param iconThumb The itemview's thumbnail icon. + * @param iconMime The itemview's mime icon. Hidden when iconThumb is shown. + * @param subIconMime The second itemview's mime icon. Always visible. */ public void load(Uri uri, UserId userId, String mimeType, int docFlags, int docIcon, long docLastModified, ImageView iconThumb, ImageView iconMime, @@ -180,7 +186,7 @@ public class IconHelper { final boolean showThumbnail = supportsThumbnail && allowThumbnail && mThumbnailsEnabled; if (showThumbnail) { loadedThumbnail = - loadThumbnail(uri, userId, docAuthority, docLastModified, iconThumb, iconMime); + loadThumbnail(uri, userId, docAuthority, docLastModified, iconThumb, iconMime); } final Drawable mimeIcon = getDocumentIcon(mContext, userId, docAuthority, @@ -207,9 +213,11 @@ public class IconHelper { iconThumb.setImageBitmap(cachedThumbnail); boolean stale = (docLastModified > result.getLastModified()); - if (VERBOSE) Log.v(TAG, - String.format("Load thumbnail for %s, got result %d and stale %b.", - uri.toString(), result.getStatus(), stale)); + if (VERBOSE) { + Log.v(TAG, + String.format("Load thumbnail for %s, got result %d and stale %b.", + uri.toString(), result.getStatus(), stale)); + } if (!result.isExactHit() || stale) { final BiConsumer<View, View> animator = (cachedThumbnail == null ? ThumbnailLoader.ANIM_FADE_IN : @@ -264,7 +272,21 @@ public class IconHelper { * Returns true if we should show a briefcase icon for the given user. */ public boolean shouldShowBadge(int userIdIdentifier) { + if (mConfigStore.isPrivateSpaceInDocsUIEnabled() && SdkLevel.isAtLeastS()) { + return mMaybeShowBadge + && mUserManagerState.getUserIds().size() > 1 + && ActivityManager.getCurrentUser() != userIdIdentifier; + } return mMaybeShowBadge && mManagedUser != null && mManagedUser.getIdentifier() == userIdIdentifier; } + + /** Returns label of the profile the icon belongs to. */ + public String getProfileLabel(int userIdIdentifier) { + if (SdkLevel.isAtLeastS()) { + return mUserManagerState.getUserIdToLabelMap().get(UserId.of(userIdIdentifier)); + } else { + return ""; + } + } } diff --git a/src/com/android/documentsui/dirlist/InflateMessageDocumentHolder.java b/src/com/android/documentsui/dirlist/InflateMessageDocumentHolder.java index 2e2b92128..1fbb32b49 100644 --- a/src/com/android/documentsui/dirlist/InflateMessageDocumentHolder.java +++ b/src/com/android/documentsui/dirlist/InflateMessageDocumentHolder.java @@ -25,6 +25,7 @@ import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; +import com.android.documentsui.ConfigStore; import com.android.documentsui.R; import com.android.documentsui.util.VersionUtils; @@ -52,8 +53,8 @@ final class InflateMessageDocumentHolder extends MessageHolder { private View mCrossProfileContent; private ProgressBar mCrossProfileProgress; - public InflateMessageDocumentHolder(Context context, ViewGroup parent) { - super(context, parent, R.layout.item_doc_inflated_message); + InflateMessageDocumentHolder(Context context, ViewGroup parent, ConfigStore configStore) { + super(context, parent, R.layout.item_doc_inflated_message, configStore); mContentView = itemView.findViewById(R.id.content); mCrossProfileView = itemView.findViewById(R.id.cross_profile); mCrossProfileContent = mCrossProfileView.findViewById(R.id.cross_profile_content); diff --git a/src/com/android/documentsui/dirlist/ListDocumentHolder.java b/src/com/android/documentsui/dirlist/ListDocumentHolder.java index 96c49e047..849acb5c1 100644 --- a/src/com/android/documentsui/dirlist/ListDocumentHolder.java +++ b/src/com/android/documentsui/dirlist/ListDocumentHolder.java @@ -20,6 +20,7 @@ import static com.android.documentsui.DevicePolicyResources.Drawables.Style.SOLI import static com.android.documentsui.DevicePolicyResources.Drawables.WORK_PROFILE_ICON; import static com.android.documentsui.base.DocumentInfo.getCursorInt; import static com.android.documentsui.base.DocumentInfo.getCursorString; +import static com.android.documentsui.flags.Flags.useMaterial3; import android.app.admin.DevicePolicyManager; import android.content.Context; @@ -40,6 +41,8 @@ import android.widget.TextView; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; +import com.android.documentsui.ConfigStore; +import com.android.documentsui.DocumentsApplication; import com.android.documentsui.R; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.Lookup; @@ -51,6 +54,7 @@ import com.android.documentsui.ui.Views; import com.android.modules.utils.build.SdkLevel; import java.util.ArrayList; +import java.util.Map; import java.util.function.Function; final class ListDocumentHolder extends DocumentHolder { @@ -67,7 +71,7 @@ final class ListDocumentHolder extends DocumentHolder { private final ImageView mIconMime; private final ImageView mIconThumb; private final ImageView mIconCheck; - private final ImageView mIconBriefcase; + private final ImageView mIconBadge; private final View mIconLayout; final View mPreviewIcon; @@ -77,14 +81,14 @@ final class ListDocumentHolder extends DocumentHolder { private final DocumentInfo mDoc; public ListDocumentHolder(Context context, ViewGroup parent, IconHelper iconHelper, - Lookup<String, String> fileTypeLookup) { - super(context, parent, R.layout.item_doc_list); + Lookup<String, String> fileTypeLookup, ConfigStore configStore) { + super(context, parent, R.layout.item_doc_list, configStore); mIconLayout = itemView.findViewById(R.id.icon); mIconMime = (ImageView) itemView.findViewById(R.id.icon_mime); mIconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb); mIconCheck = (ImageView) itemView.findViewById(R.id.icon_check); - mIconBriefcase = (ImageView) itemView.findViewById(R.id.icon_briefcase); + mIconBadge = (ImageView) itemView.findViewById(R.id.icon_profile_badge); mTitle = (TextView) itemView.findViewById(android.R.id.title); mSize = (TextView) itemView.findViewById(R.id.size); mDate = (TextView) itemView.findViewById(R.id.date); @@ -98,7 +102,7 @@ final class ListDocumentHolder extends DocumentHolder { mFileTypeLookup = fileTypeLookup; mDoc = new DocumentInfo(); - if (SdkLevel.isAtLeastT()) { + if (SdkLevel.isAtLeastT() && !mConfigStore.isPrivateSpaceInDocsUIEnabled()) { setUpdatableWorkProfileIcon(context); } } @@ -108,7 +112,7 @@ final class ListDocumentHolder extends DocumentHolder { DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); Drawable drawable = dpm.getResources().getDrawable(WORK_PROFILE_ICON, SOLID_COLORED, () -> context.getDrawable(R.drawable.ic_briefcase)); - mIconBriefcase.setImageDrawable(drawable); + mIconBadge.setImageDrawable(drawable); } @Override @@ -142,10 +146,14 @@ final class ListDocumentHolder extends DocumentHolder { public void setEnabled(boolean enabled) { super.setEnabled(enabled); - // Text colors enabled/disabled is handle via a color set. - final float imgAlpha = enabled ? 1f : DISABLED_ALPHA; - mIconMime.setAlpha(imgAlpha); - mIconThumb.setAlpha(imgAlpha); + if (useMaterial3()) { + itemView.setAlpha(enabled ? 1f : DISABLED_ALPHA); + } else { + // Text colors enabled/disabled is handle via a color set. + final float imgAlpha = enabled ? 1f : DISABLED_ALPHA; + mIconMime.setAlpha(imgAlpha); + mIconThumb.setAlpha(imgAlpha); + } } @Override @@ -158,7 +166,7 @@ final class ListDocumentHolder extends DocumentHolder { mPreviewIcon.setContentDescription( getPreviewIconContentDescription( mIconHelper.shouldShowBadge(mDoc.userId.getIdentifier()), - mDoc.displayName)); + mDoc.displayName, mDoc.userId)); mPreviewIcon.setAccessibilityDelegate( new PreviewAccessibilityDelegate(clickCallback)); } @@ -167,7 +175,18 @@ final class ListDocumentHolder extends DocumentHolder { @Override public void bindBriefcaseIcon(boolean show) { - mIconBriefcase.setVisibility(show ? View.VISIBLE : View.GONE); + mIconBadge.setVisibility(show ? View.VISIBLE : View.GONE); + } + + @Override + @RequiresApi(Build.VERSION_CODES.S) + public void bindProfileIcon(boolean show, int userIdIdentifier) { + Map<UserId, Drawable> userIdToBadgeMap = DocumentsApplication.getUserManagerState( + mContext).getUserIdToBadgeMap(); + Drawable drawable = userIdToBadgeMap.get(UserId.of(userIdIdentifier)); + mIconBadge.setImageDrawable(drawable); + mIconBadge.setVisibility(show ? View.VISIBLE : View.GONE); + mIconBadge.setContentDescription(mIconHelper.getProfileLabel(userIdIdentifier)); } @Override @@ -209,7 +228,7 @@ final class ListDocumentHolder extends DocumentHolder { /** * Bind this view to the given document for display. * - * @param cursor Pointing to the item to be bound. + * @param cursor Pointing to the item to be bound. * @param modelId The model ID of the item. */ @Override diff --git a/src/com/android/documentsui/dirlist/Message.java b/src/com/android/documentsui/dirlist/Message.java index ccdad461a..7b2d6c309 100644 --- a/src/com/android/documentsui/dirlist/Message.java +++ b/src/com/android/documentsui/dirlist/Message.java @@ -32,15 +32,22 @@ import static com.android.documentsui.DevicePolicyResources.Strings.WORK_PROFILE import static com.android.documentsui.DevicePolicyResources.Strings.WORK_PROFILE_OFF_ERROR_TITLE; import android.Manifest; +import android.app.ActivityManager; import android.app.AuthenticationRequiredException; import android.app.admin.DevicePolicyManager; import android.content.pm.PackageManager; +import android.content.pm.UserProperties; +import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Build; +import android.os.UserHandle; +import android.os.UserManager; +import android.util.Log; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; +import com.android.documentsui.ConfigStore; import com.android.documentsui.CrossProfileException; import com.android.documentsui.CrossProfileNoPermissionException; import com.android.documentsui.CrossProfileQuietModeException; @@ -54,11 +61,17 @@ import com.android.documentsui.base.UserId; import com.android.documentsui.dirlist.DocumentsAdapter.Environment; import com.android.modules.utils.build.SdkLevel; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + /** * Data object used by {@link InflateMessageDocumentHolder} and {@link HeaderMessageDocumentHolder}. */ abstract class Message { + private static final int ACCESS_CROSS_PROFILE_FILES = -1; + protected final Environment mEnv; // If the message has a button, this will be the default button call back. protected final Runnable mDefaultCallback; @@ -72,13 +85,15 @@ abstract class Message { private boolean mShouldShow = false; protected boolean mShouldKeep = false; protected int mLayout; + protected ConfigStore mConfigStore; - Message(Environment env, Runnable defaultCallback) { + Message(Environment env, Runnable defaultCallback, ConfigStore configStore) { mEnv = env; mDefaultCallback = defaultCallback; + mConfigStore = configStore; } - abstract void update(Update Event); + abstract void update(Update event); protected void update(@Nullable CharSequence messageTitle, CharSequence messageString, @Nullable CharSequence buttonString, Drawable icon) { @@ -121,6 +136,7 @@ abstract class Message { /** * Return this message should keep showing or not. + * * @return true if this message should keep showing. */ boolean shouldKeep() { @@ -143,8 +159,8 @@ abstract class Message { private static final String TAG = "HeaderMessage"; - HeaderMessage(Environment env, Runnable callback) { - super(env, callback); + HeaderMessage(Environment env, Runnable callback, ConfigStore configStore) { + super(env, callback, configStore); } @Override @@ -173,7 +189,7 @@ abstract class Message { } private void updateToAuthenticationExceptionHeader(Update event) { - assert(mEnv.getFeatures().isRemoteActionsEnabled()); + assert (mEnv.getFeatures().isRemoteActionsEnabled()); RootInfo root = mEnv.getDisplayState().stack.getRoot(); String appName = DocumentsApplication.getProvidersCache( @@ -199,15 +215,57 @@ abstract class Message { final static class InflateMessage extends Message { + private static final String TAG = "InflateMessage"; + private UserId mSourceUserId = null; + private UserId mSelectedUserId = null; + private Map<UserId, String> mUserIdToLabelMap = new HashMap<>(); private final boolean mCanModifyQuietMode; + private UserManager mUserManager = null; - InflateMessage(Environment env, Runnable callback) { - super(env, callback); + InflateMessage(Environment env, Runnable callback, ConfigStore configStore) { + super(env, callback, configStore); mCanModifyQuietMode = mEnv.getContext().checkSelfPermission(Manifest.permission.MODIFY_QUIET_MODE) == PackageManager.PERMISSION_GRANTED; } + InflateMessage(Environment env, Runnable callback, UserId sourceUserId, + UserId selectedUserId, Map<UserId, String> userIdToLabelMap, + UserManager userManager, ConfigStore configStore) { + super(env, callback, configStore); + mSourceUserId = sourceUserId; + mSelectedUserId = selectedUserId; + mUserIdToLabelMap = userIdToLabelMap; + mUserManager = userManager != null ? userManager + : mEnv.getContext().getSystemService(UserManager.class); + mCanModifyQuietMode = setCanModifyQuietMode(); + } + + private boolean setCanModifyQuietMode() { + if (SdkLevel.isAtLeastV() && mConfigStore.isPrivateSpaceInDocsUIEnabled()) { + // Quite mode cannot be modified when DocsUi is launched from a non-foreground user + if (UserId.CURRENT_USER.getIdentifier() != ActivityManager.getCurrentUser()) { + return false; + } + + if (mUserManager == null) { + Log.e(TAG, "can not obtain user manager class"); + return false; + } + + UserProperties userProperties = mUserManager.getUserProperties( + UserHandle.of(mSelectedUserId.getIdentifier())); + return userProperties.getShowInQuietMode() + == UserProperties.SHOW_IN_QUIET_MODE_PAUSED + && mEnv.getContext().checkSelfPermission( + Manifest.permission.MODIFY_QUIET_MODE) + == PackageManager.PERMISSION_GRANTED; + } else { + return mEnv.getContext().checkSelfPermission(Manifest.permission.MODIFY_QUIET_MODE) + == PackageManager.PERMISSION_GRANTED; + } + } + @Override void update(Update event) { reset(); @@ -233,16 +291,29 @@ abstract class Message { private void updateToQuietModeErrorMessage(UserId userId) { mLayout = InflateMessageDocumentHolder.LAYOUT_CROSS_PROFILE_ERROR; - CharSequence buttonText = null; + String buttonText = null; + Resources res = null; + String selectedProfile = null; + if (mConfigStore.isPrivateSpaceInDocsUIEnabled()) { + res = mEnv.getContext().getResources(); + assert mUserIdToLabelMap != null; + selectedProfile = mUserIdToLabelMap.get(userId); + } if (mCanModifyQuietMode) { - buttonText = getEnterpriseString( - WORK_PROFILE_OFF_ENABLE_BUTTON, R.string.quiet_mode_button); + buttonText = mConfigStore.isPrivateSpaceInDocsUIEnabled() + ? res.getString(R.string.profile_quiet_mode_button, + selectedProfile.toLowerCase(Locale.getDefault())) + : getEnterpriseString( + WORK_PROFILE_OFF_ENABLE_BUTTON, R.string.quiet_mode_button); mCallback = () -> mEnv.getActionHandler().requestQuietModeDisabled( mEnv.getDisplayState().stack.getRoot(), userId); } - update( - getEnterpriseString( - WORK_PROFILE_OFF_ERROR_TITLE, R.string.quiet_mode_error_title), + + update(mConfigStore.isPrivateSpaceInDocsUIEnabled() + ? res.getString(R.string.profile_quiet_mode_error_title, + selectedProfile) + : getEnterpriseString( + WORK_PROFILE_OFF_ERROR_TITLE, R.string.quiet_mode_error_title), /* messageString= */ "", buttonText, getWorkProfileOffIcon()); @@ -257,58 +328,117 @@ abstract class Message { } private CharSequence getCrossProfileNoPermissionErrorTitle() { - boolean currentUserIsSystem = UserId.CURRENT_USER.isSystem(); switch (mEnv.getDisplayState().action) { case State.ACTION_GET_CONTENT: case State.ACTION_OPEN: case State.ACTION_OPEN_TREE: - return currentUserIsSystem - ? getEnterpriseString( - CANT_SELECT_WORK_FILES_TITLE, - R.string.cant_select_work_files_error_title) - : getEnterpriseString( - CANT_SELECT_PERSONAL_FILES_TITLE, - R.string.cant_select_personal_files_error_title); + return mConfigStore.isPrivateSpaceInDocsUIEnabled() + ? getErrorTitlePrivateSpaceEnabled(ACCESS_CROSS_PROFILE_FILES) + : getErrorTitlePrivateSpaceDisabled(ACCESS_CROSS_PROFILE_FILES); case State.ACTION_CREATE: - return currentUserIsSystem - ? getEnterpriseString( - CANT_SAVE_TO_WORK_TITLE, R.string.cant_save_to_work_error_title) - : getEnterpriseString( - CANT_SAVE_TO_PERSONAL_TITLE, - R.string.cant_save_to_personal_error_title); + return mConfigStore.isPrivateSpaceInDocsUIEnabled() + ? getErrorTitlePrivateSpaceEnabled(State.ACTION_CREATE) + : getErrorTitlePrivateSpaceDisabled(State.ACTION_CREATE); } return getEnterpriseString( CROSS_PROFILE_NOT_ALLOWED_TITLE, R.string.cross_profile_action_not_allowed_title); } - private CharSequence getCrossProfileNoPermissionErrorMessage() { + private CharSequence getErrorTitlePrivateSpaceEnabled(int action) { + Resources res = mEnv.getContext().getResources(); + String selectedProfileLabel = mUserIdToLabelMap.get(mSelectedUserId); + if (selectedProfileLabel == null) return ""; + if (action == ACCESS_CROSS_PROFILE_FILES) { + return res.getString(R.string.cant_select_cross_profile_files_error_title, + selectedProfileLabel.toLowerCase(Locale.getDefault())); + } else if (action == State.ACTION_CREATE) { + return res.getString(R.string.cant_save_to_cross_profile_error_title, + selectedProfileLabel.toLowerCase(Locale.getDefault())); + } else { + Log.e(TAG, "Unexpected intent action received."); + return ""; + } + } + + private CharSequence getErrorTitlePrivateSpaceDisabled(int action) { boolean currentUserIsSystem = UserId.CURRENT_USER.isSystem(); + if (action == ACCESS_CROSS_PROFILE_FILES) { + return currentUserIsSystem + ? getEnterpriseString(CANT_SELECT_WORK_FILES_TITLE, + R.string.cant_select_work_files_error_title) + : getEnterpriseString(CANT_SELECT_PERSONAL_FILES_TITLE, + R.string.cant_select_personal_files_error_title); + } else if (action == State.ACTION_CREATE) { + return currentUserIsSystem + ? getEnterpriseString(CANT_SAVE_TO_WORK_TITLE, + R.string.cant_save_to_work_error_title) + : getEnterpriseString(CANT_SAVE_TO_PERSONAL_TITLE, + R.string.cant_save_to_personal_error_title); + } else { + Log.e(TAG, "Unexpected intent action received."); + return ""; + } + } + + private CharSequence getCrossProfileNoPermissionErrorMessage() { switch (mEnv.getDisplayState().action) { case State.ACTION_GET_CONTENT: case State.ACTION_OPEN: case State.ACTION_OPEN_TREE: - return currentUserIsSystem - ? getEnterpriseString( - CANT_SELECT_WORK_FILES_MESSAGE, - R.string.cant_select_work_files_error_message) - : getEnterpriseString( - CANT_SELECT_PERSONAL_FILES_MESSAGE, - R.string.cant_select_personal_files_error_message); + return mConfigStore.isPrivateSpaceInDocsUIEnabled() + ? getErrorMessagePrivateSpaceEnabled(ACCESS_CROSS_PROFILE_FILES) + : getErrorMessagePrivateSpaceDisabled(ACCESS_CROSS_PROFILE_FILES); case State.ACTION_CREATE: - return currentUserIsSystem - ? getEnterpriseString( - CANT_SAVE_TO_WORK_MESSAGE, - R.string.cant_save_to_work_error_message) - : getEnterpriseString( - CANT_SAVE_TO_PERSONAL_MESSAGE, - R.string.cant_save_to_personal_error_message); + return mConfigStore.isPrivateSpaceInDocsUIEnabled() + ? getErrorMessagePrivateSpaceEnabled(State.ACTION_CREATE) + : getErrorMessagePrivateSpaceDisabled(State.ACTION_CREATE); + } return getEnterpriseString( CROSS_PROFILE_NOT_ALLOWED_MESSAGE, R.string.cross_profile_action_not_allowed_message); } + private CharSequence getErrorMessagePrivateSpaceEnabled(int action) { + Resources res = mEnv.getContext().getResources(); + String sourceProfileLabel = mUserIdToLabelMap.get(mSourceUserId); + String selectedProfileLabel = mUserIdToLabelMap.get(mSelectedUserId); + if (sourceProfileLabel == null || selectedProfileLabel == null) return ""; + if (action == ACCESS_CROSS_PROFILE_FILES) { + return res.getString(R.string.cant_select_cross_profile_files_error_message, + selectedProfileLabel.toLowerCase(Locale.getDefault()), + sourceProfileLabel.toLowerCase(Locale.getDefault())); + } else if (action == State.ACTION_CREATE) { + return res.getString(R.string.cant_save_to_cross_profile_error_message, + sourceProfileLabel.toLowerCase(Locale.getDefault()), + selectedProfileLabel.toLowerCase(Locale.getDefault())); + } else { + Log.e(TAG, "Unexpected intent action received."); + return ""; + } + } + + private CharSequence getErrorMessagePrivateSpaceDisabled(int action) { + boolean currentUserIsSystem = UserId.CURRENT_USER.isSystem(); + if (action == ACCESS_CROSS_PROFILE_FILES) { + return currentUserIsSystem + ? getEnterpriseString(CANT_SELECT_WORK_FILES_MESSAGE, + R.string.cant_select_work_files_error_message) + : getEnterpriseString(CANT_SELECT_PERSONAL_FILES_MESSAGE, + R.string.cant_select_personal_files_error_message); + } else if (action == State.ACTION_CREATE) { + return currentUserIsSystem + ? getEnterpriseString(CANT_SAVE_TO_WORK_MESSAGE, + R.string.cant_save_to_work_error_message) + : getEnterpriseString(CANT_SAVE_TO_PERSONAL_MESSAGE, + R.string.cant_save_to_personal_error_message); + } else { + Log.e(TAG, "Unexpected intent action received."); + return ""; + } + } + private void updateToInflatedErrorMessage() { update(null, mEnv.getContext().getResources().getText(R.string.query_error), null, mEnv.getContext().getDrawable(R.drawable.hourglass)); diff --git a/src/com/android/documentsui/dirlist/MessageHolder.java b/src/com/android/documentsui/dirlist/MessageHolder.java index 1d8d7d61c..9853e44b2 100644 --- a/src/com/android/documentsui/dirlist/MessageHolder.java +++ b/src/com/android/documentsui/dirlist/MessageHolder.java @@ -20,16 +20,18 @@ import android.content.Context; import android.view.ViewGroup; import android.widget.Space; +import com.android.documentsui.ConfigStore; + /** * Base class for all non-Document Holder classes. */ abstract class MessageHolder extends DocumentHolder { - public MessageHolder(Context context, Space space) { - super(context, space); + MessageHolder(Context context, Space space, ConfigStore configStore) { + super(context, space, configStore); } - public MessageHolder(Context context, ViewGroup parent, int layout) { - super(context, parent, layout); + MessageHolder(Context context, ViewGroup parent, int layout, ConfigStore configStore) { + super(context, parent, layout, configStore); } @Override diff --git a/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java b/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java index f76360790..fc60d07a3 100644 --- a/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java +++ b/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java @@ -29,12 +29,14 @@ import android.view.ViewGroup; import androidx.recyclerview.selection.SelectionTracker; import androidx.recyclerview.widget.RecyclerView; +import com.android.documentsui.ConfigStore; import com.android.documentsui.Model; import com.android.documentsui.Model.Update; import com.android.documentsui.base.EventListener; import com.android.documentsui.base.Lookup; import com.android.documentsui.base.State; import com.android.documentsui.roots.RootCursorWrapper; +import com.android.modules.utils.build.SdkLevel; import java.util.ArrayList; import java.util.List; @@ -51,6 +53,7 @@ final class ModelBackedDocumentsAdapter extends DocumentsAdapter { private final Environment mEnv; private final IconHelper mIconHelper; // a transitive dependency of the holders. private final Lookup<String, String> mFileTypeLookup; + private final ConfigStore mConfigStore; /** * An ordered list of model IDs. This is the data structure that determines what shows up in @@ -60,10 +63,12 @@ final class ModelBackedDocumentsAdapter extends DocumentsAdapter { private EventListener<Model.Update> mModelUpdateListener; public ModelBackedDocumentsAdapter( - Environment env, IconHelper iconHelper, Lookup<String, String> fileTypeLookup) { + Environment env, IconHelper iconHelper, Lookup<String, String> fileTypeLookup, + ConfigStore configStore) { mEnv = env; mIconHelper = iconHelper; mFileTypeLookup = fileTypeLookup; + mConfigStore = configStore; mModelUpdateListener = new EventListener<Model.Update>() { @Override @@ -90,12 +95,16 @@ final class ModelBackedDocumentsAdapter extends DocumentsAdapter { case MODE_GRID: switch (viewType) { case ITEM_TYPE_DIRECTORY: - holder = new GridDirectoryHolder(mEnv.getContext(), parent); + holder = + new GridDirectoryHolder( + mEnv.getContext(), parent, mIconHelper, mConfigStore); break; case ITEM_TYPE_DOCUMENT: holder = state.isPhotoPicking() - ? new GridPhotoHolder(mEnv.getContext(), parent, mIconHelper) - : new GridDocumentHolder(mEnv.getContext(), parent, mIconHelper); + ? new GridPhotoHolder(mEnv.getContext(), parent, mIconHelper, + mConfigStore) + : new GridDocumentHolder(mEnv.getContext(), parent, mIconHelper, + mConfigStore); break; default: throw new IllegalStateException("Unsupported layout type."); @@ -103,7 +112,7 @@ final class ModelBackedDocumentsAdapter extends DocumentsAdapter { break; case MODE_LIST: holder = new ListDocumentHolder( - mEnv.getContext(), parent, mIconHelper, mFileTypeLookup); + mEnv.getContext(), parent, mIconHelper, mFileTypeLookup, mConfigStore); break; default: throw new IllegalStateException("Unsupported layout mode."); @@ -136,14 +145,18 @@ final class ModelBackedDocumentsAdapter extends DocumentsAdapter { boolean enabled = mEnv.isDocumentEnabled(docMimeType, docFlags); boolean selected = mEnv.isSelected(modelId); if (!enabled) { - assert(!selected); + assert (!selected); } holder.setEnabled(enabled); holder.setSelected(mEnv.isSelected(modelId), false); holder.setAction(mEnv.getDisplayState().action); holder.bindPreviewIcon(mEnv.getDisplayState().shouldShowPreview() && enabled, view -> mEnv.getActionHandler().previewItem(holder.getItemDetails())); - holder.bindBriefcaseIcon(mIconHelper.shouldShowBadge(userIdIdentifier)); + if (mConfigStore.isPrivateSpaceInDocsUIEnabled() && SdkLevel.isAtLeastS()) { + holder.bindProfileIcon(mIconHelper.shouldShowBadge(userIdIdentifier), userIdIdentifier); + } else { + holder.bindBriefcaseIcon(mIconHelper.shouldShowBadge(userIdIdentifier)); + } mEnv.onBindDocumentHolder(holder, cursor); } diff --git a/src/com/android/documentsui/dirlist/SelectionMetadata.java b/src/com/android/documentsui/dirlist/SelectionMetadata.java index 3abc3e190..74b6061b3 100644 --- a/src/com/android/documentsui/dirlist/SelectionMetadata.java +++ b/src/com/android/documentsui/dirlist/SelectionMetadata.java @@ -168,7 +168,7 @@ public class SelectionMetadata extends SelectionObserver<String> } @Override - public boolean canOpenWith() { + public boolean canOpen() { return size() == 1 && mDirectoryCount == 0 && mInArchiveCount == 0 && mPartialCount == 0; } } diff --git a/src/com/android/documentsui/dirlist/TransparentDividerDocumentHolder.java b/src/com/android/documentsui/dirlist/TransparentDividerDocumentHolder.java index 44efd8090..cb65e7023 100644 --- a/src/com/android/documentsui/dirlist/TransparentDividerDocumentHolder.java +++ b/src/com/android/documentsui/dirlist/TransparentDividerDocumentHolder.java @@ -21,6 +21,7 @@ import android.content.Context; import android.database.Cursor; import android.widget.Space; +import com.android.documentsui.ConfigStore; import com.android.documentsui.R; import com.android.documentsui.base.State; @@ -32,8 +33,8 @@ final class TransparentDividerDocumentHolder extends MessageHolder { private final int mVisibleHeight; private State mState; - public TransparentDividerDocumentHolder(Context context) { - super(context, new Space(context)); + TransparentDividerDocumentHolder(Context context, ConfigStore configStore) { + super(context, new Space(context), configStore); mVisibleHeight = context.getResources().getDimensionPixelSize( R.dimen.grid_section_separator_height); @@ -51,6 +52,5 @@ final class TransparentDividerDocumentHolder extends MessageHolder { } else { itemView.setMinimumHeight(0); } - return; } }
\ No newline at end of file diff --git a/src/com/android/documentsui/files/ActionHandler.java b/src/com/android/documentsui/files/ActionHandler.java index 20b831856..af5ef5bbc 100644 --- a/src/com/android/documentsui/files/ActionHandler.java +++ b/src/com/android/documentsui/files/ActionHandler.java @@ -19,10 +19,12 @@ package com.android.documentsui.files; import static android.content.ContentResolver.wrap; import static com.android.documentsui.base.SharedMinimal.DEBUG; +import com.android.documentsui.flags.Flags; import android.app.DownloadManager; import android.content.ActivityNotFoundException; import android.content.ClipData; +import android.content.ComponentName; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.Intent; @@ -221,6 +223,12 @@ public class ActionHandler<T extends FragmentActivity & AbstractActionHandler.Co } @Override + public void openDocumentViewOnly(DocumentInfo doc) { + mInjector.searchManager.recordHistory(); + openDocument(doc, VIEW_TYPE_REGULAR, VIEW_TYPE_NONE); + } + + @Override public void springOpenDirectory(DocumentInfo doc) { assert(doc.isDirectory()); mActionModeAddons.finishActionMode(); @@ -543,17 +551,27 @@ public class ActionHandler<T extends FragmentActivity & AbstractActionHandler.Co return; } - Intent intent = Intent.createChooser(buildViewIntent(doc), null); - intent.putExtra(Intent.EXTRA_AUTO_LAUNCH_SINGLE_CHOICE, false); - try { - doc.userId.startActivityAsUser(mActivity, intent); - } catch (ActivityNotFoundException e) { - mDialogs.showNoApplicationFound(); + if (Flags.desktopFileHandling()) { + Intent intent = buildViewIntent(doc); + intent.setComponent( + new ComponentName("android", "com.android.internal.app.ResolverActivity")); + try { + doc.userId.startActivityAsUser(mActivity, intent); + } catch (ActivityNotFoundException e) { + mDialogs.showNoApplicationFound(); + } + } else { + Intent intent = Intent.createChooser(buildViewIntent(doc), null); + intent.putExtra(Intent.EXTRA_AUTO_LAUNCH_SINGLE_CHOICE, false); + try { + doc.userId.startActivityAsUser(mActivity, intent); + } catch (ActivityNotFoundException e) { + mDialogs.showNoApplicationFound(); + } } } - @Override - public void showInspector(DocumentInfo doc) { + private void showInspector(DocumentInfo doc) { Metrics.logUserAction(MetricConsts.USER_ACTION_INSPECTOR); Intent intent = InspectorActivity.createIntent(mActivity, doc.derivedUri, doc.userId); @@ -577,4 +595,17 @@ public class ActionHandler<T extends FragmentActivity & AbstractActionHandler.Co } mActivity.startActivity(intent); } + + private void showPeek() { + Log.d(TAG, "Peek not implemented"); + } + + @Override + public void showPreview(DocumentInfo doc) { + if (Flags.useMaterial3() && Flags.usePeekPreview()) { + showPeek(); + } else { + showInspector(doc); + } + } } diff --git a/src/com/android/documentsui/files/FilesActivity.java b/src/com/android/documentsui/files/FilesActivity.java index 7c09811c9..4bb7c1ac5 100644 --- a/src/com/android/documentsui/files/FilesActivity.java +++ b/src/com/android/documentsui/files/FilesActivity.java @@ -17,12 +17,15 @@ package com.android.documentsui.files; import static com.android.documentsui.OperationDialogFragment.DIALOG_TYPE_UNKNOWN; +import static com.android.documentsui.base.SharedMinimal.DEBUG; +import static com.android.documentsui.flags.Flags.useMaterial3; import android.app.ActivityManager.TaskDescription; import android.content.Intent; import android.graphics.Color; import android.net.Uri; import android.os.Bundle; +import android.util.Log; import android.view.KeyEvent; import android.view.KeyboardShortcutGroup; import android.view.Menu; @@ -57,6 +60,7 @@ import com.android.documentsui.clipping.DocumentClipper; import com.android.documentsui.dirlist.AnimationView.AnimationType; import com.android.documentsui.dirlist.AppsRowManager; import com.android.documentsui.dirlist.DirectoryFragment; +import com.android.documentsui.flags.Flags; import com.android.documentsui.services.FileOperationService; import com.android.documentsui.sidebar.RootsFragment; import com.android.documentsui.ui.DialogController; @@ -83,8 +87,15 @@ public class FilesActivity extends BaseActivity implements AbstractActionHandler } // make these methods visible in this package to work around compiler bug http://b/62218600 - @Override protected boolean focusSidebar() { return super.focusSidebar(); } - @Override protected boolean popDir() { return super.popDir(); } + @Override + protected boolean focusSidebar() { + return super.focusSidebar(); + } + + @Override + protected boolean popDir() { + return super.popDir(); + } @Override public void onCreate(Bundle icicle) { @@ -157,8 +168,7 @@ public class FilesActivity extends BaseActivity implements AbstractActionHandler mInjector.selectionMgr, mProfileTabsAddonsStub); - mAppsRowManager = new AppsRowManager(mInjector.actions, mState.supportsCrossProfile(), - mUserIdManager); + mAppsRowManager = getAppsRowManager(); mInjector.appsRowManager = mAppsRowManager; mActivityInputHandler = @@ -175,6 +185,14 @@ public class FilesActivity extends BaseActivity implements AbstractActionHandler RootsFragment.show(getSupportFragmentManager(), /* includeApps= */ false, /* intent= */ null); + if (useMaterial3()) { + View navRailRoots = findViewById(R.id.nav_rail_container_roots); + if (navRailRoots != null) { + // Medium layout, populate navigation rail layout. + RootsFragment.showNavRail(getSupportFragmentManager(), /* includeApps= */ false, + /* intent= */ null); + } + } final Intent intent = getIntent(); @@ -194,6 +212,14 @@ public class FilesActivity extends BaseActivity implements AbstractActionHandler presentFileErrors(icicle, intent); } + private AppsRowManager getAppsRowManager() { + return mConfigStore.isPrivateSpaceInDocsUIEnabled() + ? new AppsRowManager(mInjector.actions, mState.supportsCrossProfile(), + mUserManagerState, mConfigStore) + : new AppsRowManager(mInjector.actions, mState.supportsCrossProfile(), + mUserIdManager, mConfigStore); + } + // This is called in the intent contains label and icon resources. // When that is true, the launcher activity has supplied them so we // can adapt our presentation to how we were launched. @@ -207,11 +233,11 @@ public class FilesActivity extends BaseActivity implements AbstractActionHandler // called Downloads, which is also not the desired behavior. private void updateTaskDescription(final Intent intent) { int labelRes = intent.getIntExtra(LauncherActivity.TASK_LABEL_RES, -1); - assert(labelRes > -1); + assert (labelRes > -1); String label = getResources().getString(labelRes); int iconRes = intent.getIntExtra(LauncherActivity.TASK_ICON_RES, -1); - assert(iconRes > -1); + assert (iconRes > -1); setTaskDescription(new TaskDescription(label, iconRes)); } @@ -244,14 +270,14 @@ public class FilesActivity extends BaseActivity implements AbstractActionHandler final Intent intent = getIntent(); // This is a remnant of old logic where we used to initialize accept MIME types in - // BaseActivity. ProvidersAccess still rely on this being correctly initialized so we still have - // to initialize it in FilesActivity. + // BaseActivity. ProvidersAccess still rely on this being correctly initialized, so we + // still have to initialize it in FilesActivity. state.initAcceptMimes(intent, "*/*"); state.action = State.ACTION_BROWSE; state.allowMultiple = true; // Options specific to the DocumentsActivity. - assert(!intent.hasExtra(Intent.EXTRA_LOCAL_ONLY)); + assert (!intent.hasExtra(Intent.EXTRA_LOCAL_ONLY)); } @Override @@ -286,6 +312,11 @@ public class FilesActivity extends BaseActivity implements AbstractActionHandler } @Override + protected void onDestroy() { + super.onDestroy(); + } + + @Override public String getDrawerTitle() { Intent intent = getIntent(); return (intent != null && intent.hasExtra(Intent.EXTRA_TITLE)) @@ -302,26 +333,30 @@ public class FilesActivity extends BaseActivity implements AbstractActionHandler @Override public boolean onOptionsItemSelected(MenuItem item) { - DirectoryFragment dir; - switch (item.getItemId()) { - case R.id.option_menu_create_dir: - assert(canCreateDirectory()); - mInjector.actions.showCreateDirectoryDialog(); - break; - case R.id.option_menu_new_window: - mInjector.actions.openInNewWindow(mState.stack); - break; - case R.id.option_menu_settings: - mInjector.actions.openSettings(getCurrentRoot()); - break; - case R.id.option_menu_select_all: - mInjector.actions.selectAllFiles(); - break; - case R.id.option_menu_inspect: - mInjector.actions.showInspector(getCurrentDirectory()); - break; - default: - return super.onOptionsItemSelected(item); + final int id = item.getItemId(); + if (id == R.id.option_menu_create_dir) { + assert (canCreateDirectory()); + mInjector.actions.showCreateDirectoryDialog(); + } else if (id == R.id.option_menu_new_window) { + mInjector.actions.openInNewWindow(mState.stack); + } else if (id == R.id.option_menu_settings) { + mInjector.actions.openSettings(getCurrentRoot()); + } else if (id == R.id.option_menu_extract_all) { + if (!Flags.zipNg()) return false; + final DirectoryFragment dir = getDirectoryFragment(); + if (dir == null) return false; + mInjector.actions.selectAllFiles(); + return dir.onContextItemSelected(item); + } else if (id == R.id.option_menu_select_all) { + mInjector.actions.selectAllFiles(); + } else if (id == R.id.option_menu_inspect) { + mInjector.actions.showPreview(getCurrentDirectory()); + } else { + final boolean ok = super.onOptionsItemSelected(item); + if (DEBUG && !ok) { + Log.d(TAG, "Unhandled option item " + id); + } + return ok; } return true; } @@ -338,7 +373,9 @@ public class FilesActivity extends BaseActivity implements AbstractActionHandler final RootInfo root = getCurrentRoot(); final DocumentInfo cwd = getCurrentDirectory(); - assert(!mSearchManager.isSearching()); + setInitialStack(mState.stack); + + assert (!mSearchManager.isSearching()); if (mState.stack.isRecents()) { DirectoryFragment.showRecentsOpen(fm, anim); @@ -360,7 +397,7 @@ public class FilesActivity extends BaseActivity implements AbstractActionHandler @Override public void onDirectoryCreated(DocumentInfo doc) { - assert(doc.isDirectory()); + assert (doc.isDirectory()); mInjector.focusManager.focusDocument(doc.documentId); } diff --git a/src/com/android/documentsui/files/MenuManager.java b/src/com/android/documentsui/files/MenuManager.java index 742bc9739..0fb7c4fa1 100644 --- a/src/com/android/documentsui/files/MenuManager.java +++ b/src/com/android/documentsui/files/MenuManager.java @@ -16,6 +16,8 @@ package com.android.documentsui.files; +import static com.android.documentsui.flags.Flags.desktopFileHandling; + import android.content.Context; import android.content.res.Resources; import android.net.Uri; @@ -161,7 +163,12 @@ public final class MenuManager extends com.android.documentsui.MenuManager { @Override protected void updateOpenWith(MenuItem openWith, SelectionDetails selectionDetails) { - Menus.setEnabledAndVisible(openWith, selectionDetails.canOpenWith()); + Menus.setEnabledAndVisible(openWith, selectionDetails.canOpen()); + } + + @Override + protected void updateOpenInContextMenu(MenuItem open, SelectionDetails selectionDetails) { + Menus.setEnabledAndVisible(open, desktopFileHandling() && selectionDetails.canOpen()); } @Override @@ -218,6 +225,11 @@ public final class MenuManager extends com.android.documentsui.MenuManager { } @Override + protected void updateExtractAll(MenuItem it) { + Menus.setEnabledAndVisible(it, mDirDetails.isInArchive()); + } + + @Override protected void updateSelectAll(MenuItem selectAll) { Menus.setEnabledAndVisible(selectAll, true); } diff --git a/src/com/android/documentsui/inspector/KeyValueRow.java b/src/com/android/documentsui/inspector/KeyValueRow.java index 00ef819f8..349d01794 100644 --- a/src/com/android/documentsui/inspector/KeyValueRow.java +++ b/src/com/android/documentsui/inspector/KeyValueRow.java @@ -98,9 +98,11 @@ public class KeyValueRow extends LinearLayout { public void setOnClickListener(OnClickListener callback) { TextView clickable = ((TextView) findViewById(R.id.table_row_value)); mDefaultTextColor = clickable.getTextColors(); - TypedArray ta = getContext().obtainStyledAttributes(R.styleable.TextAppearance); - int linkColor = ta.getColor(R.styleable.TextAppearance_android_textColorLink, - mDefaultTextColor.getDefaultColor()); + TypedArray ta = + getContext().obtainStyledAttributes(androidx.appcompat.R.styleable.TextAppearance); + int linkColor = + ta.getColor(androidx.appcompat.R.styleable.TextAppearance_android_textColorLink, + mDefaultTextColor.getDefaultColor()); ta.recycle(); clickable.setTextColor(linkColor); clickable.setPaintFlags(clickable.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); diff --git a/src/com/android/documentsui/loaders/BaseFileLoader.kt b/src/com/android/documentsui/loaders/BaseFileLoader.kt new file mode 100644 index 000000000..dd76217ac --- /dev/null +++ b/src/com/android/documentsui/loaders/BaseFileLoader.kt @@ -0,0 +1,208 @@ +/* + * 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.documentsui.loaders + +import android.content.Context +import android.database.Cursor +import android.database.MatrixCursor +import android.database.MergeCursor +import android.net.Uri +import android.os.Bundle +import android.os.CancellationSignal +import android.os.RemoteException +import android.provider.DocumentsContract.Document +import android.util.Log +import androidx.loader.content.AsyncTaskLoader +import com.android.documentsui.DirectoryResult +import com.android.documentsui.base.Lookup +import com.android.documentsui.base.UserId +import com.android.documentsui.roots.RootCursorWrapper + +const val TAG = "SearchV2" + +val FILE_ENTRY_COLUMNS = arrayOf( + Document.COLUMN_DOCUMENT_ID, + Document.COLUMN_MIME_TYPE, + Document.COLUMN_DISPLAY_NAME, + Document.COLUMN_LAST_MODIFIED, + Document.COLUMN_FLAGS, + Document.COLUMN_SUMMARY, + Document.COLUMN_SIZE, + Document.COLUMN_ICON, +) + +fun emptyCursor(): Cursor { + return MatrixCursor(FILE_ENTRY_COLUMNS) +} + +/** + * Helper function that returns a single, non-null cursor constructed from the given list of + * cursors. + */ +fun toSingleCursor(cursorList: List<Cursor>): Cursor { + if (cursorList.isEmpty()) { + return emptyCursor() + } + if (cursorList.size == 1) { + return cursorList[0] + } + return MergeCursor(cursorList.toTypedArray()) +} + +/** + * The base class for search and directory loaders. This class implements common functionality + * shared by these loaders. The extending classes should implement loadInBackground, which + * should call the queryLocation method. + */ +abstract class BaseFileLoader( + context: Context, + private val mUserIdList: List<UserId>, + protected val mMimeTypeLookup: Lookup<String, String>, +) : AsyncTaskLoader<DirectoryResult>(context) { + + private var mSignal: CancellationSignal? = null + private var mResult: DirectoryResult? = null + + override fun cancelLoadInBackground() { + Log.d(TAG, "BasedFileLoader.cancelLoadInBackground") + super.cancelLoadInBackground() + + synchronized(this) { + mSignal?.cancel() + } + } + + override fun deliverResult(result: DirectoryResult?) { + Log.d(TAG, "BasedFileLoader.deliverResult") + if (isReset) { + closeResult(result) + return + } + val oldResult: DirectoryResult? = mResult + mResult = result + + if (isStarted) { + super.deliverResult(result) + } + + if (oldResult != null && oldResult !== result) { + closeResult(oldResult) + } + } + + override fun onStartLoading() { + Log.d(TAG, "BasedFileLoader.onStartLoading") + val isCursorStale: Boolean = checkIfCursorStale(mResult) + if (mResult != null && !isCursorStale) { + deliverResult(mResult) + } + if (takeContentChanged() || mResult == null || isCursorStale) { + forceLoad() + } + } + + override fun onStopLoading() { + Log.d(TAG, "BasedFileLoader.onStopLoading") + cancelLoad() + } + + override fun onCanceled(result: DirectoryResult?) { + Log.d(TAG, "BasedFileLoader.onCanceled") + closeResult(result) + } + + override fun onReset() { + Log.d(TAG, "BasedFileLoader.onReset") + super.onReset() + + // Ensure the loader is stopped + onStopLoading() + + closeResult(mResult) + mResult = null + } + + /** + * Quietly closes the result cursor, if results are still available. + */ + fun closeResult(result: DirectoryResult?) { + try { + result?.close() + } catch (e: Exception) { + Log.d(TAG, "Failed to close result", e) + } + } + + private fun checkIfCursorStale(result: DirectoryResult?): Boolean { + if (result == null) { + return true + } + val cursor = result.cursor ?: return true + if (cursor.isClosed) { + return true + } + Log.d(TAG, "Long check of cursor staleness") + val count = cursor.count + if (!cursor.moveToPosition(-1)) { + return true + } + for (i in 1..count) { + if (!cursor.moveToNext()) { + return true + } + } + return false + } + + /** + * A function that, for the specified location rooted in the root with the given rootId + * attempts to obtain a non-null cursor from the content provider client obtained for the + * given locationUri. It returns the first non-null cursor, if one can be found, or null, + * if it fails to query the given location for all known users. + */ + fun queryLocation( + rootId: String, + locationUri: Uri, + queryArgs: Bundle?, + maxResults: Int, + ): Cursor? { + val authority = locationUri.authority ?: return null + for (userId in mUserIdList) { + Log.d(TAG, "BaseFileLoader.queryLocation for $userId at $locationUri") + val resolver = userId.getContentResolver(context) + try { + resolver.acquireUnstableContentProviderClient( + authority + ).use { client -> + if (client == null) { + return null + } + try { + val cursor = + client.query(locationUri, null, queryArgs, mSignal) ?: return null + return RootCursorWrapper(userId, authority, rootId, cursor, maxResults) + } catch (e: RemoteException) { + Log.d(TAG, "Failed to get cursor for $locationUri", e) + } + } + } catch (e: Exception) { + Log.d(TAG, "Failed to get a content provider client for $locationUri", e) + } + } + + return null + } +} diff --git a/src/com/android/documentsui/loaders/FolderLoader.kt b/src/com/android/documentsui/loaders/FolderLoader.kt new file mode 100644 index 000000000..2bfcd895d --- /dev/null +++ b/src/com/android/documentsui/loaders/FolderLoader.kt @@ -0,0 +1,79 @@ +/* + * 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.documentsui.loaders + +import android.content.Context +import android.provider.DocumentsContract +import com.android.documentsui.ContentLock +import com.android.documentsui.DirectoryResult +import com.android.documentsui.LockingContentObserver +import com.android.documentsui.base.DocumentInfo +import com.android.documentsui.base.FilteringCursorWrapper +import com.android.documentsui.base.Lookup +import com.android.documentsui.base.RootInfo +import com.android.documentsui.base.UserId +import com.android.documentsui.sorting.SortModel + +/** + * A specialization of the BaseFileLoader that loads the children of a single folder. To list + * a directory you need to provide: + * + * - The current application context + * - A content lock for which a locking content observer is built + * - A list of user IDs on behalf of which the search is conducted + * - The root info of the listed directory + * - The document info of the listed directory + * - a lookup from file extension to file type + * - The model capable of sorting results + */ +class FolderLoader( + context: Context, + userIdList: List<UserId>, + mimeTypeLookup: Lookup<String, String>, + contentLock: ContentLock, + private val mRoot: RootInfo, + private val mListedDir: DocumentInfo, + private val mOptions: QueryOptions, + private val mSortModel: SortModel, +) : BaseFileLoader(context, userIdList, mimeTypeLookup) { + + // An observer registered on the cursor to force a reload if the cursor reports a change. + private val mObserver = LockingContentObserver(contentLock, this::onContentChanged) + + // Creates a directory result object corresponding to the current parameters of the loader. + override fun loadInBackground(): DirectoryResult? { + val rejectBeforeTimestamp = mOptions.getRejectBeforeTimestamp() + val folderChildrenUri = DocumentsContract.buildChildDocumentsUri( + mListedDir.authority, + mListedDir.documentId + ) + var cursor = + queryLocation(mRoot.rootId, folderChildrenUri, null, ALL_RESULTS) ?: emptyCursor() + val filteredCursor = FilteringCursorWrapper(cursor) + filteredCursor.filterHiddenFiles(mOptions.showHidden) + if (rejectBeforeTimestamp > 0L) { + filteredCursor.filterLastModified(rejectBeforeTimestamp) + } + // TODO(b:380945065): Add filtering by category, such as images, audio, video. + val sortedCursor = mSortModel.sortCursor(filteredCursor, mMimeTypeLookup) + sortedCursor.registerContentObserver(mObserver) + + val result = DirectoryResult() + result.doc = mListedDir + result.cursor = sortedCursor + return result + } +} diff --git a/src/com/android/documentsui/loaders/QueryOptions.kt b/src/com/android/documentsui/loaders/QueryOptions.kt new file mode 100644 index 000000000..1e098b288 --- /dev/null +++ b/src/com/android/documentsui/loaders/QueryOptions.kt @@ -0,0 +1,82 @@ +/* + * 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.documentsui.loaders + +import java.time.Duration + +/** + * The constant to be used for the maxResults parameter, if we wish to get all (unlimited) results. + */ +const val ALL_RESULTS: Int = -1 + +/** + * Common query options. These are: + * - maximum number to return; pass ALL_RESULTS to impose no limits. + * - maximum lastModified delta in milliseconds: the delta from now used to reject files that were + * not modified in the specified milliseconds; pass null for no limits. + * - maximum time the query should return, including empty, results; pass null for no limits. + * - whether or not to show hidden files. + * - A list of MIME types used to filter returned files. + */ +data class QueryOptions( + val maxResults: Int, + val maxLastModifiedDelta: Duration?, + val maxQueryTime: Duration?, + val showHidden: Boolean, + val acceptableMimeTypes: Array<String>, +) { + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as QueryOptions + + return maxResults == other.maxResults && + maxLastModifiedDelta == other.maxLastModifiedDelta && + maxQueryTime == other.maxQueryTime && + showHidden == other.showHidden && + acceptableMimeTypes.contentEquals(other.acceptableMimeTypes) + } + + /** + * Helper method that computes the earliest valid last modified timestamp. Converts last + * modified duration to milliseconds past now. If the maxLastModifiedDelta is negative + * this method returns 0L. + */ + fun getRejectBeforeTimestamp() = + if (maxLastModifiedDelta == null) { + 0L + } else { + System.currentTimeMillis() - maxLastModifiedDelta.toMillis() + } + + /** + * Helper function that indicates if query time is unlimited. Due to internal reliance on + * Java's Duration class it assumes anything larger than 60 seconds has unlimited waiting + * time. + */ + fun isQueryTimeUnlimited() = maxQueryTime == null + + override fun hashCode(): Int { + var result = maxResults + result = 31 * result + maxLastModifiedDelta.hashCode() + result = 31 * result + maxQueryTime.hashCode() + result = 31 * result + showHidden.hashCode() + result = 31 * result + acceptableMimeTypes.contentHashCode() + return result + } +} diff --git a/src/com/android/documentsui/loaders/SearchLoader.kt b/src/com/android/documentsui/loaders/SearchLoader.kt new file mode 100644 index 000000000..b394c009e --- /dev/null +++ b/src/com/android/documentsui/loaders/SearchLoader.kt @@ -0,0 +1,246 @@ +/* + * 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.documentsui.loaders + +import android.content.Context +import android.database.Cursor +import android.net.Uri +import android.os.Bundle +import android.provider.DocumentsContract +import android.provider.DocumentsContract.Document +import android.util.Log +import com.android.documentsui.DirectoryResult +import com.android.documentsui.LockingContentObserver +import com.android.documentsui.base.DocumentInfo +import com.android.documentsui.base.FilteringCursorWrapper +import com.android.documentsui.base.Lookup +import com.android.documentsui.base.RootInfo +import com.android.documentsui.base.UserId +import com.android.documentsui.sorting.SortModel +import com.google.common.util.concurrent.AbstractFuture +import java.io.Closeable +import java.util.concurrent.CountDownLatch +import java.util.concurrent.ExecutorService +import java.util.concurrent.TimeUnit +import kotlin.time.measureTime + +/** + * A specialization of the BaseFileLoader that searches the set of specified roots. To search + * the roots you must provider: + * + * - The current application context + * - A content lock for which a locking content observer is built + * - A list of user IDs, on whose behalf we query content provider clients. + * - A list of RootInfo objects representing searched roots + * - A query used to search for matching files. + * - Query options such as maximum number of results, last modified time delta, etc. + * - a lookup from file extension to file type + * - The model capable of sorting results + * - An acceptable mime types + */ +class SearchLoader( + context: Context, + userIdList: List<UserId>, + mimeTypeLookup: Lookup<String, String>, + private val mObserver: LockingContentObserver, + private val mRootList: Collection<RootInfo>, + private val mQuery: String?, + private val mOptions: QueryOptions, + private val mSortModel: SortModel, + private val mExecutorService: ExecutorService, +) : BaseFileLoader(context, userIdList, mimeTypeLookup) { + + /** + * Helper class that runs query on a single user for the given parameter. This class implements + * an abstract future so that if the task is completed, we can retrieve the cursor via the get + * method. + */ + inner class SearchTask( + private val mRootId: String, + private val mSearchUri: Uri, + private val mQueryArgs: Bundle, + private val mLatch: CountDownLatch, + ) : Closeable, Runnable, AbstractFuture<Cursor>() { + private var mCursor: Cursor? = null + val cursor: Cursor? get() = mCursor + val taskId: String get() = mSearchUri.toString() + + override fun close() { + mCursor = null + } + + override fun run() { + val queryDuration = measureTime { + try { + mCursor = queryLocation(mRootId, mSearchUri, mQueryArgs, mOptions.maxResults) + set(mCursor) + } finally { + mLatch.countDown() + } + } + Log.d(TAG, "Query on $mSearchUri took $queryDuration") + } + } + + @Volatile + private lateinit var mSearchTaskList: List<SearchTask> + + // Creates a directory result object corresponding to the current parameters of the loader. + override fun loadInBackground(): DirectoryResult? { + val result = DirectoryResult() + // TODO(b:378590632): If root list has one root use it to construct result.doc + result.doc = DocumentInfo() + result.cursor = emptyCursor() + + val searchedRoots = mRootList + val countDownLatch = CountDownLatch(searchedRoots.size) + val rejectBeforeTimestamp = mOptions.getRejectBeforeTimestamp() + + // Step 1: Build a list of search tasks. + val searchTaskList = + createSearchTaskList(rejectBeforeTimestamp, countDownLatch, mRootList) + Log.d(TAG, "${searchTaskList.size} tasks have been created") + + // Check if we are cancelled; if not copy the task list. + if (isLoadInBackgroundCanceled) { + return result + } + mSearchTaskList = searchTaskList + + // Step 2: Enqueue tasks and wait for them to complete or time out. + for (task in mSearchTaskList) { + mExecutorService.execute(task) + } + Log.d(TAG, "${mSearchTaskList.size} tasks have been enqueued") + + // Step 3: Wait for the results. + try { + if (mOptions.isQueryTimeUnlimited()) { + Log.d(TAG, "Waiting for results with no time limit") + countDownLatch.await() + } else { + Log.d(TAG, "Waiting ${mOptions.maxQueryTime!!.toMillis()}ms for results") + countDownLatch.await( + mOptions.maxQueryTime.toMillis(), + TimeUnit.MILLISECONDS + ) + } + Log.d(TAG, "Waiting for results is done") + } catch (e: InterruptedException) { + Log.d(TAG, "Failed to complete all searches within ${mOptions.maxQueryTime}") + // TODO(b:388336095): Record a metrics indicating incomplete search. + throw RuntimeException(e) + } + + // Step 4: Collect cursors from done tasks. + val cursorList = mutableListOf<Cursor>() + for (task in mSearchTaskList) { + Log.d(TAG, "Processing task ${task.taskId}") + if (isLoadInBackgroundCanceled) { + break + } + // TODO(b:388336095): Record a metric for each done and not done task. + val cursor = task.cursor + if (task.isDone && cursor != null) { + // TODO(b:388336095): Record a metric for null and not null cursor. + Log.d(TAG, "Task ${task.taskId} has ${cursor.count} results") + cursorList.add(cursor) + } + } + Log.d(TAG, "Search complete with ${cursorList.size} cursors collected") + + // Step 5: Assign the cursor, after adding filtering and sorting, to the results. + val filteringCursor = FilteringCursorWrapper(toSingleCursor(cursorList)) + filteringCursor.filterHiddenFiles(mOptions.showHidden) + if (rejectBeforeTimestamp > 0L) { + filteringCursor.filterLastModified(rejectBeforeTimestamp) + } + filteringCursor.filterMimes(mOptions.acceptableMimeTypes, arrayOf(Document.MIME_TYPE_DIR)) + val sortingCursor = mSortModel.sortCursor(filteringCursor, mMimeTypeLookup) + sortingCursor.registerContentObserver(mObserver) + result.cursor = sortingCursor + + // TODO(b:388336095): Record the total time it took to complete search. + return result + } + + private fun createContentProviderQuery(root: RootInfo) = + if (mQuery == null || mQuery.isBlank()) { + DocumentsContract.buildRecentDocumentsUri( + root.authority, + root.rootId + ) + } else { + // NOTE: We pass empty query, as the name matching query is placed in queryArgs. + DocumentsContract.buildSearchDocumentsUri( + root.authority, + root.rootId, + "" + ) + } + + private fun createQueryArgs(rejectBeforeTimestamp: Long): Bundle { + val queryArgs = Bundle() + mSortModel.addQuerySortArgs(queryArgs) + if (rejectBeforeTimestamp > 0L) { + queryArgs.putLong( + DocumentsContract.QUERY_ARG_LAST_MODIFIED_AFTER, + rejectBeforeTimestamp + ) + } + if (mQuery != null && !mQuery.isBlank()) { + queryArgs.putString(DocumentsContract.QUERY_ARG_DISPLAY_NAME, mQuery) + } + return queryArgs + } + + /** + * Helper function that creates a list of search tasks for the given countdown latch. + */ + private fun createSearchTaskList( + rejectBeforeTimestamp: Long, + countDownLatch: CountDownLatch, + rootList: Collection<RootInfo> + ): List<SearchTask> { + val searchTaskList = mutableListOf<SearchTask>() + for (root in rootList) { + if (isLoadInBackgroundCanceled) { + break + } + val rootSearchUri = createContentProviderQuery(root) + // TODO(b:385789236): Correctly pass sort order information. + val queryArgs = createQueryArgs(rejectBeforeTimestamp) + mSortModel.addQuerySortArgs(queryArgs) + Log.d(TAG, "Query $rootSearchUri and queryArgs $queryArgs") + val task = SearchTask( + root.rootId, + rootSearchUri, + queryArgs, + countDownLatch + ) + searchTaskList.add(task) + } + return searchTaskList + } + + override fun onReset() { + for (task in mSearchTaskList) { + task.close() + } + Log.d(TAG, "Resetting search loader; search task list emptied.") + super.onReset() + } +} diff --git a/src/com/android/documentsui/picker/ActionHandler.java b/src/com/android/documentsui/picker/ActionHandler.java index c0f829732..553fa6986 100644 --- a/src/com/android/documentsui/picker/ActionHandler.java +++ b/src/com/android/documentsui/picker/ActionHandler.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.android.documentsui.picker; import static android.provider.DocumentsContract.isDocumentUri; @@ -53,7 +52,6 @@ import com.android.documentsui.DocumentsAccess; import com.android.documentsui.Injector; import com.android.documentsui.MetricConsts; import com.android.documentsui.Metrics; -import com.android.documentsui.UserIdManager; import com.android.documentsui.base.BooleanConsumer; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentStack; @@ -84,8 +82,8 @@ class ActionHandler<T extends FragmentActivity & Addons> extends AbstractActionH private static final String TAG = "PickerActionHandler"; /** - * Used to prevent applications from using {@link Intent.ACTION_OPEN_DOCUMENT_TREE} and - * the {@link Intent.ACTION_OPEN_DOCUMENT} actions to request that the user select individual + * Used to prevent applications from using {@link Intent#ACTION_OPEN_DOCUMENT_TREE} and + * the {@link Intent#ACTION_OPEN_DOCUMENT} actions to request that the user select individual * files from "/Android/data", "/Android/obb", "/Android/sandbox" directories and all their * subdirectories (on the external storage), in accordance with the SAF privacy restrictions * introduced in Android 11 (R). @@ -100,8 +98,6 @@ class ActionHandler<T extends FragmentActivity & Addons> extends AbstractActionH private final Features mFeatures; private final ActivityConfig mConfig; private final LastAccessedStorage mLastAccessed; - private final UserIdManager mUserIdManager; - private UpdatePickResultTask mUpdatePickResultTask; ActionHandler( @@ -112,21 +108,19 @@ class ActionHandler<T extends FragmentActivity & Addons> extends AbstractActionH SearchViewManager searchMgr, Lookup<String, Executor> executors, Injector injector, - LastAccessedStorage lastAccessed, - UserIdManager userIdManager) { + LastAccessedStorage lastAccessed) { super(activity, state, providers, docs, searchMgr, executors, injector); mConfig = injector.config; mFeatures = injector.features; mLastAccessed = lastAccessed; mUpdatePickResultTask = new UpdatePickResultTask( - activity.getApplicationContext(), mInjector.pickResult); - mUserIdManager = userIdManager; + activity.getApplicationContext(), mInjector.pickResult); } @Override public void initLocation(Intent intent) { - assert(intent != null); + assert (intent != null); // stack is initialized if it's restored from bundle, which means we're restoring a // previously stored state. @@ -247,7 +241,7 @@ class ActionHandler<T extends FragmentActivity & Addons> extends AbstractActionH final String docId = DocumentsContract.getDocumentId(uri); final String filePath; try { - filePath = FileUtils.getPathFromStorageDocId(docId); + filePath = FileUtils.getPathFromStorageDocId(docId); } catch (IOException e) { Log.w(TAG, "Could not get canonical file path from docId '" + docId + "'"); return true; @@ -434,7 +428,7 @@ class ActionHandler<T extends FragmentActivity & Addons> extends AbstractActionH } void pickDocument(FragmentManager fm, DocumentInfo pickTarget) { - assert(pickTarget != null); + assert (pickTarget != null); mInjector.pickResult.increaseActionCount(); Uri result; switch (mState.action) { @@ -453,7 +447,7 @@ class ActionHandler<T extends FragmentActivity & Addons> extends AbstractActionH void saveDocument( String mimeType, String displayName, BooleanConsumer inProgressStateListener) { - assert(mState.action == ACTION_CREATE); + assert (mState.action == ACTION_CREATE); mInjector.pickResult.increaseActionCount(); new CreatePickedDocumentTask( mActivity, @@ -470,9 +464,9 @@ class ActionHandler<T extends FragmentActivity & Addons> extends AbstractActionH // User requested to overwrite a target. If confirmed by user #finishPicking() will be // called. void saveDocument(FragmentManager fm, DocumentInfo replaceTarget) { - assert(mState.action == ACTION_CREATE); + assert (mState.action == ACTION_CREATE); mInjector.pickResult.increaseActionCount(); - assert(replaceTarget != null); + assert (replaceTarget != null); // Adding a confirmation dialog breaks an inherited CTS test (testCreateExisting), so we // need to add a feature flag to bypass this feature in ARC++ environment. @@ -491,7 +485,7 @@ class ActionHandler<T extends FragmentActivity & Addons> extends AbstractActionH () -> { onPickFinished(docs); } - ) .executeOnExecutor(getExecutorForCurrentDirectory()); + ).executeOnExecutor(getExecutorForCurrentDirectory()); } private void onPickFinished(Uri... uris) { @@ -512,7 +506,7 @@ class ActionHandler<T extends FragmentActivity & Addons> extends AbstractActionH } updatePickResult( - intent, mSearchMgr.isSearching(), Metrics.sanitizeRoot(mState.stack.getRoot())); + intent, mSearchMgr.isSearching(), Metrics.sanitizeRoot(mState.stack.getRoot())); // TODO: Separate this piece of logic per action. // We don't instantiate different objects for different actions at the first place, so it's @@ -561,4 +555,4 @@ class ActionHandler<T extends FragmentActivity & Addons> extends AbstractActionH @VisibleForTesting void setResult(int resultCode, Intent result, int notUsed); } -} +}
\ No newline at end of file diff --git a/src/com/android/documentsui/picker/LastAccessedProvider.java b/src/com/android/documentsui/picker/LastAccessedProvider.java index 36c00f317..3a0de08dd 100644 --- a/src/com/android/documentsui/picker/LastAccessedProvider.java +++ b/src/com/android/documentsui/picker/LastAccessedProvider.java @@ -57,6 +57,7 @@ public class LastAccessedProvider extends ContentProvider { private static final int URI_LAST_ACCESSED = 1; + public static final String METHOD_CLOSE_DATABASE = "closeDatabase"; public static final String METHOD_PURGE = "purge"; public static final String METHOD_PURGE_PACKAGE = "purgePackage"; @@ -236,6 +237,9 @@ public class LastAccessedProvider extends ContentProvider { return null; + } else if (METHOD_CLOSE_DATABASE.equals(method)) { + mHelper.close(); + return null; } else { return super.call(method, arg, extras); } diff --git a/src/com/android/documentsui/picker/PickActivity.java b/src/com/android/documentsui/picker/PickActivity.java index c2fbd50a0..481b67e77 100644 --- a/src/com/android/documentsui/picker/PickActivity.java +++ b/src/com/android/documentsui/picker/PickActivity.java @@ -21,6 +21,7 @@ import static com.android.documentsui.base.State.ACTION_GET_CONTENT; import static com.android.documentsui.base.State.ACTION_OPEN; import static com.android.documentsui.base.State.ACTION_OPEN_TREE; import static com.android.documentsui.base.State.ACTION_PICK_COPY_DESTINATION; +import static com.android.documentsui.flags.Flags.useMaterial3; import android.content.Intent; import android.content.res.Resources; @@ -66,6 +67,7 @@ import com.android.documentsui.ui.DialogController; import com.android.documentsui.ui.MessageBuilder; import com.android.documentsui.util.CrossProfileUtils; import com.android.documentsui.util.VersionUtils; +import com.android.modules.utils.build.SdkLevel; import java.util.Collection; import java.util.Collections; @@ -85,8 +87,15 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons { } // make these methods visible in this package to work around compiler bug http://b/62218600 - @Override protected boolean focusSidebar() { return super.focusSidebar(); } - @Override protected boolean popDir() { return super.popDir(); } + @Override + protected boolean focusSidebar() { + return super.focusSidebar(); + } + + @Override + protected boolean popDir() { + return super.popDir(); + } @Override public void onCreate(Bundle icicle) { @@ -99,7 +108,8 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons { new MessageBuilder(this), DialogController.create(features, this), DocumentsApplication.getFileTypeLookup(this), - (Collection<RootInfo> roots) -> {}); + (Collection<RootInfo> roots) -> { + }); super.onCreate(icicle); @@ -138,15 +148,13 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons { mSearchManager, ProviderExecutor::forAuthority, mInjector, - LastAccessedStorage.create(), - mUserIdManager); + LastAccessedStorage.create()); mInjector.searchManager = mSearchManager; Intent intent = getIntent(); - mAppsRowManager = new AppsRowManager(mInjector.actions, mState.supportsCrossProfile(), - mUserIdManager); + mAppsRowManager = getAppsRowManager(); mInjector.appsRowManager = mAppsRowManager; mSharedInputHandler = @@ -163,6 +171,14 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons { Metrics.logPickerLaunchedFrom(Shared.getCallingPackageName(this)); } + private AppsRowManager getAppsRowManager() { + return mConfigStore.isPrivateSpaceInDocsUIEnabled() + ? new AppsRowManager(mInjector.actions, mState.supportsCrossProfile(), + mUserManagerState, mConfigStore) + : new AppsRowManager(mInjector.actions, mState.supportsCrossProfile(), + mUserIdManager, mConfigStore); + } + @Override public void onBackPressed() { super.onBackPressed(); @@ -203,7 +219,7 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons { final String title = intent.getStringExtra(Intent.EXTRA_TITLE); SaveFragment.show(getSupportFragmentManager(), mimeType, title); } else if (mState.action == ACTION_OPEN_TREE || - mState.action == ACTION_PICK_COPY_DESTINATION) { + mState.action == ACTION_PICK_COPY_DESTINATION) { PickFragment.show(getSupportFragmentManager()); } else { // If PickFragment or SaveFragment does not show, @@ -215,10 +231,15 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons { final Intent moreApps = new Intent(intent); moreApps.setComponent(null); moreApps.setPackage(null); - if (mState.supportsCrossProfile() - && CrossProfileUtils.getCrossProfileResolveInfo( - getPackageManager(), moreApps) != null) { - mState.canShareAcrossProfile = true; + if (mState.supportsCrossProfile) { + if (mConfigStore.isPrivateSpaceInDocsUIEnabled() && SdkLevel.isAtLeastS()) { + mState.canForwardToProfileIdMap = mUserManagerState.getCanForwardToProfileIdMap( + moreApps); + } else if (CrossProfileUtils.getCrossProfileResolveInfo(UserId.CURRENT_USER, + getPackageManager(), moreApps, getApplicationContext(), + mConfigStore.isPrivateSpaceInDocsUIEnabled()) != null) { + mState.canShareAcrossProfile = true; + } } if (mState.action == ACTION_GET_CONTENT @@ -229,6 +250,15 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons { RootsFragment.show(getSupportFragmentManager(), /* includeApps= */ mState.action == ACTION_GET_CONTENT, /* intent= */ moreApps); + if (useMaterial3()) { + View navRailRoots = findViewById(R.id.nav_rail_container_roots); + if (navRailRoots != null) { + // Medium layout, populate navigation rail layout. + RootsFragment.showNavRail(getSupportFragmentManager(), + /* includeApps= */ mState.action == ACTION_GET_CONTENT, + /* intent= */ moreApps); + } + } } } @@ -281,6 +311,11 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons { } @Override + protected void onDestroy() { + super.onDestroy(); + } + + @Override public String getDrawerTitle() { String title; try { @@ -334,6 +369,8 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons { final RootInfo root = getCurrentRoot(); final DocumentInfo cwd = getCurrentDirectory(); + setInitialStack(mState.stack); + if (mState.stack.isRecents()) { DirectoryFragment.showRecentsOpen(fm, anim); @@ -345,8 +382,8 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons { MimeTypes.VISUAL_MIMES, mState.acceptMimes); mState.derivedMode = visualMimes ? State.MODE_GRID : State.MODE_LIST; } else { - // Normal boring directory - DirectoryFragment.showDirectory(fm, root, cwd, anim); + // Normal boring directory + DirectoryFragment.showDirectory(fm, root, cwd, anim); } // Forget any replacement target @@ -358,7 +395,7 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons { } if (mState.action == ACTION_OPEN_TREE || - mState.action == ACTION_PICK_COPY_DESTINATION) { + mState.action == ACTION_PICK_COPY_DESTINATION) { final PickFragment pick = PickFragment.get(fm); if (pick != null) { pick.setPickTarget(mState.action, @@ -369,7 +406,7 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons { @Override protected void onDirectoryCreated(DocumentInfo doc) { - assert(doc.isDirectory()); + assert (doc.isDirectory()); mInjector.actions.openContainerDocument(doc); } diff --git a/src/com/android/documentsui/picker/PickCountRecordProvider.java b/src/com/android/documentsui/picker/PickCountRecordProvider.java index 0a8e21505..aa98ca042 100644 --- a/src/com/android/documentsui/picker/PickCountRecordProvider.java +++ b/src/com/android/documentsui/picker/PickCountRecordProvider.java @@ -25,6 +25,7 @@ import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; +import android.os.Bundle; import android.util.Log; public class PickCountRecordProvider extends ContentProvider { @@ -40,6 +41,8 @@ public class PickCountRecordProvider extends ContentProvider { static final String AUTHORITY = "com.android.documentsui.pickCountRecord"; + public static final String METHOD_CLOSE_DATABASE = "closeDatabase"; + static { MATCHER.addURI(AUTHORITY, "pickCountRecord/*", URI_PICK_RECORD); } @@ -148,4 +151,14 @@ public class PickCountRecordProvider extends ContentProvider { public String getType(Uri uri) { return null; } + + @Override + public Bundle call(String method, String arg, Bundle extras) { + if (METHOD_CLOSE_DATABASE.equals(method)) { + mHelper.close(); + return null; + } else { + return super.call(method, arg, extras); + } + } }
\ No newline at end of file diff --git a/src/com/android/documentsui/picker/TrampolineActivity.kt b/src/com/android/documentsui/picker/TrampolineActivity.kt new file mode 100644 index 000000000..6cb7d37a1 --- /dev/null +++ b/src/com/android/documentsui/picker/TrampolineActivity.kt @@ -0,0 +1,170 @@ +/* + * 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.documentsui.picker + +import android.content.ComponentName +import android.content.Intent +import android.content.Intent.ACTION_GET_CONTENT +import android.content.pm.PackageInfo +import android.content.pm.PackageManager +import android.os.Build +import android.os.Bundle +import android.os.ext.SdkExtensions +import android.provider.MediaStore.ACTION_PICK_IMAGES +import androidx.appcompat.app.AppCompatActivity + +/** + * DocumentsUI PickActivity currently defers picking of media mime types to the Photopicker. This + * activity trampolines the intent to either Photopicker or to the PickActivity depending on whether + * there are non-media mime types to handle. + */ +class TrampolineActivity : AppCompatActivity() { + override fun onCreate(savedInstanceBundle: Bundle?) { + super.onCreate(savedInstanceBundle) + + // This activity should not be present in the back stack nor should handle any of the + // corresponding results when picking items. + intent?.apply { + addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT) + addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) + } + + // In the event there is no photopicker returned, just refer to DocumentsUI. + val photopickerComponentName = getPhotopickerComponentName(intent.type) + if (photopickerComponentName == null) { + forwardIntentToDocumentsUI() + return + } + + // The Photopicker has an entry point to take them back to DocumentsUI. In the event the + // user originated from Photopicker, we don't want to send them back. + val referredFromPhotopicker = referrer?.host == photopickerComponentName.packageName + if (referredFromPhotopicker || !shouldForwardIntentToPhotopicker(intent)) { + forwardIntentToDocumentsUI() + return + } + + // Forward intent to Photopicker. + intent.setComponent(photopickerComponentName) + startActivity(intent) + finish() + } + + private fun forwardIntentToDocumentsUI() { + intent.setClass(applicationContext, PickActivity::class.java) + startActivity(intent) + finish() + } + + private fun getPhotopickerComponentName(type: String?): ComponentName? { + // Intent.ACTION_PICK_IMAGES is only available from SdkExtensions v2 onwards. Prior to that + // the Photopicker was not available, so in those cases should always send to DocumentsUI. + if (SdkExtensions.getExtensionVersion(Build.VERSION_CODES.R) < 2) { + return null + } + + // Attempt to resolve the `ACTION_PICK_IMAGES` intent to get the Photopicker package. + // On T+ devices this is is a standalone package, whilst prior to T it is part of the + // MediaProvider module. + val pickImagesIntent = Intent( + ACTION_PICK_IMAGES + ).apply { addCategory(Intent.CATEGORY_DEFAULT) } + val photopickerComponentName: ComponentName? = pickImagesIntent.resolveActivity( + packageManager + ) + + // For certain devices the activity that handles ACTION_GET_CONTENT can be disabled (when + // the ACTION_PICK_IMAGES is enabled) so double check by explicitly checking the + // ACTION_GET_CONTENT activity on the same activity that handles ACTION_PICK_IMAGES. + val photopickerGetContentIntent = Intent(ACTION_GET_CONTENT).apply { + setType(type) + setPackage(photopickerComponentName?.packageName) + } + val photopickerGetContentComponent: ComponentName? = + photopickerGetContentIntent.resolveActivity(packageManager) + + // Ensure the `ACTION_GET_CONTENT` activity is enabled. + if (!isComponentEnabled(photopickerGetContentComponent)) { + return null + } + + return photopickerGetContentComponent + } + + private fun isComponentEnabled(componentName: ComponentName?): Boolean { + if (componentName == null) { + return false + } + + return when (packageManager.getComponentEnabledSetting(componentName)) { + PackageManager.COMPONENT_ENABLED_STATE_ENABLED -> true + PackageManager.COMPONENT_ENABLED_STATE_DEFAULT -> { + // DEFAULT is a state that essentially defers to the state defined in the + // AndroidManifest which can be either enabled or disabled. + packageManager.getPackageInfo( + componentName.packageName, + PackageManager.GET_ACTIVITIES + )?.let { packageInfo: PackageInfo -> + if (packageInfo.activities == null) { + return false + } + for (val info in packageInfo.activities) { + if (info.name == componentName.className) { + return info.enabled + } + } + } + return false + } + + // Everything else is considered disabled. + else -> false + } + } +} + +fun shouldForwardIntentToPhotopicker(intent: Intent): Boolean { + if (intent.action != ACTION_GET_CONTENT || !isMediaMimeType(intent.type)) { + return false + } + + // Intent has type ACTION_GET_CONTENT and is either image/* or video/* with no + // additional mime types. + if (!intent.hasExtra(Intent.EXTRA_MIME_TYPES)) { + return true + } + + val extraMimeTypes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES) + extraMimeTypes?.let { + if (it.size == 0) { + return false + } + + for (mimeType in it) { + if (!isMediaMimeType(mimeType)) { + return false + } + } + } ?: return false + + return true +} + +fun isMediaMimeType(mimeType: String?): Boolean { + return mimeType?.let { mimeType -> + mimeType.startsWith("image/") || mimeType.startsWith("video/") + } == true +} diff --git a/src/com/android/documentsui/queries/SearchChipViewManager.java b/src/com/android/documentsui/queries/SearchChipViewManager.java index f80a3a7fa..ad1dfc201 100644 --- a/src/com/android/documentsui/queries/SearchChipViewManager.java +++ b/src/com/android/documentsui/queries/SearchChipViewManager.java @@ -16,6 +16,8 @@ package com.android.documentsui.queries; +import static com.android.documentsui.flags.Flags.useMaterial3; + import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.drawable.Drawable; @@ -39,6 +41,7 @@ import com.android.documentsui.base.Shared; import com.android.documentsui.util.VersionUtils; import com.google.android.material.chip.Chip; +import com.google.android.material.chip.ChipGroup; import com.google.common.primitives.Ints; import java.time.LocalDate; @@ -372,6 +375,22 @@ public class SearchChipViewManager { } } + /** + * When the chip is focused, adding a focus ring indicator using Stroke. + * TODO(b/381957932): Remove this once Material Chip supports focus ring. + */ + private void onChipFocusChange(View v, boolean hasFocus) { + Chip chip = (Chip) v; + if (hasFocus) { + final int focusRingWidth = mChipGroup + .getResources() + .getDimensionPixelSize(R.dimen.focus_ring_width); + chip.setChipStrokeWidth(focusRingWidth); + } else { + chip.setChipStrokeWidth(1f); + } + } + private void bindChip(Chip chip, SearchChipData chipData) { final Context context = mChipGroup.getContext(); chip.setTag(chipData); @@ -390,6 +409,10 @@ public class SearchChipViewManager { chip.setChipIcon(chipIcon); chip.setOnClickListener(this::onChipClick); + if (useMaterial3()) { + chip.setOnFocusChangeListener(this::onChipFocusChange); + } + if (mCheckedChipItems.contains(chipData)) { setChipChecked(chip, true); } @@ -425,10 +448,20 @@ public class SearchChipViewManager { return; } - final int chipSpacing = mChipGroup.getResources().getDimensionPixelSize( - R.dimen.search_chip_spacing); + final int chipSpacing = + useMaterial3() + ? ((ChipGroup) mChipGroup).getChipSpacingHorizontal() + : mChipGroup + .getResources() + .getDimensionPixelSize(R.dimen.search_chip_spacing); final boolean isRtl = mChipGroup.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; - float lastX = isRtl ? mChipGroup.getWidth() - chipSpacing / 2 : chipSpacing / 2; + final float chipGroupPaddingStart = + useMaterial3() + ? mChipGroup.getPaddingStart() + : mChipGroup + .getResources() + .getDimensionPixelSize(R.dimen.search_chip_half_spacing); + float lastX = isRtl ? mChipGroup.getWidth() - chipGroupPaddingStart : chipGroupPaddingStart; // remove all chips except current clicked chip to avoid losing // accessibility focus. diff --git a/src/com/android/documentsui/queries/SearchFragment.java b/src/com/android/documentsui/queries/SearchFragment.java index 92cd91a3f..890d2b262 100644 --- a/src/com/android/documentsui/queries/SearchFragment.java +++ b/src/com/android/documentsui/queries/SearchFragment.java @@ -163,9 +163,9 @@ public class SearchFragment extends Fragment { updateDirectoryVisibility(View.VISIBLE); - FragmentTransaction ft = getParentFragmentManager().beginTransaction(); - ft.remove(this); - ft.commitNow(); + getParentFragmentManager().beginTransaction() + .remove(this) + .commitAllowingStateLoss(); } private void updateDirectoryVisibility(int visibility) { diff --git a/src/com/android/documentsui/queries/SearchHistoryManager.java b/src/com/android/documentsui/queries/SearchHistoryManager.java index 26def876d..6ccad6a29 100644 --- a/src/com/android/documentsui/queries/SearchHistoryManager.java +++ b/src/com/android/documentsui/queries/SearchHistoryManager.java @@ -175,6 +175,13 @@ public class SearchHistoryManager { } } + /** + * Closes the database. + */ + public void closeDatabase() { + mHelper.close(); + } + private class DatabaseTask extends AsyncTask<Object, Void, Object> { private final String mKeyword; private final DATABASE_OPERATION mOperation; diff --git a/src/com/android/documentsui/queries/SearchViewManager.java b/src/com/android/documentsui/queries/SearchViewManager.java index b0c298731..053dc93c8 100644 --- a/src/com/android/documentsui/queries/SearchViewManager.java +++ b/src/com/android/documentsui/queries/SearchViewManager.java @@ -227,7 +227,7 @@ public class SearchViewManager implements mSearchView.setOnCloseListener(this); mSearchView.setOnSearchClickListener(this); mSearchView.setOnQueryTextFocusChangeListener(this); - final View clearButton = mSearchView.findViewById(R.id.search_close_btn); + final View clearButton = mSearchView.findViewById(androidx.appcompat.R.id.search_close_btn); if (clearButton != null) { clearButton.setPadding(clearButton.getPaddingStart() + getPixelForDp(4), clearButton.getPaddingTop(), clearButton.getPaddingEnd() + getPixelForDp(4), @@ -239,7 +239,7 @@ public class SearchViewManager implements }); } if (SdkLevel.isAtLeastU()) { - final View textView = mSearchView.findViewById(R.id.search_src_text); + final View textView = mSearchView.findViewById(androidx.appcompat.R.id.search_src_text); if (textView != null) { try { textView.setIsHandwritingDelegate(true); diff --git a/src/com/android/documentsui/roots/ProvidersCache.java b/src/com/android/documentsui/roots/ProvidersCache.java index e053b45a7..bc54fce83 100644 --- a/src/com/android/documentsui/roots/ProvidersCache.java +++ b/src/com/android/documentsui/roots/ProvidersCache.java @@ -51,7 +51,6 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import com.android.documentsui.DocumentsApplication; import com.android.documentsui.R; -import com.android.documentsui.UserIdManager; import com.android.documentsui.UserPackage; import com.android.documentsui.archives.ArchivesProvider; import com.android.documentsui.base.LookupApplicationName; @@ -59,10 +58,10 @@ import com.android.documentsui.base.Providers; import com.android.documentsui.base.RootInfo; import com.android.documentsui.base.State; import com.android.documentsui.base.UserId; +import com.android.modules.utils.build.SdkLevel; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; -import com.google.common.util.concurrent.MoreExecutors; import java.util.ArrayList; import java.util.Collection; @@ -76,7 +75,6 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; -import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.function.Function; @@ -90,11 +88,14 @@ public class ProvidersCache implements ProvidersAccess, LookupApplicationName { // empty results we don't cache them...unless they're in this magical list // of beloved providers. private static final List<String> PERMIT_EMPTY_CACHE = List.of( - // MTP provider commonly returns no roots (if no devices are attached). - Providers.AUTHORITY_MTP, - // ArchivesProvider doesn't support any roots. - ArchivesProvider.AUTHORITY); + // MTP provider commonly returns no roots (if no devices are attached). + Providers.AUTHORITY_MTP, + // ArchivesProvider doesn't support any roots. + ArchivesProvider.AUTHORITY); private static final int FIRST_LOAD_TIMEOUT_MS = 5000; + private static final int NUM_THREADS = 10; + private static final ExecutorService ASYNC_TASKS_THREAD_POOL = + Executors.newFixedThreadPool(NUM_THREADS); private final Context mContext; @@ -121,13 +122,13 @@ public class ProvidersCache implements ProvidersAccess, LookupApplicationName { @GuardedBy("mObservedAuthoritiesDetails") private final Map<UserAuthority, PackageDetails> mObservedAuthoritiesDetails = new HashMap<>(); - private final UserIdManager mUserIdManager; - - public ProvidersCache(Context context, UserIdManager userIdManager) { + public ProvidersCache(Context context) { mContext = context; - mUserIdManager = userIdManager; } + /** + * Generates recent root for the provided user id + */ private RootInfo generateRecentsRoot(UserId rootUserId) { return new RootInfo() {{ // Special root for recents @@ -199,7 +200,8 @@ public class ProvidersCache implements ProvidersAccess, LookupApplicationName { // For that reason we update our RecentsRoot to reflect // the current language. final String title = mContext.getString(R.string.root_recent); - for (UserId userId : mUserIdManager.getUserIds()) { + List<UserId> userIds = new ArrayList<>(getUserIds()); + for (UserId userId : userIds) { RootInfo recentRoot = createOrGetRecentsRoot(userId); recentRoot.title = title; // Nothing else about the root should ever change. @@ -509,11 +511,12 @@ public class ProvidersCache implements ProvidersAccess, LookupApplicationName { /** * Create task to update roots cache. * - * @param forceRefreshAll when true, all previously cached values for - * all packages should be ignored. + * @param forceRefreshAll when true, all previously cached values for + * all packages should be ignored. * @param forceRefreshUserPackage when non-null, all previously cached - * values for this specific user package should be ignored. - * @param callback when non-null, it will be invoked after the task is executed. + * values for this specific user package should be ignored. + * @param callback when non-null, it will be invoked after the task is + * executed. */ MultiProviderUpdateTask( boolean forceRefreshAll, @@ -536,7 +539,8 @@ public class ProvidersCache implements ProvidersAccess, LookupApplicationName { final long start = SystemClock.elapsedRealtime(); - for (UserId userId : mUserIdManager.getUserIds()) { + List<UserId> userIds = new ArrayList<>(getUserIds()); + for (UserId userId : userIds) { final RootInfo recents = createOrGetRecentsRoot(userId); synchronized (mLock) { mLocalRoots.put(new UserAuthority(recents.userId, recents.authority), recents); @@ -544,7 +548,7 @@ public class ProvidersCache implements ProvidersAccess, LookupApplicationName { } List<SingleProviderUpdateTaskInfo> taskInfos = new ArrayList<>(); - for (UserId userId : mUserIdManager.getUserIds()) { + for (UserId userId : userIds) { final PackageManager pm = userId.getPackageManager(mContext); // Pick up provider with action string final Intent intent = new Intent(DocumentsContract.PROVIDER_INTERFACE); @@ -559,9 +563,8 @@ public class ProvidersCache implements ProvidersAccess, LookupApplicationName { if (!taskInfos.isEmpty()) { CountDownLatch updateTaskInternalCountDown = new CountDownLatch(taskInfos.size()); - ExecutorService executor = MoreExecutors.getExitingExecutorService( - (ThreadPoolExecutor) Executors.newCachedThreadPool()); - for (SingleProviderUpdateTaskInfo taskInfo: taskInfos) { + ExecutorService executor = ASYNC_TASKS_THREAD_POOL; + for (SingleProviderUpdateTaskInfo taskInfo : taskInfos) { executor.submit(() -> startSingleProviderUpdateTask( taskInfo.providerInfo, @@ -701,4 +704,12 @@ public class ProvidersCache implements ProvidersAccess, LookupApplicationName { packageName = pckgName; } } + + private List<UserId> getUserIds() { + if (DocumentsApplication.getConfigStore().isPrivateSpaceInDocsUIEnabled() + && SdkLevel.isAtLeastS()) { + return DocumentsApplication.getUserManagerState(mContext).getUserIds(); + } + return DocumentsApplication.getUserIdManager(mContext).getUserIds(); + } } diff --git a/src/com/android/documentsui/services/CompressJob.java b/src/com/android/documentsui/services/CompressJob.java index e9ba6e4c8..a7d2de9aa 100644 --- a/src/com/android/documentsui/services/CompressJob.java +++ b/src/com/android/documentsui/services/CompressJob.java @@ -115,11 +115,11 @@ final class CompressJob extends CopyJob { mArchiveUri, ParcelFileDescriptor.MODE_WRITE_ONLY), UserId.DEFAULT_USER); ArchivesProvider.acquireArchive(getClient(mDstInfo), mDstInfo.derivedUri); } catch (FileNotFoundException e) { - Log.e(TAG, "Failed to create dstInfo.", e); + Log.e(TAG, "Cannot create document info", e); failureCount = mResourceUris.getItemCount(); return false; } catch (RemoteException e) { - Log.e(TAG, "Failed to acquire the archive.", e); + Log.e(TAG, "Cannot acquire archive", e); failureCount = mResourceUris.getItemCount(); return false; } @@ -132,7 +132,7 @@ final class CompressJob extends CopyJob { try { ArchivesProvider.releaseArchive(getClient(mDstInfo), mDstInfo.derivedUri); } catch (RemoteException e) { - Log.e(TAG, "Failed to release the archive."); + Log.e(TAG, "Cannot release archive", e); } // Remove the archive file in case of an error. @@ -141,7 +141,7 @@ final class CompressJob extends CopyJob { DocumentsContract.deleteDocument(wrap(getClient(mArchiveUri)), mArchiveUri); } } catch (RemoteException | FileNotFoundException e) { - Log.w(TAG, "Failed to cleanup after compress error: " + mDstInfo.toString(), e); + Log.w(TAG, "Cannot clean up after compress error: " + mDstInfo.toString(), e); } super.finish(); diff --git a/src/com/android/documentsui/services/ResolvedResourcesJob.java b/src/com/android/documentsui/services/ResolvedResourcesJob.java index 500958978..a6001d5f8 100644 --- a/src/com/android/documentsui/services/ResolvedResourcesJob.java +++ b/src/com/android/documentsui/services/ResolvedResourcesJob.java @@ -16,6 +16,10 @@ package com.android.documentsui.services; +import static android.os.SystemClock.uptimeMillis; + +import static com.android.documentsui.base.SharedMinimal.DEBUG; + import android.content.ContentResolver; import android.content.Context; import android.net.Uri; @@ -44,6 +48,9 @@ import java.util.List; public abstract class ResolvedResourcesJob extends Job { private static final String TAG = "ResolvedResourcesJob"; + // Used in logs. + protected final long mStartTime = uptimeMillis(); + final List<DocumentInfo> mResolvedDocs; final List<Uri> mAcquiredArchivedUris = new ArrayList<>(); @@ -72,22 +79,22 @@ public abstract class ResolvedResourcesJob extends Job { mAcquiredArchivedUris.add(uri); } } catch (RemoteException e) { - Log.e(TAG, "Failed to acquire an archive."); + Log.e(TAG, "Cannot acquire an archive", e); return false; } } } catch (IOException e) { - Log.e(TAG, "Failed to read list of target resource Uris. Cannot continue.", e); + Log.e(TAG, "Cannot read list of target resource URIs", e); return false; } int docsResolved = buildDocumentList(); if (!isCanceled() && docsResolved < mResourceUris.getItemCount()) { if (docsResolved == 0) { - Log.e(TAG, "Failed to load any documents. Aborting."); + Log.e(TAG, "Cannot load any documents. Aborting."); return false; } else { - Log.e(TAG, "Failed to load some documents. Processing loaded documents only."); + Log.e(TAG, "Cannot load some documents"); } } @@ -101,9 +108,14 @@ public abstract class ResolvedResourcesJob extends Job { try { ArchivesProvider.releaseArchive(getClient(uri), uri); } catch (RemoteException e) { - Log.e(TAG, "Failed to release an archived document."); + Log.e(TAG, "Cannot release an archived document", e); } } + + if (DEBUG) { + Log.d(TAG, String.format("%s %s finished after %d ms", getClass().getSimpleName(), id, + uptimeMillis() - mStartTime)); + } } /** @@ -123,7 +135,7 @@ public abstract class ResolvedResourcesJob extends Job { try { uris = mResourceUris.getUris(appContext); } catch (IOException e) { - Log.e(TAG, "Failed to read list of target resource Uris. Cannot continue.", e); + Log.e(TAG, "Cannot read list of target resource URIs", e); failureCount = this.mResourceUris.getItemCount(); return 0; } @@ -135,8 +147,7 @@ public abstract class ResolvedResourcesJob extends Job { try { doc = DocumentInfo.fromUri(resolver, uri, UserId.DEFAULT_USER); } catch (FileNotFoundException e) { - Log.e(TAG, "Failed to resolve content from Uri: " + uri - + ". Skipping to next resource.", e); + Log.e(TAG, "Cannot resolve content from URI " + uri, e); onResolveFailed(uri); continue; } diff --git a/src/com/android/documentsui/sidebar/AppItem.java b/src/com/android/documentsui/sidebar/AppItem.java index 4bb7257b6..c719241d2 100644 --- a/src/com/android/documentsui/sidebar/AppItem.java +++ b/src/com/android/documentsui/sidebar/AppItem.java @@ -16,21 +16,22 @@ package com.android.documentsui.sidebar; +import static com.android.documentsui.flags.Flags.useMaterial3; + import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.os.UserManager; -import android.text.TextUtils; import android.view.View; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.LayoutRes; + import com.android.documentsui.ActionHandler; import com.android.documentsui.IconUtils; import com.android.documentsui.R; import com.android.documentsui.base.UserId; -import com.android.documentsui.dirlist.AppsRowItemData; /** * An {@link Item} for apps that supports some picking actions like @@ -44,7 +45,16 @@ public class AppItem extends Item { private final ActionHandler mActionHandler; public AppItem(ResolveInfo info, String title, UserId userId, ActionHandler actionHandler) { - super(R.layout.item_root, title, getStringId(info), userId); + this(R.layout.item_root, info, title, userId, actionHandler); + } + + public AppItem( + @LayoutRes int layoutId, + ResolveInfo info, + String title, + UserId userId, + ActionHandler actionHandler) { + super(layoutId, title, getStringId(info), userId); this.info = info; mActionHandler = actionHandler; } @@ -84,14 +94,19 @@ public class AppItem extends Item { final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon); final TextView titleView = (TextView) convertView.findViewById(android.R.id.title); final TextView summary = (TextView) convertView.findViewById(android.R.id.summary); - final View actionIconArea = convertView.findViewById(R.id.action_icon_area); - final ImageView actionIcon = (ImageView) convertView.findViewById(R.id.action_icon); titleView.setText(title); titleView.setContentDescription(userId.getUserBadgedLabel(convertView.getContext(), title)); bindIcon(icon); - bindActionIcon(actionIconArea, actionIcon); + + // In M3, we don't show action icon for the app items, do nothing here because the icons + // are hidden by default. + if (!useMaterial3()) { + final View actionIconArea = convertView.findViewById(R.id.action_icon_area); + final ImageView actionIcon = (ImageView) convertView.findViewById(R.id.action_icon); + bindActionIcon(actionIconArea, actionIcon); + } // TODO: match existing summary behavior from disambig dialog summary.setVisibility(View.GONE); diff --git a/src/com/android/documentsui/sidebar/NavRailAppItem.java b/src/com/android/documentsui/sidebar/NavRailAppItem.java new file mode 100644 index 000000000..befddf0aa --- /dev/null +++ b/src/com/android/documentsui/sidebar/NavRailAppItem.java @@ -0,0 +1,48 @@ +/* + * 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.documentsui.sidebar; + +import android.content.pm.ResolveInfo; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.android.documentsui.ActionHandler; +import com.android.documentsui.R; +import com.android.documentsui.base.UserId; + +/** + * Similar to {@link AppItem} but only used in the navigation rail. + */ +public class NavRailAppItem extends AppItem { + + public NavRailAppItem( + ResolveInfo info, String title, UserId userId, ActionHandler actionHandler) { + super(R.layout.nav_rail_item_root, info, title, userId, actionHandler); + } + + @Override + public void bindView(View convertView) { + final ImageView icon = convertView.findViewById(android.R.id.icon); + final TextView titleView = convertView.findViewById(android.R.id.title); + + titleView.setText(title); + titleView.setContentDescription(userId.getUserBadgedLabel(convertView.getContext(), title)); + + bindIcon(icon); + } +} diff --git a/src/com/android/documentsui/sidebar/NavRailProfileItem.java b/src/com/android/documentsui/sidebar/NavRailProfileItem.java new file mode 100644 index 000000000..fe69c286f --- /dev/null +++ b/src/com/android/documentsui/sidebar/NavRailProfileItem.java @@ -0,0 +1,47 @@ +/* + * 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.documentsui.sidebar; + +import android.content.pm.ResolveInfo; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.android.documentsui.ActionHandler; +import com.android.documentsui.R; + + +/** + * Similar to {@link ProfileItem} but only used in the navigation rail. + */ +public class NavRailProfileItem extends ProfileItem { + + public NavRailProfileItem(ResolveInfo info, String title, ActionHandler actionHandler) { + super(R.layout.nav_rail_item_root, info, title, actionHandler); + } + + @Override + public void bindView(View convertView) { + final ImageView icon = convertView.findViewById(android.R.id.icon); + final TextView titleView = convertView.findViewById(android.R.id.title); + + titleView.setText(title); + titleView.setContentDescription(userId.getUserBadgedLabel(convertView.getContext(), title)); + + bindIcon(icon); + } +} diff --git a/src/com/android/documentsui/sidebar/NavRailRootAndAppItem.java b/src/com/android/documentsui/sidebar/NavRailRootAndAppItem.java new file mode 100644 index 000000000..1bcc42f5c --- /dev/null +++ b/src/com/android/documentsui/sidebar/NavRailRootAndAppItem.java @@ -0,0 +1,40 @@ +/* + * 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.documentsui.sidebar; + +import android.content.pm.ResolveInfo; +import android.view.View; + +import com.android.documentsui.ActionHandler; +import com.android.documentsui.R; +import com.android.documentsui.base.RootInfo; + +/** + * Similar to {@link RootAndAppItem} but only used in the navigation rail. + */ +public class NavRailRootAndAppItem extends RootAndAppItem { + + public NavRailRootAndAppItem( + RootInfo root, ResolveInfo info, ActionHandler actionHandler, boolean maybeShowBadge) { + super(R.layout.nav_rail_item_root, root, info, actionHandler, maybeShowBadge); + } + + @Override + public void bindView(View convertView) { + bindIconAndTitle(convertView); + } +} diff --git a/src/com/android/documentsui/sidebar/NavRailRootItem.java b/src/com/android/documentsui/sidebar/NavRailRootItem.java new file mode 100644 index 000000000..3d4042f22 --- /dev/null +++ b/src/com/android/documentsui/sidebar/NavRailRootItem.java @@ -0,0 +1,52 @@ +/* + * 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.documentsui.sidebar; + + +import android.view.View; + +import com.android.documentsui.ActionHandler; +import com.android.documentsui.R; +import com.android.documentsui.base.RootInfo; + +/** + * Similar to {@link RootItem} but only used in the navigation rail. + */ +public class NavRailRootItem extends RootItem { + + public NavRailRootItem(RootInfo root, ActionHandler actionHandler, boolean maybeShowBadge) { + super( + R.layout.nav_rail_item_root, + root, + actionHandler, + "" /* packageName */, + maybeShowBadge); + } + + public NavRailRootItem( + RootInfo root, + ActionHandler actionHandler, + String packageName, + boolean maybeShowBadge) { + super(R.layout.nav_rail_item_root, root, actionHandler, packageName, maybeShowBadge); + } + + @Override + public void bindView(View convertView) { + bindIconAndTitle(convertView); + } +} diff --git a/src/com/android/documentsui/sidebar/ProfileItem.java b/src/com/android/documentsui/sidebar/ProfileItem.java index 15068ad4b..779f54445 100644 --- a/src/com/android/documentsui/sidebar/ProfileItem.java +++ b/src/com/android/documentsui/sidebar/ProfileItem.java @@ -20,6 +20,8 @@ import android.content.pm.ResolveInfo; import android.view.View; import android.widget.ImageView; +import androidx.annotation.LayoutRes; + import com.android.documentsui.ActionHandler; import com.android.documentsui.base.UserId; @@ -32,6 +34,11 @@ class ProfileItem extends AppItem { super(info, title, UserId.CURRENT_USER, actionHandler); } + ProfileItem( + @LayoutRes int layoutId, ResolveInfo info, String title, ActionHandler actionHandler) { + super(layoutId, info, title, UserId.CURRENT_USER, actionHandler); + } + @Override protected void bindIcon(ImageView icon) { icon.setImageResource(com.android.documentsui.R.drawable.ic_user_profile); diff --git a/src/com/android/documentsui/sidebar/RootAndAppItem.java b/src/com/android/documentsui/sidebar/RootAndAppItem.java index b893878f3..8861f6058 100644 --- a/src/com/android/documentsui/sidebar/RootAndAppItem.java +++ b/src/com/android/documentsui/sidebar/RootAndAppItem.java @@ -18,11 +18,11 @@ package com.android.documentsui.sidebar; import android.content.Context; import android.content.pm.ResolveInfo; -import android.os.UserManager; import android.provider.DocumentsProvider; -import android.text.TextUtils; import android.view.View; +import androidx.annotation.LayoutRes; + import com.android.documentsui.ActionHandler; import com.android.documentsui.R; import com.android.documentsui.base.RootInfo; @@ -36,9 +36,18 @@ class RootAndAppItem extends RootItem { public final ResolveInfo resolveInfo; - public RootAndAppItem(RootInfo root, ResolveInfo info, ActionHandler actionHandler, + RootAndAppItem( + RootInfo root, ResolveInfo info, ActionHandler actionHandler, boolean maybeShowBadge) { + this(R.layout.item_root, root, info, actionHandler, maybeShowBadge); + } + + RootAndAppItem( + @LayoutRes int layoutId, + RootInfo root, + ResolveInfo info, + ActionHandler actionHandler, boolean maybeShowBadge) { - super(root, actionHandler, info.activityInfo.packageName, maybeShowBadge); + super(layoutId, root, actionHandler, info.activityInfo.packageName, maybeShowBadge); this.resolveInfo = info; } diff --git a/src/com/android/documentsui/sidebar/RootItem.java b/src/com/android/documentsui/sidebar/RootItem.java index a0a3210f8..326f086e1 100644 --- a/src/com/android/documentsui/sidebar/RootItem.java +++ b/src/com/android/documentsui/sidebar/RootItem.java @@ -16,6 +16,8 @@ package com.android.documentsui.sidebar; +import static com.android.documentsui.flags.Flags.useMaterial3; + import android.content.Context; import android.graphics.drawable.Drawable; import android.provider.DocumentsProvider; @@ -28,6 +30,7 @@ import android.view.View; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.LayoutRes; import androidx.annotation.Nullable; import com.android.documentsui.ActionHandler; @@ -38,6 +41,8 @@ import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.RootInfo; import com.android.documentsui.base.UserId; +import com.google.android.material.button.MaterialButton; + import java.util.Objects; /** @@ -60,7 +65,16 @@ public class RootItem extends Item { public RootItem(RootInfo root, ActionHandler actionHandler, String packageName, boolean maybeShowBadge) { - super(R.layout.item_root, root.title, getStringId(root), root.userId); + this(R.layout.item_root, root, actionHandler, packageName, maybeShowBadge); + } + + public RootItem( + @LayoutRes int layoutId, + RootInfo root, + ActionHandler actionHandler, + String packageName, + boolean maybeShowBadge) { + super(layoutId, root.title, getStringId(root), root.userId); this.root = root; mActionHandler = actionHandler; mPackageName = packageName; @@ -96,19 +110,36 @@ public class RootItem extends Item { } protected final void bindAction(View view, int visibility, int iconId, String description) { - final ImageView actionIcon = (ImageView) view.findViewById(R.id.action_icon); - final View verticalDivider = view.findViewById(R.id.vertical_divider); - final View actionIconArea = view.findViewById(R.id.action_icon_area); - - verticalDivider.setVisibility(visibility); - actionIconArea.setVisibility(visibility); - actionIconArea.setOnClickListener(visibility == View.VISIBLE ? this::onActionClick : null); - if (description != null) { - actionIconArea.setContentDescription(description); - } - if (iconId > 0) { - actionIcon.setImageDrawable(IconUtils.applyTintColor(view.getContext(), iconId, - R.color.item_action_icon)); + if (useMaterial3()) { + final MaterialButton actionIcon = view.findViewById(R.id.action_icon); + + actionIcon.setVisibility(visibility); + actionIcon.setOnClickListener(visibility == View.VISIBLE ? this::onActionClick : null); + actionIcon.setOnFocusChangeListener( + visibility == View.VISIBLE ? this::onActionIconFocusChange : null); + if (description != null) { + actionIcon.setContentDescription(description); + } + if (iconId > 0) { + actionIcon.setIconResource(iconId); + } + } else { + final ImageView actionIcon = (ImageView) view.findViewById(R.id.action_icon); + final View verticalDivider = view.findViewById(R.id.vertical_divider); + final View actionIconArea = view.findViewById(R.id.action_icon_area); + + verticalDivider.setVisibility(visibility); + actionIconArea.setVisibility(visibility); + actionIconArea.setOnClickListener( + visibility == View.VISIBLE ? this::onActionClick : null); + if (description != null) { + actionIconArea.setContentDescription(description); + } + if (iconId > 0) { + actionIcon.setImageDrawable( + IconUtils.applyTintColor( + view.getContext(), iconId, R.color.item_action_icon)); + } } } @@ -116,6 +147,21 @@ public class RootItem extends Item { RootsFragment.ejectClicked(view, root, mActionHandler); } + /** + * When the action icon is focused, adding a focus ring indicator using Stroke. + * TODO(b/381957932): Remove this once Material Button supports focus ring. + */ + protected void onActionIconFocusChange(View view, boolean hasFocus) { + MaterialButton actionIcon = (MaterialButton) view; + if (hasFocus) { + final int focusRingWidth = + actionIcon.getResources().getDimensionPixelSize(R.dimen.focus_ring_width); + actionIcon.setStrokeWidth(focusRingWidth); + } else { + actionIcon.setStrokeWidth(0); + } + } + protected final void bindIconAndTitle(View view) { bindIcon(view, root.loadDrawerIcon(view.getContext(), mMaybeShowBadge)); bindTitle(view); diff --git a/src/com/android/documentsui/sidebar/RootsAdapter.java b/src/com/android/documentsui/sidebar/RootsAdapter.java index a08637c9d..b64e39d5f 100644 --- a/src/com/android/documentsui/sidebar/RootsAdapter.java +++ b/src/com/android/documentsui/sidebar/RootsAdapter.java @@ -16,12 +16,15 @@ package com.android.documentsui.sidebar; +import static com.android.documentsui.flags.Flags.useMaterial3; + import android.app.Activity; import android.os.Looper; import android.view.View; import android.view.View.OnDragListener; import android.view.ViewGroup; import android.widget.ArrayAdapter; +import android.widget.ListView; import com.android.documentsui.R; @@ -83,6 +86,16 @@ class RootsAdapter extends ArrayAdapter<Item> { final Item item = getItem(position); final View view = item.getView(convertView, parent); + if (useMaterial3()) { + // In order to have hover showing on the list item, we need to have + // "android:clickable=true" on the list item level, which will break the click handler + // because it's set at the list level, so here we "bubble up" the item level click + // event to the list level by explicitly calling the "performItemClick" on the list + // level. + view.setOnClickListener( + v -> ((ListView) parent).performItemClick(v, position, getItemId(position))); + } + if (item.isRoot()) { view.setTag(R.id.item_position_tag, position); view.setOnDragListener(mDragListener); diff --git a/src/com/android/documentsui/sidebar/RootsFragment.java b/src/com/android/documentsui/sidebar/RootsFragment.java index 5bf3f1af5..e30017fe4 100644 --- a/src/com/android/documentsui/sidebar/RootsFragment.java +++ b/src/com/android/documentsui/sidebar/RootsFragment.java @@ -19,6 +19,8 @@ package com.android.documentsui.sidebar; import static com.android.documentsui.base.Shared.compareToIgnoreCaseNullable; import static com.android.documentsui.base.SharedMinimal.DEBUG; import static com.android.documentsui.base.SharedMinimal.VERBOSE; +import static com.android.documentsui.flags.Flags.hideRootsOnDesktop; +import static com.android.documentsui.flags.Flags.useMaterial3; import android.app.admin.DevicePolicyManager; import android.content.Context; @@ -27,8 +29,11 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; +import android.os.Build; import android.os.Bundle; +import android.os.ext.SdkExtensions; import android.provider.DocumentsContract; +import android.provider.MediaStore; import android.text.TextUtils; import android.util.Log; import android.view.ContextMenu; @@ -46,7 +51,9 @@ import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.ListView; +import androidx.annotation.IdRes; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; @@ -63,6 +70,7 @@ import com.android.documentsui.Injector; import com.android.documentsui.Injector.Injected; import com.android.documentsui.ItemDragListener; import com.android.documentsui.R; +import com.android.documentsui.UserManagerState; import com.android.documentsui.UserPackage; import com.android.documentsui.base.BooleanConsumer; import com.android.documentsui.base.DocumentInfo; @@ -77,6 +85,7 @@ import com.android.documentsui.roots.ProvidersAccess; import com.android.documentsui.roots.ProvidersCache; import com.android.documentsui.roots.RootsLoader; import com.android.documentsui.util.CrossProfileUtils; +import com.android.modules.utils.build.SdkLevel; import java.util.ArrayList; import java.util.Collection; @@ -86,15 +95,27 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.stream.Collectors; /** * Display list of known storage backend roots. + * This fragment will be used in: + * * fixed_layout: as navigation tree (sidebar) + * * drawer_layout: as navigation drawer + * * nav_rail_layout: as navigation drawer and navigation rail. */ public class RootsFragment extends Fragment { private static final String TAG = "RootsFragment"; private static final String EXTRA_INCLUDE_APPS = "includeApps"; private static final String EXTRA_INCLUDE_APPS_INTENT = "includeAppsIntent"; + /** + * A key used to store the container id in the RootFragment. + * RootFragment is used in both navigation drawer and navigation rail, there are 2 instances + * of the fragment rendered on the page, we need to know which one is which to render different + * nav items inside. + */ + private static final String EXTRA_CONTAINER_ID = "containerId"; private static final int CONTEXT_MENU_ITEM_TIMEOUT = 500; private final OnItemClickListener mItemListener = new OnItemClickListener() { @@ -128,40 +149,88 @@ public class RootsFragment extends Fragment { private List<Item> mApplicationItemList; + // Weather the fragment is using nav_rail_container_roots as its container (in nav_rail_layout). + // This will always be false if useMaterial3() flag is off. + private boolean mUseRailAsContainer = false; + + /** + * Show the RootsFragment inside the navigation drawer container. + */ + public static RootsFragment show(FragmentManager fm, boolean includeApps, Intent intent) { + return showWithLayout(R.id.container_roots, fm, includeApps, intent); + } + + /** + * Show the RootsFragment inside the navigation rail container. + */ + public static RootsFragment showNavRail(FragmentManager fm, boolean includeApps, + Intent intent) { + return showWithLayout(R.id.nav_rail_container_roots, fm, includeApps, intent); + } + /** * Shows the {@link RootsFragment}. - * @param fm the FragmentManager for interacting with fragments associated with this - * fragment's activity + * + * @param containerId the container id where the {@link RootsFragment} will be rendered into + * @param fm the FragmentManager for interacting with fragments associated with this + * fragment's activity * @param includeApps if {@code true}, query the intent from the system and include apps in * the {@RootsFragment}. - * @param intent the intent to query for package manager + * @param intent the intent to query for package manager */ - public static RootsFragment show(FragmentManager fm, boolean includeApps, Intent intent) { + private static RootsFragment showWithLayout( + @IdRes int containerId, FragmentManager fm, boolean includeApps, Intent intent) { final Bundle args = new Bundle(); args.putBoolean(EXTRA_INCLUDE_APPS, includeApps); args.putParcelable(EXTRA_INCLUDE_APPS_INTENT, intent); + if (useMaterial3()) { + args.putInt(EXTRA_CONTAINER_ID, containerId); + } final RootsFragment fragment = new RootsFragment(); fragment.setArguments(args); final FragmentTransaction ft = fm.beginTransaction(); - ft.replace(R.id.container_roots, fragment); + ft.replace(containerId, fragment); ft.commitAllowingStateLoss(); return fragment; } + /** + * Get the RootsFragment instance for the navigation drawer. + */ public static RootsFragment get(FragmentManager fm) { return (RootsFragment) fm.findFragmentById(R.id.container_roots); } + /** + * Get the RootsFragment instance for the navigation drawer. + */ + public static RootsFragment getNavRail(FragmentManager fm) { + return (RootsFragment) fm.findFragmentById(R.id.nav_rail_container_roots); + } + @Override public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + if (useMaterial3()) { + mUseRailAsContainer = + getArguments() != null + && getArguments().getInt(EXTRA_CONTAINER_ID) + == R.id.nav_rail_container_roots; + } + mInjector = getBaseActivity().getInjector(); - final View view = inflater.inflate(R.layout.fragment_roots, container, false); + final View view = + inflater.inflate( + mUseRailAsContainer + ? R.layout.fragment_nav_rail_roots + : R.layout.fragment_roots, + container, + false); mList = (ListView) view.findViewById(R.id.roots_list); mList.setOnItemClickListener(mItemListener); // ListView does not have right-click specific listeners, so we will have a @@ -184,8 +253,8 @@ public class RootsFragment extends Fragment { }); } return false; - } - }); + } + }); mList.setChoiceMode(ListView.CHOICE_MODE_SINGLE); mList.setSelector(new ColorDrawable(Color.TRANSPARENT)); return view; @@ -265,11 +334,27 @@ public class RootsFragment extends Fragment { // For action which supports cross profile, update the policy value in state if // necessary. ResolveInfo crossProfileResolveInfo = null; + UserManagerState userManagerState = null; if (state.supportsCrossProfile() && handlerAppIntent != null) { - crossProfileResolveInfo = CrossProfileUtils.getCrossProfileResolveInfo( - getContext().getPackageManager(), handlerAppIntent); - updateCrossProfileStateAndMaybeRefresh( - /* canShareAcrossProfile= */ crossProfileResolveInfo != null); + if (state.configStore.isPrivateSpaceInDocsUIEnabled() + && SdkLevel.isAtLeastS()) { + userManagerState = DocumentsApplication.getUserManagerState(getContext()); + Map<UserId, Boolean> canForwardToProfileIdMap = + userManagerState.getCanForwardToProfileIdMap(handlerAppIntent); + updateCrossProfileMapStateAndMaybeRefresh(canForwardToProfileIdMap); + } else { + crossProfileResolveInfo = CrossProfileUtils.getCrossProfileResolveInfo( + UserId.CURRENT_USER, getContext().getPackageManager(), + handlerAppIntent, getContext(), + state.configStore.isPrivateSpaceInDocsUIEnabled()); + updateCrossProfileStateAndMaybeRefresh( + /* canShareAcrossProfile= */ crossProfileResolveInfo != null); + } + } + + if (state.configStore.isPrivateSpaceInDocsUIEnabled() + && userManagerState == null) { + userManagerState = DocumentsApplication.getUserManagerState(getContext()); } List<Item> sortedItems = sortLoadResult( @@ -280,17 +365,25 @@ public class RootsFragment extends Fragment { shouldIncludeHandlerApp ? handlerAppIntent : null, DocumentsApplication.getProvidersCache(getContext()), getBaseActivity().getSelectedUser(), - DocumentsApplication.getUserIdManager(getContext()).getUserIds(), - maybeShowBadge); + getUserIds(), + maybeShowBadge, + userManagerState); // This will be removed when feature flag is removed. if (crossProfileResolveInfo != null && !Features.CROSS_PROFILE_TABS) { // Add profile item if we don't support cross-profile tab. sortedItems.add(new SpacerItem()); - sortedItems.add(new ProfileItem(crossProfileResolveInfo, - crossProfileResolveInfo.loadLabel( - getContext().getPackageManager()).toString(), - mActionHandler)); + if (mUseRailAsContainer) { + sortedItems.add(new NavRailProfileItem(crossProfileResolveInfo, + crossProfileResolveInfo.loadLabel( + getContext().getPackageManager()).toString(), + mActionHandler)); + } else { + sortedItems.add(new ProfileItem(crossProfileResolveInfo, + crossProfileResolveInfo.loadLabel( + getContext().getPackageManager()).toString(), + mActionHandler)); + } } // Disable drawer if only one root @@ -316,6 +409,13 @@ public class RootsFragment extends Fragment { onCurrentRootChanged(); } + private List<UserId> getUserIds() { + if (state.configStore.isPrivateSpaceInDocsUIEnabled() && SdkLevel.isAtLeastS()) { + return DocumentsApplication.getUserManagerState(getContext()).getUserIds(); + } + return DocumentsApplication.getUserIdManager(getContext()).getUserIds(); + } + @Override public void onLoaderReset(Loader<Collection<RootInfo>> loader) { mAdapter = null; @@ -338,12 +438,24 @@ public class RootsFragment extends Fragment { } } + private void updateCrossProfileMapStateAndMaybeRefresh( + Map<UserId, Boolean> canForwardToProfileIdMap) { + final State state = getBaseActivity().getDisplayState(); + if (!state.canForwardToProfileIdMap.equals(canForwardToProfileIdMap)) { + state.canForwardToProfileIdMap = canForwardToProfileIdMap; + if (!UserId.CURRENT_USER.equals(getBaseActivity().getSelectedUser())) { + mActionHandler.loadDocumentsForCurrentStack(); + } + } + } + /** * If the package name of other providers or apps capable of handling the original intent * include the preferred root source, it will have higher order than others. - * @param excludePackage Exclude activities from this given package + * + * @param excludePackage Exclude activities from this given package * @param handlerAppIntent When not null, apps capable of handling the original intent will - * be included in list of roots (in special section at bottom). + * be included in list of roots (in special section at bottom). */ @VisibleForTesting List<Item> sortLoadResult( @@ -355,7 +467,8 @@ public class RootsFragment extends Fragment { ProvidersAccess providersAccess, UserId selectedUser, List<UserId> userIds, - boolean maybeShowBadge) { + boolean maybeShowBadge, + UserManagerState userManagerState) { final List<Item> result = new ArrayList<>(); final RootItemListBuilder librariesBuilder = new RootItemListBuilder(selectedUser, userIds); @@ -368,16 +481,38 @@ public class RootsFragment extends Fragment { if (root.isExternalStorageHome()) { continue; + } else if (hideRootsOnDesktop() && context.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_PC) && (root.isImages() || root.isVideos() + || root.isDocuments() + || root.isAudio())) { + // Hide Images/Videos/Documents/Audio roots on desktop. + Log.d(TAG, "Hiding " + root); + continue; } else if (root.isLibrary() || root.isDownloads()) { - item = new RootItem(root, mActionHandler, maybeShowBadge); + item = + mUseRailAsContainer + ? new NavRailRootItem(root, mActionHandler, maybeShowBadge) + : new RootItem(root, mActionHandler, maybeShowBadge); librariesBuilder.add(item); } else if (root.isStorage()) { - item = new RootItem(root, mActionHandler, maybeShowBadge); + item = + mUseRailAsContainer + ? new NavRailRootItem(root, mActionHandler, maybeShowBadge) + : new RootItem(root, mActionHandler, maybeShowBadge); storageProvidersBuilder.add(item); } else { - item = new RootItem(root, mActionHandler, - providersAccess.getPackageName(root.userId, root.authority), - maybeShowBadge); + item = + mUseRailAsContainer + ? new NavRailRootItem( + root, + mActionHandler, + providersAccess.getPackageName(root.userId, root.authority), + maybeShowBadge) + : new RootItem( + root, + mActionHandler, + providersAccess.getPackageName(root.userId, root.authority), + maybeShowBadge); otherProviders.add(item); } } @@ -401,30 +536,55 @@ public class RootsFragment extends Fragment { final List<Item> rootList = new ArrayList<>(); final List<Item> rootListOtherUser = new ArrayList<>(); + final List<List<Item>> rootListAllUsers = new ArrayList<>(); + for (int i = 0; i < userIds.size(); ++i) { + rootListAllUsers.add(new ArrayList<>()); + } + mApplicationItemList = new ArrayList<>(); if (handlerAppIntent != null) { includeHandlerApps(state, handlerAppIntent, excludePackage, rootList, rootListOtherUser, - otherProviders, userIds, maybeShowBadge); + rootListAllUsers, otherProviders, userIds, maybeShowBadge); } else { // Only add providers - Collections.sort(otherProviders, comp); + otherProviders.sort(comp); for (RootItem item : otherProviders) { - if (UserId.CURRENT_USER.equals(item.userId)) { - rootList.add(item); + if (state.configStore.isPrivateSpaceInDocsUIEnabled()) { + createRootListsPrivateSpaceEnabled(item, userIds, rootListAllUsers); } else { - rootListOtherUser.add(item); + createRootListsPrivateSpaceDisabled(item, rootList, rootListOtherUser); } mApplicationItemList.add(item); } } - List<Item> presentableList = new UserItemsCombiner( - context.getResources(), context.getSystemService(DevicePolicyManager.class), state) + List<Item> presentableList = + state.configStore.isPrivateSpaceInDocsUIEnabled() && SdkLevel.isAtLeastS() + ? getPresentableListPrivateSpaceEnabled( + context, state, rootListAllUsers, userIds, userManagerState) : + getPresentableListPrivateSpaceDisabled(context, state, rootList, + rootListOtherUser); + addListToResult(result, presentableList); + return result; + } + + @RequiresApi(Build.VERSION_CODES.S) + private List<Item> getPresentableListPrivateSpaceEnabled(Context context, State state, + List<List<Item>> rootListAllUsers, List<UserId> userIds, + UserManagerState userManagerState) { + return new UserItemsCombiner(context.getResources(), + context.getSystemService(DevicePolicyManager.class), state) + .setRootListForAllUsers(rootListAllUsers) + .createPresentableListForAllUsers(userIds, userManagerState.getUserIdToLabelMap()); + } + + private List<Item> getPresentableListPrivateSpaceDisabled(Context context, State state, + List<Item> rootList, List<Item> rootListOtherUser) { + return new UserItemsCombiner(context.getResources(), + context.getSystemService(DevicePolicyManager.class), state) .setRootListForCurrentUser(rootList) .setRootListForOtherUser(rootListOtherUser) .createPresentableList(); - addListToResult(result, presentableList); - return result; } private void addListToResult(List<Item> result, List<Item> rootList) { @@ -440,8 +600,8 @@ public class RootsFragment extends Fragment { */ private void includeHandlerApps(State state, Intent handlerAppIntent, @Nullable String excludePackage, List<Item> rootList, - List<Item> rootListOtherUser, List<RootItem> otherProviders, List<UserId> userIds, - boolean maybeShowBadge) { + List<Item> rootListOtherUser, List<List<Item>> rootListAllUsers, + List<RootItem> otherProviders, List<UserId> userIds, boolean maybeShowBadge) { if (VERBOSE) Log.v(TAG, "Adding handler apps for intent: " + handlerAppIntent); Context context = getContext(); @@ -454,6 +614,25 @@ public class RootsFragment extends Fragment { final List<ResolveInfo> infos = pm.queryIntentActivities( handlerAppIntent, PackageManager.MATCH_DEFAULT_ONLY); + // In addition to hiding DocumentsUI from possible handler apps, the Android + // Photopicker should also be hidden. ACTION_PICK_IMAGES is used to identify + // the Photopicker package since that is the primary API. + List<ResolveInfo> photopickerActivities; + List<String> photopickerPackages; + + if (SdkLevel.isAtLeastR() + && SdkExtensions.getExtensionVersion(Build.VERSION_CODES.R) >= 2) { + photopickerActivities = pm.queryIntentActivities( + new Intent(MediaStore.ACTION_PICK_IMAGES), + PackageManager.MATCH_DEFAULT_ONLY); + photopickerPackages = photopickerActivities.stream() + .map(info -> info.activityInfo.packageName) + .collect(Collectors.toList()); + } else { + photopickerActivities = Collections.emptyList(); + photopickerPackages = Collections.emptyList(); + } + // Omit ourselves and maybe calling package from the list for (ResolveInfo info : infos) { if (!info.activityInfo.exported) { @@ -464,14 +643,31 @@ public class RootsFragment extends Fragment { } final String packageName = info.activityInfo.packageName; + + // If the package name for the activity is in the list of Photopicker + // activities, exclude it. + if (photopickerPackages.contains(packageName)) { + continue; + } + if (!myPackageName.equals(packageName) && !TextUtils.equals(excludePackage, packageName)) { UserPackage userPackage = new UserPackage(userId, packageName); appsMapping.put(userPackage, info); if (!CrossProfileUtils.isCrossProfileIntentForwarderActivity(info)) { - final Item item = new AppItem(info, info.loadLabel(pm).toString(), userId, - mActionHandler); + final Item item = + mUseRailAsContainer + ? new NavRailAppItem( + info, + info.loadLabel(pm).toString(), + userId, + mActionHandler) + : new AppItem( + info, + info.loadLabel(pm).toString(), + userId, + mActionHandler); appItems.put(userPackage, item); if (VERBOSE) Log.v(TAG, "Adding handler app: " + item); } @@ -487,36 +683,60 @@ public class RootsFragment extends Fragment { final Item item; if (resolveInfo != null) { - item = new RootAndAppItem(rootItem.root, resolveInfo, mActionHandler, - maybeShowBadge); + item = + mUseRailAsContainer + ? new NavRailRootAndAppItem( + rootItem.root, resolveInfo, mActionHandler, maybeShowBadge) + : new RootAndAppItem( + rootItem.root, resolveInfo, mActionHandler, maybeShowBadge); appItems.remove(userPackage); } else { item = rootItem; } - if (UserId.CURRENT_USER.equals(item.userId)) { - if (VERBOSE) Log.v(TAG, "Adding provider : " + item); - rootList.add(item); + if (state.configStore.isPrivateSpaceInDocsUIEnabled()) { + createRootListsPrivateSpaceEnabled(item, userIds, rootListAllUsers); } else { - if (VERBOSE) Log.v(TAG, "Adding provider to other users : " + item); - rootListOtherUser.add(item); + createRootListsPrivateSpaceDisabled(item, rootList, rootListOtherUser); } } for (Item item : appItems.values()) { - if (UserId.CURRENT_USER.equals(item.userId)) { - rootList.add(item); + if (state.configStore.isPrivateSpaceInDocsUIEnabled()) { + createRootListsPrivateSpaceEnabled(item, userIds, rootListAllUsers); } else { - rootListOtherUser.add(item); + createRootListsPrivateSpaceDisabled(item, rootList, rootListOtherUser); } } final String preferredRootPackage = getResources().getString( R.string.preferred_root_package, ""); final ItemComparator comp = new ItemComparator(preferredRootPackage); - Collections.sort(rootList, comp); - Collections.sort(rootListOtherUser, comp); + if (state.configStore.isPrivateSpaceInDocsUIEnabled()) { + addToApplicationItemListPrivateSpaceEnabled(userIds, rootListAllUsers, comp, state); + } else { + addToApplicationItemListPrivateSpaceDisabled(rootList, rootListOtherUser, comp, state); + } + + } + + private void addToApplicationItemListPrivateSpaceEnabled(List<UserId> userIds, + List<List<Item>> rootListAllUsers, ItemComparator comp, State state) { + for (int i = 0; i < userIds.size(); ++i) { + rootListAllUsers.get(i).sort(comp); + if (UserId.CURRENT_USER.equals(userIds.get(i))) { + mApplicationItemList.addAll(rootListAllUsers.get(i)); + } else if (state.supportsCrossProfile && state.canInteractWith(userIds.get(i))) { + mApplicationItemList.addAll(rootListAllUsers.get(i)); + } + } + } + + private void addToApplicationItemListPrivateSpaceDisabled(List<Item> rootList, + List<Item> rootListOtherUser, ItemComparator comp, State state) { + rootList.sort(comp); + rootListOtherUser.sort(comp); if (state.supportsCrossProfile() && state.canShareAcrossProfile) { mApplicationItemList.addAll(rootList); mApplicationItemList.addAll(rootListOtherUser); @@ -525,6 +745,25 @@ public class RootsFragment extends Fragment { } } + private void createRootListsPrivateSpaceEnabled(Item item, List<UserId> userIds, + List<List<Item>> rootListAllUsers) { + for (int i = 0; i < userIds.size(); ++i) { + if (userIds.get(i).equals(item.userId)) { + rootListAllUsers.get(i).add(item); + break; + } + } + } + + private void createRootListsPrivateSpaceDisabled(Item item, List<Item> rootList, + List<Item> rootListOtherUser) { + if (UserId.CURRENT_USER.equals(item.userId)) { + rootList.add(item); + } else { + rootListOtherUser.add(item); + } + } + @Override public void onResume() { super.onResume(); @@ -611,26 +850,25 @@ public class RootsFragment extends Fragment { return false; } final RootItem rootItem = (RootItem) mAdapter.getItem(adapterMenuInfo.position); - switch (item.getItemId()) { - case R.id.root_menu_eject_root: - final View ejectIcon = adapterMenuInfo.targetView.findViewById(R.id.action_icon); - ejectClicked(ejectIcon, rootItem.root, mActionHandler); - return true; - case R.id.root_menu_open_in_new_window: - mActionHandler.openInNewWindow(new DocumentStack(rootItem.root)); - return true; - case R.id.root_menu_paste_into_folder: - mActionHandler.pasteIntoFolder(rootItem.root); - return true; - case R.id.root_menu_settings: - mActionHandler.openSettings(rootItem.root); - return true; - default: - if (DEBUG) { - Log.d(TAG, "Unhandled menu item selected: " + item); - } - return false; + final int id = item.getItemId(); + if (id == R.id.root_menu_eject_root) { + final View ejectIcon = adapterMenuInfo.targetView.findViewById(R.id.action_icon); + ejectClicked(ejectIcon, rootItem.root, mActionHandler); + return true; + } else if (id == R.id.root_menu_open_in_new_window) { + mActionHandler.openInNewWindow(new DocumentStack(rootItem.root)); + return true; + } else if (id == R.id.root_menu_paste_into_folder) { + mActionHandler.pasteIntoFolder(rootItem.root); + return true; + } else if (id == R.id.root_menu_settings) { + mActionHandler.openSettings(rootItem.root); + return true; + } + if (DEBUG) { + Log.d(TAG, "Unhandled menu item selected: " + item); } + return false; } private void getRootDocument(RootItem rootItem, RootUpdater updater) { @@ -650,8 +888,8 @@ public class RootsFragment extends Fragment { } static void ejectClicked(View ejectIcon, RootInfo root, ActionHandler actionHandler) { - assert(ejectIcon != null); - assert(!root.ejecting); + assert (ejectIcon != null); + assert (!root.ejecting); ejectIcon.setEnabled(false); root.ejecting = true; actionHandler.ejectRoot( diff --git a/src/com/android/documentsui/sidebar/UserItemsCombiner.java b/src/com/android/documentsui/sidebar/UserItemsCombiner.java index 1a68ca778..564a51127 100644 --- a/src/com/android/documentsui/sidebar/UserItemsCombiner.java +++ b/src/com/android/documentsui/sidebar/UserItemsCombiner.java @@ -36,6 +36,7 @@ import com.android.modules.utils.build.SdkLevel; import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * Converts user-specific lists of items into a single merged list appropriate for displaying in the @@ -49,6 +50,7 @@ class UserItemsCombiner { private final State mState; private List<Item> mRootList; private List<Item> mRootListOtherUser; + private List<List<Item>> mRootListAllUsers; UserItemsCombiner(Resources resources, DevicePolicyManager dpm, State state) { mCurrentUser = UserId.CURRENT_USER; @@ -73,6 +75,11 @@ class UserItemsCombiner { return this; } + UserItemsCombiner setRootListForAllUsers(List<List<Item>> listOfRootLists) { + mRootListAllUsers = checkNotNull(listOfRootLists); + return this; + } + /** * Returns a combined lists from the provided lists. {@link HeaderItem}s indicating profile * will be added if the list of current user and the other user are not empty. @@ -109,6 +116,52 @@ class UserItemsCombiner { return result; } + public List<Item> createPresentableListForAllUsers(List<UserId> userIds, + Map<UserId, String> userIdToLabelMap) { + + checkArgument(mRootListAllUsers != null, "RootListForAllUsers is not set"); + + final List<Item> result = new ArrayList<>(); + if (mState.supportsCrossProfile()) { + // headerItemList will hold headers for userIds that are accessible, and + final List<Item> headerItemList = new ArrayList<>(); + int accessibleProfilesCount = 0; + for (int i = 0; i < userIds.size(); ++i) { + // The received user id list contains all users present on the device, + // the headerItemList will contain header item or null at the same index as + // the user id in the received list + if (mState.canInteractWith(userIds.get(i)) + && !mRootListAllUsers.get(i).isEmpty()) { + accessibleProfilesCount += 1; + headerItemList.add(new HeaderItem(userIdToLabelMap.get(userIds.get(i)))); + } else { + headerItemList.add(null); + } + } + // Do not add header item if: + // 1. only the current profile is accessible + // 2. only one profile has non-empty root item list + if (accessibleProfilesCount == 1) { + for (int i = 0; i < userIds.size(); ++i) { + if (headerItemList.get(i) == null) continue; + result.addAll(mRootListAllUsers.get(i)); + break; + } + } else { + for (int i = 0; i < userIds.size(); ++i) { + // Since the header item and the corresponding accessible user id share the same + // index we add the user id along with its non-null header to the result. + if (headerItemList.get(i) == null) continue; + result.add(headerItemList.get(i)); + result.addAll(mRootListAllUsers.get(i)); + } + } + } else { + result.addAll(mRootListAllUsers.get(userIds.indexOf(mCurrentUser))); + } + return result; + } + private String getEnterpriseString(String updatableStringId, int defaultStringId) { if (SdkLevel.isAtLeastT()) { return getUpdatableEnterpriseString(updatableStringId, defaultStringId); diff --git a/src/com/android/documentsui/sorting/HeaderCell.java b/src/com/android/documentsui/sorting/HeaderCell.java index 43e254e39..acdc45235 100644 --- a/src/com/android/documentsui/sorting/HeaderCell.java +++ b/src/com/android/documentsui/sorting/HeaderCell.java @@ -19,8 +19,6 @@ package com.android.documentsui.sorting; import android.animation.AnimatorInflater; import android.animation.LayoutTransition; import android.animation.ObjectAnimator; -import androidx.annotation.AnimatorRes; -import androidx.annotation.StringRes; import android.content.Context; import android.util.AttributeSet; import android.view.Gravity; @@ -29,14 +27,14 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import androidx.annotation.AnimatorRes; +import androidx.annotation.StringRes; + import com.android.documentsui.R; -import com.android.documentsui.sorting.SortDimension; /** - * A clickable, sortable table header cell layout. - * - * It updates its display when it binds to {@link SortDimension} and changes the status of sorting - * when it's clicked. + * A clickable, sortable table header cell layout. It updates its display when it binds to {@link + * SortDimension} and changes the status of sorting when it's clicked. */ public class HeaderCell extends LinearLayout { @@ -62,7 +60,7 @@ public class HeaderCell extends LinearLayout { setVisibility(dimension.getVisibility()); if (dimension.getVisibility() == View.VISIBLE) { - TextView label = (TextView) findViewById(R.id.label); + TextView label = findViewById(R.id.label); label.setText(dimension.getLabelId()); switch (dimension.getDataType()) { case SortDimension.DATA_TYPE_NUMBER: @@ -77,17 +75,21 @@ public class HeaderCell extends LinearLayout { } if (mCurDirection != dimension.getSortDirection()) { - ImageView arrow = (ImageView) findViewById(R.id.sort_arrow); + ImageView arrow = findViewById(R.id.sort_arrow); switch (dimension.getSortDirection()) { case SortDimension.SORT_DIRECTION_NONE: arrow.setVisibility(View.GONE); break; case SortDimension.SORT_DIRECTION_ASCENDING: - showArrow(arrow, R.animator.arrow_rotate_up, + showArrow( + arrow, + R.animator.arrow_rotate_up, R.string.sort_direction_ascending); break; case SortDimension.SORT_DIRECTION_DESCENDING: - showArrow(arrow, R.animator.arrow_rotate_down, + showArrow( + arrow, + R.animator.arrow_rotate_down, R.string.sort_direction_descending); break; default: @@ -100,6 +102,22 @@ public class HeaderCell extends LinearLayout { } } + /** + * Sets a listener on the sort arrow image. When Material 3 is enabled, the Sort Arrow has + * "android:clickable" set to true (to enable a hover state). This stops the click listener from + * falling through to the cell click listener and thus the sort arrow will need to handle clicks + * itself. + */ + public void setSortArrowListeners( + View.OnClickListener clickListener, + View.OnKeyListener keyListener, + SortDimension dimension) { + ImageView arrow = findViewById(R.id.sort_arrow); + arrow.setTag(dimension); + arrow.setOnKeyListener(keyListener); + arrow.setOnClickListener(clickListener); + } + private void showArrow( ImageView arrow, @AnimatorRes int anim, @StringRes int contentDescriptionId) { arrow.setVisibility(View.VISIBLE); diff --git a/src/com/android/documentsui/sorting/SortController.java b/src/com/android/documentsui/sorting/SortController.java index ccfc3f146..4fc28448d 100644 --- a/src/com/android/documentsui/sorting/SortController.java +++ b/src/com/android/documentsui/sorting/SortController.java @@ -16,11 +16,11 @@ package com.android.documentsui.sorting; +import android.view.View; + import androidx.annotation.Nullable; import androidx.fragment.app.FragmentActivity; -import android.view.View; - import com.android.documentsui.BaseActivity; import com.android.documentsui.Injector; import com.android.documentsui.MetricConsts; @@ -67,19 +67,15 @@ public final class SortController { final Injector<?> injector = ((BaseActivity)activity).getInjector(); sortModel.setMetricRecorder((SortDimension dimension) -> { int sortType = MetricConsts.USER_ACTION_UNKNOWN; - switch (dimension.getId()) { - case SortModel.SORT_DIMENSION_ID_TITLE: - sortType = MetricConsts.USER_ACTION_SORT_NAME; - break; - case SortModel.SORT_DIMENSION_ID_SIZE: - sortType = MetricConsts.USER_ACTION_SORT_SIZE; - break; - case SortModel.SORT_DIMENSION_ID_DATE: - sortType = MetricConsts.USER_ACTION_SORT_DATE; - break; - case SortModel.SORT_DIMENSION_ID_FILE_TYPE: - sortType = MetricConsts.USER_ACTION_SORT_TYPE; - break; + final int id = dimension.getId(); + if (id == SortModel.SORT_DIMENSION_ID_TITLE) { + sortType = MetricConsts.USER_ACTION_SORT_NAME; + } else if (id == SortModel.SORT_DIMENSION_ID_SIZE) { + sortType = MetricConsts.USER_ACTION_SORT_SIZE; + } else if (id == SortModel.SORT_DIMENSION_ID_DATE) { + sortType = MetricConsts.USER_ACTION_SORT_DATE; + } else if (id == SortModel.SORT_DIMENSION_ID_FILE_TYPE) { + sortType = MetricConsts.USER_ACTION_SORT_TYPE; } Metrics.logUserAction(sortType); diff --git a/src/com/android/documentsui/sorting/SortListFragment.java b/src/com/android/documentsui/sorting/SortListFragment.java index 7c33c9d3a..8d4032c9e 100644 --- a/src/com/android/documentsui/sorting/SortListFragment.java +++ b/src/com/android/documentsui/sorting/SortListFragment.java @@ -20,7 +20,6 @@ import androidx.fragment.app.FragmentManager; import com.android.documentsui.R; import com.android.documentsui.sorting.SortDimension.SortDirection; -import com.android.documentsui.sorting.SortModel.SortDimensionId; import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetDialog; @@ -66,18 +65,15 @@ public class SortListFragment extends DialogFragment { for (int i = 0; i < mModel.getSize(); ++i) { SortDimension dimension = mModel.getDimensionAt(i); if (dimension.getSortCapability() != SortDimension.SORT_CAPABILITY_NONE) { - switch (dimension.getId()) { - case SortModel.SORT_DIMENSION_ID_TITLE: - case SortModel.SORT_DIMENSION_ID_FILE_TYPE: - addBothDirectionDimension(dimension, true); - break; - case SortModel.SORT_DIMENSION_ID_DATE: - case SortModel.SORT_DIMENSION_ID_SIZE: - addBothDirectionDimension(dimension, false); - break; - default: - mSortingList.add(new SortItem(dimension)); - break; + final int id = dimension.getId(); + if (id == SortModel.SORT_DIMENSION_ID_TITLE + || id == SortModel.SORT_DIMENSION_ID_FILE_TYPE) { + addBothDirectionDimension(dimension, true); + } else if (id == SortModel.SORT_DIMENSION_ID_DATE + || id == SortModel.SORT_DIMENSION_ID_SIZE) { + addBothDirectionDimension(dimension, false); + } else { + mSortingList.add(new SortItem(dimension)); } } } @@ -96,22 +92,21 @@ public class SortListFragment extends DialogFragment { public static @StringRes int getSheetLabelId(SortDimension dimension, @SortDirection int direction) { boolean isAscending = direction == SortDimension.SORT_DIRECTION_ASCENDING; - switch (dimension.getId()) { - case SortModel.SORT_DIMENSION_ID_TITLE: - return isAscending ? R.string.sort_dimension_name_ascending : - R.string.sort_dimension_name_descending; - case SortModel.SORT_DIMENSION_ID_DATE: - return isAscending ? R.string.sort_dimension_date_ascending : - R.string.sort_dimension_date_descending; - case SortModel.SORT_DIMENSION_ID_FILE_TYPE: - return isAscending ? R.string.sort_dimension_file_type_ascending : - R.string.sort_dimension_file_type_descending; - case SortModel.SORT_DIMENSION_ID_SIZE: - return isAscending ? R.string.sort_dimension_size_ascending : - R.string.sort_dimension_size_descending; - default: - return dimension.getLabelId(); + final int id = dimension.getId(); + if (id == SortModel.SORT_DIMENSION_ID_TITLE) { + return isAscending ? R.string.sort_dimension_name_ascending : + R.string.sort_dimension_name_descending; + } else if (id == SortModel.SORT_DIMENSION_ID_DATE) { + return isAscending ? R.string.sort_dimension_date_ascending : + R.string.sort_dimension_date_descending; + } else if (id == SortModel.SORT_DIMENSION_ID_FILE_TYPE) { + return isAscending ? R.string.sort_dimension_file_type_ascending : + R.string.sort_dimension_file_type_descending; + } else if (id == SortModel.SORT_DIMENSION_ID_SIZE) { + return isAscending ? R.string.sort_dimension_size_ascending : + R.string.sort_dimension_size_descending; } + return dimension.getLabelId(); } @Override @@ -170,7 +165,7 @@ public class SortListFragment extends DialogFragment { private static class SortItem { - @SortDimensionId final int id; + final int id; @SortDirection final int direction; @StringRes final int labelId; @@ -180,7 +175,7 @@ public class SortListFragment extends DialogFragment { labelId = dimension.getLabelId(); } - SortItem(@SortDimensionId int id, @SortDirection int direction, @StringRes int labelId) { + SortItem(int id, @SortDirection int direction, @StringRes int labelId) { this.id = id; this.direction = direction; this.labelId = labelId; diff --git a/src/com/android/documentsui/sorting/SortModel.java b/src/com/android/documentsui/sorting/SortModel.java index 4e544a9df..9bf5b9666 100644 --- a/src/com/android/documentsui/sorting/SortModel.java +++ b/src/com/android/documentsui/sorting/SortModel.java @@ -47,16 +47,6 @@ import java.util.function.Consumer; * Sort model that contains all columns and their sorting state. */ public class SortModel implements Parcelable { - @IntDef({ - SORT_DIMENSION_ID_UNKNOWN, - SORT_DIMENSION_ID_TITLE, - SORT_DIMENSION_ID_SUMMARY, - SORT_DIMENSION_ID_SIZE, - SORT_DIMENSION_ID_FILE_TYPE, - SORT_DIMENSION_ID_DATE - }) - @Retention(RetentionPolicy.SOURCE) - public @interface SortDimensionId {} public static final int SORT_DIMENSION_ID_UNKNOWN = 0; public static final int SORT_DIMENSION_ID_TITLE = android.R.id.title; public static final int SORT_DIMENSION_ID_SUMMARY = android.R.id.summary; @@ -239,32 +229,28 @@ public class SortModel implements Parcelable { // should only be called when R.bool.feature_content_paging is true final int id = getSortedDimensionId(); - switch (id) { - case SORT_DIMENSION_ID_UNKNOWN: - return; - case SortModel.SORT_DIMENSION_ID_TITLE: - queryArgs.putStringArray( - ContentResolver.QUERY_ARG_SORT_COLUMNS, - new String[]{ Document.COLUMN_DISPLAY_NAME }); - break; - case SortModel.SORT_DIMENSION_ID_DATE: - queryArgs.putStringArray( - ContentResolver.QUERY_ARG_SORT_COLUMNS, - new String[]{ Document.COLUMN_LAST_MODIFIED }); - break; - case SortModel.SORT_DIMENSION_ID_SIZE: - queryArgs.putStringArray( - ContentResolver.QUERY_ARG_SORT_COLUMNS, - new String[]{ Document.COLUMN_SIZE }); - break; - case SortModel.SORT_DIMENSION_ID_FILE_TYPE: - // Unfortunately sorting by mime type is pretty much guaranteed different from - // sorting by user-friendly type, so there is no point to guide the provider to sort - // in a particular order. - return; - default: - throw new IllegalStateException( - "Unexpected sort dimension id: " + id); + if (id == SORT_DIMENSION_ID_UNKNOWN) { + return; + } else if (id == SortModel.SORT_DIMENSION_ID_TITLE) { + queryArgs.putStringArray( + ContentResolver.QUERY_ARG_SORT_COLUMNS, + new String[]{Document.COLUMN_DISPLAY_NAME}); + } else if (id == SortModel.SORT_DIMENSION_ID_DATE) { + queryArgs.putStringArray( + ContentResolver.QUERY_ARG_SORT_COLUMNS, + new String[]{Document.COLUMN_LAST_MODIFIED}); + } else if (id == SortModel.SORT_DIMENSION_ID_SIZE) { + queryArgs.putStringArray( + ContentResolver.QUERY_ARG_SORT_COLUMNS, + new String[]{Document.COLUMN_SIZE}); + } else if (id == SortModel.SORT_DIMENSION_ID_FILE_TYPE) { + // Unfortunately sorting by mime type is pretty much guaranteed different from + // sorting by user-friendly type, so there is no point to guide the provider to sort + // in a particular order. + return; + } else { + throw new IllegalStateException( + "Unexpected sort dimension id: " + id); } final SortDimension dimension = getDimensionById(id); @@ -296,26 +282,22 @@ public class SortModel implements Parcelable { final int id = getSortedDimensionId(); final String columnName; - switch (id) { - case SORT_DIMENSION_ID_UNKNOWN: - return null; - case SortModel.SORT_DIMENSION_ID_TITLE: - columnName = Document.COLUMN_DISPLAY_NAME; - break; - case SortModel.SORT_DIMENSION_ID_DATE: - columnName = Document.COLUMN_LAST_MODIFIED; - break; - case SortModel.SORT_DIMENSION_ID_SIZE: - columnName = Document.COLUMN_SIZE; - break; - case SortModel.SORT_DIMENSION_ID_FILE_TYPE: - // Unfortunately sorting by mime type is pretty much guaranteed different from - // sorting by user-friendly type, so there is no point to guide the provider to sort - // in a particular order. - return null; - default: - throw new IllegalStateException( - "Unexpected sort dimension id: " + id); + if (id == SORT_DIMENSION_ID_UNKNOWN) { + return null; + } else if (id == SortModel.SORT_DIMENSION_ID_TITLE) { + columnName = Document.COLUMN_DISPLAY_NAME; + } else if (id == SortModel.SORT_DIMENSION_ID_DATE) { + columnName = Document.COLUMN_LAST_MODIFIED; + } else if (id == SortModel.SORT_DIMENSION_ID_SIZE) { + columnName = Document.COLUMN_SIZE; + } else if (id == SortModel.SORT_DIMENSION_ID_FILE_TYPE) { + // Unfortunately sorting by mime type is pretty much guaranteed different from + // sorting by user-friendly type, so there is no point to guide the provider to sort + // in a particular order. + return null; + } else { + throw new IllegalStateException( + "Unexpected sort dimension id: " + id); } final SortDimension dimension = getDimensionById(id); diff --git a/src/com/android/documentsui/sorting/SortingCursorWrapper.java b/src/com/android/documentsui/sorting/SortingCursorWrapper.java index d8c686c3e..1e359a3ab 100644 --- a/src/com/android/documentsui/sorting/SortingCursorWrapper.java +++ b/src/com/android/documentsui/sorting/SortingCursorWrapper.java @@ -27,7 +27,6 @@ import android.provider.DocumentsContract.Document; import com.android.documentsui.base.Lookup; import com.android.documentsui.base.Shared; -import com.android.documentsui.sorting.SortModel.SortDimensionId; /** * Cursor wrapper that presents a sorted view of the underlying cursor. Handles @@ -49,16 +48,13 @@ class SortingCursorWrapper extends AbstractCursor { long[] longValues = null; String[] ids = new String[count]; - final @SortDimensionId int id = dimension.getId(); - switch (id) { - case SortModel.SORT_DIMENSION_ID_TITLE: - case SortModel.SORT_DIMENSION_ID_FILE_TYPE: - stringValues = new String[count]; - break; - case SortModel.SORT_DIMENSION_ID_DATE: - case SortModel.SORT_DIMENSION_ID_SIZE: - longValues = new long[count]; - break; + final int id = dimension.getId(); + if (id == SortModel.SORT_DIMENSION_ID_TITLE + || id == SortModel.SORT_DIMENSION_ID_FILE_TYPE) { + stringValues = new String[count]; + } else if (id == SortModel.SORT_DIMENSION_ID_DATE + || id == SortModel.SORT_DIMENSION_ID_SIZE) { + longValues = new long[count]; } cursor.moveToPosition(-1); @@ -70,34 +66,26 @@ class SortingCursorWrapper extends AbstractCursor { isDirs[i] = Document.MIME_TYPE_DIR.equals(mimeType); ids[i] = getCursorString(mCursor, Document.COLUMN_DOCUMENT_ID); - switch(id) { - case SortModel.SORT_DIMENSION_ID_TITLE: - final String displayName = getCursorString( - mCursor, Document.COLUMN_DISPLAY_NAME); - stringValues[i] = displayName; - break; - case SortModel.SORT_DIMENSION_ID_FILE_TYPE: - stringValues[i] = fileTypeLookup.lookup(mimeType); - break; - case SortModel.SORT_DIMENSION_ID_DATE: - longValues[i] = getLastModified(mCursor); - break; - case SortModel.SORT_DIMENSION_ID_SIZE: - longValues[i] = getCursorLong(mCursor, Document.COLUMN_SIZE); - break; + if (id == SortModel.SORT_DIMENSION_ID_TITLE) { + final String displayName = getCursorString( + mCursor, Document.COLUMN_DISPLAY_NAME); + stringValues[i] = displayName; + } else if (id == SortModel.SORT_DIMENSION_ID_FILE_TYPE) { + stringValues[i] = fileTypeLookup.lookup(mimeType); + } else if (id == SortModel.SORT_DIMENSION_ID_DATE) { + longValues[i] = getLastModified(mCursor); + } else if (id == SortModel.SORT_DIMENSION_ID_SIZE) { + longValues[i] = getCursorLong(mCursor, Document.COLUMN_SIZE); } } - switch (id) { - case SortModel.SORT_DIMENSION_ID_TITLE: - case SortModel.SORT_DIMENSION_ID_FILE_TYPE: - binarySort(stringValues, isDirs, mPosition, ids, dimension.getSortDirection()); - break; - case SortModel.SORT_DIMENSION_ID_DATE: - case SortModel.SORT_DIMENSION_ID_SIZE: - binarySort(longValues, isDirs, mPosition, ids, dimension.getSortDirection()); - break; + if (id == SortModel.SORT_DIMENSION_ID_TITLE + || id == SortModel.SORT_DIMENSION_ID_FILE_TYPE) { + binarySort(stringValues, isDirs, mPosition, ids, dimension.getSortDirection()); + } else if (id == SortModel.SORT_DIMENSION_ID_DATE + || id == SortModel.SORT_DIMENSION_ID_SIZE) { + binarySort(longValues, isDirs, mPosition, ids, dimension.getSortDirection()); } } diff --git a/src/com/android/documentsui/sorting/TableHeaderController.java b/src/com/android/documentsui/sorting/TableHeaderController.java index f3853c08f..52fa465a9 100644 --- a/src/com/android/documentsui/sorting/TableHeaderController.java +++ b/src/com/android/documentsui/sorting/TableHeaderController.java @@ -16,50 +16,54 @@ package com.android.documentsui.sorting; +import static com.android.documentsui.flags.Flags.useMaterial3; + +import android.view.KeyEvent; import android.view.View; import com.android.documentsui.R; -import com.android.documentsui.sorting.SortModel.SortDimensionId; import javax.annotation.Nullable; -/** - * View controller for table header that associates header cells in table header and columns. - */ +/** View controller for table header that associates header cells in table header and columns. */ public final class TableHeaderController implements SortController.WidgetController { - private View mTableHeader; - private final HeaderCell mTitleCell; private final HeaderCell mSummaryCell; private final HeaderCell mSizeCell; private final HeaderCell mFileTypeCell; private final HeaderCell mDateCell; - + private final SortModel mModel; // We assign this here porque each method reference creates a new object // instance (which is wasteful). private final View.OnClickListener mOnCellClickListener = this::onCellClicked; + private final View.OnKeyListener mOnCellKeyListener = this::onCellKeyEvent; private final SortModel.UpdateListener mModelListener = this::onModelUpdate; - - private final SortModel mModel; + private final View mTableHeader; private TableHeaderController(SortModel sortModel, View tableHeader) { - assert(sortModel != null); - assert(tableHeader != null); + assert (sortModel != null); + assert (tableHeader != null); mModel = sortModel; mTableHeader = tableHeader; - mTitleCell = (HeaderCell) tableHeader.findViewById(android.R.id.title); - mSummaryCell = (HeaderCell) tableHeader.findViewById(android.R.id.summary); - mSizeCell = (HeaderCell) tableHeader.findViewById(R.id.size); - mFileTypeCell = (HeaderCell) tableHeader.findViewById(R.id.file_type); - mDateCell = (HeaderCell) tableHeader.findViewById(R.id.date); + mTitleCell = tableHeader.findViewById(android.R.id.title); + mSummaryCell = tableHeader.findViewById(android.R.id.summary); + mSizeCell = tableHeader.findViewById(R.id.size); + mFileTypeCell = tableHeader.findViewById(R.id.file_type); + mDateCell = tableHeader.findViewById(R.id.date); onModelUpdate(mModel, SortModel.UPDATE_TYPE_UNSPECIFIED); mModel.addListener(mModelListener); } + /** Creates a TableHeaderController. */ + public static @Nullable TableHeaderController create( + SortModel sortModel, @Nullable View tableHeader) { + return (tableHeader == null) ? null : new TableHeaderController(sortModel, tableHeader); + } + private void onModelUpdate(SortModel model, int updateTypeUnspecified) { bindCell(mTitleCell, SortModel.SORT_DIMENSION_ID_TITLE); bindCell(mSummaryCell, SortModel.SORT_DIMENSION_ID_SUMMARY); @@ -78,8 +82,8 @@ public final class TableHeaderController implements SortController.WidgetControl mModel.removeListener(mModelListener); } - private void bindCell(HeaderCell cell, @SortDimensionId int id) { - assert(cell != null); + private void bindCell(HeaderCell cell, int id) { + assert (cell != null); SortDimension dimension = mModel.getDimensionById(id); cell.setTag(dimension); @@ -88,8 +92,12 @@ public final class TableHeaderController implements SortController.WidgetControl if (dimension.getVisibility() == View.VISIBLE && dimension.getSortCapability() != SortDimension.SORT_CAPABILITY_NONE) { cell.setOnClickListener(mOnCellClickListener); + if (useMaterial3()) { + cell.setSortArrowListeners(mOnCellClickListener, mOnCellKeyListener, dimension); + } } else { cell.setOnClickListener(null); + if (useMaterial3()) cell.setSortArrowListeners(null, null, null); } } @@ -99,8 +107,17 @@ public final class TableHeaderController implements SortController.WidgetControl mModel.sortByUser(dimension.getId(), dimension.getNextDirection()); } - public static @Nullable TableHeaderController create( - SortModel sortModel, @Nullable View tableHeader) { - return (tableHeader == null) ? null : new TableHeaderController(sortModel, tableHeader); + /** Sorts the column if the key pressed was Enter or Space. */ + private boolean onCellKeyEvent(View v, int keyCode, KeyEvent event) { + if (!useMaterial3()) { + return false; + } + // Only the enter and space bar should trigger the sort header to engage. + if (event.getAction() == KeyEvent.ACTION_UP + && (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_SPACE)) { + onCellClicked(v); + return true; + } + return false; } } diff --git a/src/com/android/documentsui/ui/DocumentDebugInfo.java b/src/com/android/documentsui/ui/DocumentDebugInfo.java deleted file mode 100644 index b7712c60a..000000000 --- a/src/com/android/documentsui/ui/DocumentDebugInfo.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2015 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.documentsui.ui; - -import androidx.annotation.Nullable; -import android.content.Context; -import android.util.AttributeSet; -import android.widget.TextView; - -import com.android.documentsui.base.DocumentInfo; - -/** - * Document debug info view. - */ -public class DocumentDebugInfo extends TextView { - public DocumentDebugInfo(Context context) { - super(context); - - } - - public DocumentDebugInfo(Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - } - - public void update(DocumentInfo doc) { - - String dbgInfo = new StringBuilder() - .append("** PROPERTIES **\n\n") - .append("docid: " + doc.documentId).append("\n") - .append("name: " + doc.displayName).append("\n") - .append("mimetype: " + doc.mimeType).append("\n") - .append("container: " + doc.isContainer()).append("\n") - .append("virtual: " + doc.isVirtual()).append("\n") - .append("\n") - .append("** OPERATIONS **\n\n") - .append("create: " + doc.isCreateSupported()).append("\n") - .append("delete: " + doc.isDeleteSupported()).append("\n") - .append("rename: " + doc.isRenameSupported()).append("\n\n") - .append("** URI **\n\n") - .append(doc.derivedUri).append("\n") - .toString(); - - setText(dbgInfo); - } -} diff --git a/src/com/android/documentsui/ui/Snackbars.java b/src/com/android/documentsui/ui/Snackbars.java index b45c247b5..c6eaf4661 100644 --- a/src/com/android/documentsui/ui/Snackbars.java +++ b/src/com/android/documentsui/ui/Snackbars.java @@ -16,6 +16,8 @@ package com.android.documentsui.ui; +import static com.android.documentsui.flags.Flags.useMaterial3; + import android.app.Activity; import android.view.Gravity; import android.view.View; @@ -110,7 +112,10 @@ public final class Snackbars { public static final Snackbar makeSnackbar( Activity activity, CharSequence message, int duration) { - final View view = activity.findViewById(R.id.container_save); + final View view = activity.findViewById(useMaterial3() + ? R.id.coordinator_layout + : R.id.container_save + ); return Snackbar.make(view, message, duration); } } diff --git a/src/com/android/documentsui/util/CrossProfileUtils.java b/src/com/android/documentsui/util/CrossProfileUtils.java index e60ffdddc..3b53847ae 100644 --- a/src/com/android/documentsui/util/CrossProfileUtils.java +++ b/src/com/android/documentsui/util/CrossProfileUtils.java @@ -16,16 +16,27 @@ package com.android.documentsui.util; +import android.annotation.TargetApi; +import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.pm.UserProperties; +import android.os.UserHandle; +import android.os.UserManager; +import android.util.Log; import androidx.annotation.Nullable; +import com.android.documentsui.base.UserId; +import com.android.modules.utils.build.SdkLevel; + /** * A utility class for cross-profile usage. */ public class CrossProfileUtils { + + private static final String TAG = "CrossProfileUtils"; private static final String PROFILE_TARGET_ACTIVITY = "com.android.internal.app.IntentForwarderActivity"; @@ -46,11 +57,55 @@ public class CrossProfileUtils { } /** - * Returns the {@ResolveInfo} if this intent is a cross-profile intent or {@code null} + * Returns the {@link ResolveInfo} if this intent is a cross-profile intent or {@code null} * otherwise. */ @Nullable - public static ResolveInfo getCrossProfileResolveInfo(PackageManager packageManager, + public static ResolveInfo getCrossProfileResolveInfo(UserId currentUser, + PackageManager packageManager, Intent intent, Context context, + boolean isPrivateSpaceEnabled) { + if (isPrivateSpaceEnabled && SdkLevel.isAtLeastV()) { + return getCrossProfileResolveInfoPostV(currentUser, packageManager, + intent, context); + } + return getCrossProfileResolveInfoPreV(packageManager, intent); + } + + @Nullable + @TargetApi(35) + private static ResolveInfo getCrossProfileResolveInfoPostV( + UserId currentUser, PackageManager packageManager, + Intent intent, Context context) { + UserManager userManager = context.getSystemService(UserManager.class); + UserHandle queringUser = UserHandle.of(currentUser.getIdentifier()); + if (userManager == null) { + Log.e(TAG, "cannot obtain user manager"); + return null; + } + + UserProperties userProperties = userManager.getUserProperties(queringUser); + if (userProperties == null) { + Log.e(TAG, "cannot obtain user properties"); + return null; + } + + if (userProperties.getCrossProfileContentSharingStrategy() + == UserProperties.CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT) { + queringUser = userManager.getProfileParent(queringUser); + } + + for (ResolveInfo info : packageManager.queryIntentActivitiesAsUser(intent, + PackageManager.MATCH_DEFAULT_ONLY, queringUser)) { + if (isCrossProfileIntentForwarderActivity(info)) { + return info; + } + } + return null; + } + + @Nullable + private static ResolveInfo getCrossProfileResolveInfoPreV( + PackageManager packageManager, Intent intent) { for (ResolveInfo info : packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)) { diff --git a/tests/Android.bp b/tests/Android.bp index 7a5d63112..f67d344dd 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -16,86 +16,123 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } -filegroup { - name: "DocumentsUIPerfTests-files", +java_defaults { + name: "DocumentsUITests-defaults", + libs: [ + "android.test.base.stubs.system", + "android.test.mock.stubs.system", + "android.test.runner.stubs.system", + ], + + static_libs: [ + "androidx.test.core", + "androidx.test.espresso.core", + "androidx.test.ext.truth", + "androidx.test.rules", + "androidx.test.ext.junit", + "androidx.test.uiautomator_uiautomator", + "docsui-flags-aconfig-java-lib", + "flag-junit", + "guava", + "mockito-target", + ], +} + +android_library { + name: "DocumentsUIPerfTests-lib", srcs: [ "common/com/android/documentsui/**/*.java", "functional/com/android/documentsui/ActivityTest.java", ], -} + resource_dirs: [], + libs: [ + "android.test.base.stubs.system", + "android.test.mock.stubs.system", + "android.test.runner.stubs.system", + "DocumentsUI-lib", + ], -filegroup { - name: "DocumentsUITests-srcs", - srcs: [ - "common/**/*.java", - "functional/**/*.java", - "unit/**/*.java", + static_libs: [ + "androidx.legacy_legacy-support-v4", + "androidx.test.espresso.core", + "androidx.test.rules", + "androidx.test.uiautomator_uiautomator", + "mockito-target", + "ub-janktesthelper", ], } -filegroup { - name: "DocumentsUIUnitTests-srcs", +android_library { + name: "DocumentsUIUnitTests-lib", + defaults: ["DocumentsUITests-defaults"], + + manifest: "AndroidManifestUnitTests.xml", + srcs: [ "common/**/*.java", "unit/**/*.java", + "unit/**/*.kt", ], -} - -android_library { - name: "DocumentsUITests-res-lib", - - manifest: "AndroidManifest.xml", - asset_dirs: [ - "assets", + libs: [ + "DocumentsUI-lib", ], resource_dirs: [ "res", ], - aaptflags: [ - // pack some raw file locate in assets folder - "-0 .zip", - "--auto-add-overlay", - ], - - min_sdk_version : "29", - target_sdk_version : "29", + min_sdk_version: "29", + target_sdk_version: "29", } -android_test { - name: "DocumentsUITests", +android_library { + name: "DocumentsUITests-lib", + defaults: ["DocumentsUITests-defaults"], manifest: "AndroidManifest.xml", srcs: [ "common/**/*.java", "functional/**/*.java", + "functional/**/*.kt", "unit/**/*.java", ], + libs: [ + "DocumentsUI-lib", + ], + + asset_dirs: [ + "assets", + ], + resource_dirs: [ "res", ], aaptflags: [ + // pack some raw file locate in assets folder "-0 .zip", ], - libs: [ - "android.test.base", - "android.test.mock", - "android.test.runner", - ], + min_sdk_version: "29", + target_sdk_version: "29", + lint: { + baseline_filename: "lint-baseline.xml", + }, +} + +android_test { + name: "DocumentsUITests", + defaults: ["DocumentsUITests-defaults"], + + manifest: "AndroidManifest.xml", + + resource_dirs: [], static_libs: [ - "androidx.test.rules", - "androidx.test.espresso.core", - "androidx.test.ext.truth", - "guava", - "mockito-target", - "ub-uiautomator", + "DocumentsUITests-lib", ], jarjar_rules: "jarjar-rules.txt", @@ -110,6 +147,6 @@ android_test { certificate: "platform", instrumentation_for: "DocumentsUI", - min_sdk_version : "29", - target_sdk_version : "29", + min_sdk_version: "29", + target_sdk_version: "29", } diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml index d5e9a6045..c64b7aedd 100644 --- a/tests/AndroidManifest.xml +++ b/tests/AndroidManifest.xml @@ -2,7 +2,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.documentsui.tests"> - <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/> + <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30"/> <uses-permission android:name="android.permission.INTERNET" /> diff --git a/tests/AndroidManifestUnitTests.xml b/tests/AndroidManifestUnitTests.xml new file mode 100644 index 000000000..13d7a08f7 --- /dev/null +++ b/tests/AndroidManifestUnitTests.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.documentsui.tests"> + +</manifest> diff --git a/tests/AndroidTest.xml b/tests/AndroidTest.xml index 7874118db..c5a00a2ea 100644 --- a/tests/AndroidTest.xml +++ b/tests/AndroidTest.xml @@ -18,6 +18,14 @@ <option name="test-file-name" value="DocumentsUITests.apk" /> </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> + <!-- Disable keyguard --> + <!-- Though keyguard is disabled globally in cts-preconditions.xml, this will ensure that + the test gets the same treatment when running in other test suites (e.g. MTS), as well + as when running locally (e.g. via atest) --> + <option name="run-command" value="locksettings set-disabled true" /> + </target_preparer> + <option name="test-suite-tag" value="apct" /> <option name="test-tag" value="DocumentsUITests" /> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > diff --git a/tests/common/com/android/documentsui/TestActivity.java b/tests/common/com/android/documentsui/TestActivity.java index 2506bdf96..5aa3faace 100644 --- a/tests/common/com/android/documentsui/TestActivity.java +++ b/tests/common/com/android/documentsui/TestActivity.java @@ -260,9 +260,28 @@ public abstract class TestActivity extends AbstractBase { } @Override + public final String getSystemServiceName(Class<?> serviceName) { + if (serviceName == UserManager.class) { + return Context.USER_SERVICE; + } + throw new IllegalArgumentException("Unknown service name " + serviceName); + } + + @Override public final void finish() { finishedHandler.accept(null); } + + @Override + public boolean isInMultiWindowMode() { + // We are seeing this causing NPEs on older platform versions of some OEM, e.g. b/297710004. + // Hence we'll wrap this in a try-catch. + try { + return super.isInMultiWindowMode(); + } catch (Exception e) { + return false; + } + } } // Trick Mockito into finding our Addons methods correctly. W/o this diff --git a/tests/common/com/android/documentsui/TestConfigStore.java b/tests/common/com/android/documentsui/TestConfigStore.java new file mode 100644 index 000000000..2e29b0caa --- /dev/null +++ b/tests/common/com/android/documentsui/TestConfigStore.java @@ -0,0 +1,41 @@ +/* + * 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.documentsui; + +import com.android.modules.utils.build.SdkLevel; + +public class TestConfigStore implements ConfigStore { + private boolean mIsPrivateSpaceEnabled = false; + + /** + * Enables private space flag for PhotoPicker in test config + */ + public void enablePrivateSpaceInPhotoPicker() { + mIsPrivateSpaceEnabled = true; + } + /** + * Disables private space flag for PhotoPicker in test config + */ + public void disablePrivateSpaceInPhotoPicker() { + mIsPrivateSpaceEnabled = false; + } + + @Override + public boolean isPrivateSpaceInDocsUIEnabled() { + return SdkLevel.isAtLeastS() && mIsPrivateSpaceEnabled; + } +} diff --git a/tests/common/com/android/documentsui/TestUserManagerState.java b/tests/common/com/android/documentsui/TestUserManagerState.java new file mode 100644 index 000000000..b7647f65d --- /dev/null +++ b/tests/common/com/android/documentsui/TestUserManagerState.java @@ -0,0 +1,96 @@ +/* + * 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.documentsui; + +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.util.Log; + +import androidx.annotation.RequiresApi; + +import com.android.documentsui.base.UserId; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RequiresApi(Build.VERSION_CODES.S) +public class TestUserManagerState implements UserManagerState { + + private static final String TAG = "TestUserManagerState"; + public List<UserId> userIds = new ArrayList<>(); + public Map<UserId, String> userIdToLabelMap = new HashMap<>(); + public Map<UserId, Boolean> canFrowardToProfileIdMap = new HashMap<>(); + public Map<UserId, Drawable> userIdToBadgeMap = new HashMap<>(); + public String profileLabel = "Test"; + public Drawable profileBadge = null; + public Intent intent = new Intent(); + + @Override + public List<UserId> getUserIds() { + return userIds; + } + + @Override + public Map<UserId, String> getUserIdToLabelMap() { + return userIdToLabelMap; + } + + @Override + public Map<UserId, Drawable> getUserIdToBadgeMap() { + return userIdToBadgeMap; + } + + @Override + public Map<UserId, Boolean> getCanForwardToProfileIdMap(Intent intent) { + return canFrowardToProfileIdMap; + } + + @Override + public void onProfileActionStatusChange(String action, UserId userId) { + if (Intent.ACTION_PROFILE_UNAVAILABLE.equals(action)) { + userIds.remove(userId); + return; + } else if (Intent.ACTION_PROFILE_AVAILABLE.equals(action)) { + if (!userIds.contains(userId)) { + userIds.add(userId); + } + if (!userIdToLabelMap.containsKey(userId)) { + userIdToLabelMap.put(userId, profileLabel); + } + if (!userIdToBadgeMap.containsKey(userId)) { + userIdToBadgeMap.put(userId, profileBadge); + } + if (!canFrowardToProfileIdMap.containsKey(userId)) { + canFrowardToProfileIdMap.put(userId, true); + } + } else { + Log.e(TAG, "Unexpected action received: " + action); + } + } + + @Override + public void setCurrentStateIntent(Intent intent) { + } + + @Override + public boolean areHiddenInQuietModeProfilesPresent() { + return false; + } +} diff --git a/tests/common/com/android/documentsui/bots/Bots.java b/tests/common/com/android/documentsui/bots/Bots.java index 8a3d347ec..8cc00ac7a 100644 --- a/tests/common/com/android/documentsui/bots/Bots.java +++ b/tests/common/com/android/documentsui/bots/Bots.java @@ -20,15 +20,15 @@ import static junit.framework.Assert.assertNotNull; import android.app.UiAutomation; import android.content.Context; -import android.support.test.uiautomator.By; -import android.support.test.uiautomator.BySelector; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiObject; -import android.support.test.uiautomator.UiObject2; -import android.support.test.uiautomator.UiSelector; -import android.support.test.uiautomator.Until; import androidx.test.InstrumentationRegistry; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.BySelector; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject; +import androidx.test.uiautomator.UiObject2; +import androidx.test.uiautomator.UiSelector; +import androidx.test.uiautomator.Until; /** * Handy collection of bots for working with Files app. diff --git a/tests/common/com/android/documentsui/bots/BreadBot.java b/tests/common/com/android/documentsui/bots/BreadBot.java index d022f52f2..7c1a81b3a 100644 --- a/tests/common/com/android/documentsui/bots/BreadBot.java +++ b/tests/common/com/android/documentsui/bots/BreadBot.java @@ -17,9 +17,10 @@ package com.android.documentsui.bots; import android.content.Context; -import android.support.test.uiautomator.By; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiObject2; + +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject2; import junit.framework.Assert; diff --git a/tests/common/com/android/documentsui/bots/DirectoryListBot.java b/tests/common/com/android/documentsui/bots/DirectoryListBot.java index 9fbc39f2a..3e9fa30b8 100644 --- a/tests/common/com/android/documentsui/bots/DirectoryListBot.java +++ b/tests/common/com/android/documentsui/bots/DirectoryListBot.java @@ -27,21 +27,22 @@ import android.content.Context; import android.graphics.Point; import android.graphics.Rect; import android.os.SystemClock; -import android.support.test.uiautomator.By; -import android.support.test.uiautomator.BySelector; -import android.support.test.uiautomator.Configurator; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiObject; -import android.support.test.uiautomator.UiObject2; -import android.support.test.uiautomator.UiObjectNotFoundException; -import android.support.test.uiautomator.UiScrollable; -import android.support.test.uiautomator.UiSelector; -import android.support.test.uiautomator.Until; import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.BySelector; +import androidx.test.uiautomator.Configurator; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject; +import androidx.test.uiautomator.UiObject2; +import androidx.test.uiautomator.UiObjectNotFoundException; +import androidx.test.uiautomator.UiScrollable; +import androidx.test.uiautomator.UiSelector; +import androidx.test.uiautomator.Until; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; diff --git a/tests/common/com/android/documentsui/bots/GestureBot.java b/tests/common/com/android/documentsui/bots/GestureBot.java index 9a0fb6ea1..4c7f7c7c9 100644 --- a/tests/common/com/android/documentsui/bots/GestureBot.java +++ b/tests/common/com/android/documentsui/bots/GestureBot.java @@ -21,16 +21,17 @@ import android.content.Context; import android.graphics.Point; import android.graphics.Rect; import android.os.SystemClock; -import android.support.test.uiautomator.Configurator; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiObject; -import android.support.test.uiautomator.UiObjectNotFoundException; -import android.support.test.uiautomator.UiSelector; import android.view.InputDevice; import android.view.MotionEvent; import android.view.MotionEvent.PointerCoords; import android.view.MotionEvent.PointerProperties; +import androidx.test.uiautomator.Configurator; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject; +import androidx.test.uiautomator.UiObjectNotFoundException; +import androidx.test.uiautomator.UiSelector; + /** * A test helper class that provides support for controlling directory list * and making assertions against the state of it. diff --git a/tests/common/com/android/documentsui/bots/InspectorBot.java b/tests/common/com/android/documentsui/bots/InspectorBot.java index 252fde452..7e459db04 100644 --- a/tests/common/com/android/documentsui/bots/InspectorBot.java +++ b/tests/common/com/android/documentsui/bots/InspectorBot.java @@ -20,12 +20,13 @@ import static junit.framework.Assert.assertTrue; import android.app.Activity; import android.content.Context; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiSelector; import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiSelector; + import com.android.documentsui.R; import com.android.documentsui.inspector.DetailsView; import com.android.documentsui.inspector.KeyValueRow; diff --git a/tests/common/com/android/documentsui/bots/KeyboardBot.java b/tests/common/com/android/documentsui/bots/KeyboardBot.java index 6167acfc0..7cd3eedef 100644 --- a/tests/common/com/android/documentsui/bots/KeyboardBot.java +++ b/tests/common/com/android/documentsui/bots/KeyboardBot.java @@ -21,10 +21,11 @@ import static androidx.test.espresso.action.ViewActions.pressImeActionButton; import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom; import android.content.Context; -import android.support.test.uiautomator.UiDevice; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; +import androidx.test.uiautomator.UiDevice; + /** * A test helper class that provides support for keyboard manipulation. */ diff --git a/tests/common/com/android/documentsui/bots/MenuBot.java b/tests/common/com/android/documentsui/bots/MenuBot.java index 511c51e4a..58e82e44c 100644 --- a/tests/common/com/android/documentsui/bots/MenuBot.java +++ b/tests/common/com/android/documentsui/bots/MenuBot.java @@ -16,13 +16,14 @@ package com.android.documentsui.bots; -import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; import android.content.Context; -import android.support.test.uiautomator.By; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiObjectNotFoundException; + +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObjectNotFoundException; import java.util.Map; diff --git a/tests/common/com/android/documentsui/bots/NotificationsBot.java b/tests/common/com/android/documentsui/bots/NotificationsBot.java index 5ab872df5..5200ddb06 100644 --- a/tests/common/com/android/documentsui/bots/NotificationsBot.java +++ b/tests/common/com/android/documentsui/bots/NotificationsBot.java @@ -19,9 +19,9 @@ package com.android.documentsui.bots; import android.app.Activity; import android.content.ComponentName; import android.content.Context; -import android.support.test.uiautomator.UiDevice; import androidx.test.InstrumentationRegistry; +import androidx.test.uiautomator.UiDevice; import com.android.documentsui.services.TestNotificationService; diff --git a/tests/common/com/android/documentsui/bots/SearchBot.java b/tests/common/com/android/documentsui/bots/SearchBot.java index d14fd1375..bde74cab7 100644 --- a/tests/common/com/android/documentsui/bots/SearchBot.java +++ b/tests/common/com/android/documentsui/bots/SearchBot.java @@ -31,13 +31,14 @@ import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.anyOf; import android.content.Context; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiObject; -import android.support.test.uiautomator.UiObjectNotFoundException; -import android.support.test.uiautomator.UiSelector; import android.view.View; -import androidx.recyclerview.R; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject; +import androidx.test.uiautomator.UiObjectNotFoundException; +import androidx.test.uiautomator.UiSelector; + +import com.android.documentsui.R; import org.hamcrest.Matcher; @@ -60,7 +61,7 @@ public class SearchBot extends Bots.BaseBot { // require this input be not clickable. @SuppressWarnings("unchecked") private static final Matcher<View> SEARCH_INPUT = allOf( - withId(R.id.search_src_text), + withId(androidx.appcompat.R.id.search_src_text), isDisplayed()); public SearchBot(UiDevice device, Context context, int timeout) { diff --git a/tests/common/com/android/documentsui/bots/SidebarBot.java b/tests/common/com/android/documentsui/bots/SidebarBot.java index 4e961260d..01f311a7f 100644 --- a/tests/common/com/android/documentsui/bots/SidebarBot.java +++ b/tests/common/com/android/documentsui/bots/SidebarBot.java @@ -22,14 +22,15 @@ import static androidx.test.espresso.action.ViewActions.swipeRight; import static androidx.test.espresso.matcher.ViewMatchers.withId; import android.content.Context; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiObject; -import android.support.test.uiautomator.UiObjectNotFoundException; -import android.support.test.uiautomator.UiScrollable; -import android.support.test.uiautomator.UiSelector; import android.util.Log; import android.view.View; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject; +import androidx.test.uiautomator.UiObjectNotFoundException; +import androidx.test.uiautomator.UiScrollable; +import androidx.test.uiautomator.UiSelector; + import com.android.documentsui.R; import junit.framework.Assert; diff --git a/tests/common/com/android/documentsui/bots/SortBot.java b/tests/common/com/android/documentsui/bots/SortBot.java index 6b6f81788..f72f16f86 100644 --- a/tests/common/com/android/documentsui/bots/SortBot.java +++ b/tests/common/com/android/documentsui/bots/SortBot.java @@ -33,27 +33,27 @@ import static junit.framework.Assert.assertTrue; import static org.hamcrest.Matchers.allOf; import android.content.Context; -import android.support.test.uiautomator.By; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiObject2; import android.view.View; import androidx.annotation.StringRes; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject2; import com.android.documentsui.R; import com.android.documentsui.sorting.SortDimension; import com.android.documentsui.sorting.SortDimension.SortDirection; import com.android.documentsui.sorting.SortListFragment; import com.android.documentsui.sorting.SortModel; -import com.android.documentsui.sorting.SortModel.SortDimensionId; import org.hamcrest.Matcher; /** - * A test helper class that provides support for controlling the UI Breadcrumb - * programmatically, and making assertions against the state of the UI. - * <p> - * Support for working directly with Roots and Directory view can be found in the respective bots. + * A test helper class that provides support for controlling the UI Breadcrumb programmatically, and + * making assertions against the state of the UI. + * + * <p>Support for working directly with Roots and Directory view can be found in the respective + * bots. */ public class SortBot extends Bots.BaseBot { @@ -67,8 +67,8 @@ public class SortBot extends Bots.BaseBot { mUiBot = uiBot; } - public void sortBy(@SortDimensionId int id, @SortDirection int direction) { - assert(direction != SortDimension.SORT_DIRECTION_NONE); + public void sortBy(int id, @SortDirection int direction) { + assert (direction != SortDimension.SORT_DIRECTION_NONE); final @StringRes int labelId = mSortModel.getDimensionById(id).getLabelId(); final String label = mContext.getString(labelId); @@ -79,16 +79,15 @@ public class SortBot extends Bots.BaseBot { result = sortByMenu(id, direction); } - assertTrue("Sorting by id: " + id + " in direction: " + direction + " failed.", - result); + assertTrue("Sorting by id: " + id + " in direction: " + direction + " failed.", result); } public boolean isHeaderShow() { - return Matchers.present(mColumnBot.MATCHER); + return Matchers.present(ColumnSortBot.MATCHER); } public void assertHeaderHide() { - assertFalse(Matchers.present(mColumnBot.MATCHER)); + assertFalse(Matchers.present(ColumnSortBot.MATCHER)); } public void assertHeaderShow() { @@ -99,11 +98,21 @@ public class SortBot extends Bots.BaseBot { // or with espresso. It's sad that I'm leaving you // with this little gremlin, but we all have to // move on and get stuff done :) - assertTrue(Matchers.present(mColumnBot.MATCHER)); + assertTrue(Matchers.present(ColumnSortBot.MATCHER)); + } + + /** + * Identify if the sort arrow in list mode is focused. + * + * @return True if the sort arrow in the file list is found. + */ + public boolean isSortIconFocused() { + UiObject2 sortArrow = mDevice.findObject(By.res(mTargetPackage + ":id/sort_arrow")); + return sortArrow.isFocused(); } - private boolean sortByMenu(@SortDimensionId int id, @SortDirection int direction) { - assert(direction != SortDimension.SORT_DIRECTION_NONE); + private boolean sortByMenu(int id, @SortDirection int direction) { + assert (direction != SortDimension.SORT_DIRECTION_NONE); clickMenuSort(); mDevice.waitForIdle(); @@ -132,9 +141,8 @@ public class SortBot extends Bots.BaseBot { private static final Matcher<View> MATCHER = withId(R.id.table_header); private boolean sortBy(String label, @SortDirection int direction) { - final Matcher<View> cellMatcher = allOf( - withChild(withText(label)), - isDescendantOfA(MATCHER)); + final Matcher<View> cellMatcher = + allOf(withChild(withText(label)), isDescendantOfA(MATCHER)); onView(cellMatcher).perform(click()); final @SortDirection int viewDirection = getDirection(cellMatcher); diff --git a/tests/common/com/android/documentsui/bots/UiBot.java b/tests/common/com/android/documentsui/bots/UiBot.java index 36256ff74..f30cb93b8 100644 --- a/tests/common/com/android/documentsui/bots/UiBot.java +++ b/tests/common/com/android/documentsui/bots/UiBot.java @@ -35,13 +35,6 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.endsWith; import android.content.Context; -import android.support.test.uiautomator.By; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiObject; -import android.support.test.uiautomator.UiObject2; -import android.support.test.uiautomator.UiObjectNotFoundException; -import android.support.test.uiautomator.UiSelector; -import android.support.test.uiautomator.Until; import android.util.TypedValue; import android.view.View; @@ -51,6 +44,13 @@ import androidx.test.espresso.Espresso; import androidx.test.espresso.action.ViewActions; import androidx.test.espresso.matcher.BoundedMatcher; import androidx.test.espresso.matcher.ViewMatchers; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject; +import androidx.test.uiautomator.UiObject2; +import androidx.test.uiautomator.UiObjectNotFoundException; +import androidx.test.uiautomator.UiSelector; +import androidx.test.uiautomator.Until; import com.android.documentsui.R; diff --git a/tests/common/com/android/documentsui/dirlist/TestContext.java b/tests/common/com/android/documentsui/dirlist/TestContext.java index d5122f271..29047a49a 100644 --- a/tests/common/com/android/documentsui/dirlist/TestContext.java +++ b/tests/common/com/android/documentsui/dirlist/TestContext.java @@ -30,7 +30,7 @@ public final class TestContext { */ static Context createStorageTestContext(Context context, String authority) { final MockContentResolver testResolver = new MockContentResolver(); - TestDocumentsProvider provider = new TestDocumentsProvider(authority); + TestDocumentsProvider provider = new TestDocumentsProvider(context, authority); testResolver.addProvider(authority, provider); return new ContextWrapper(context) { diff --git a/tests/common/com/android/documentsui/testing/TestDirectoryDetails.java b/tests/common/com/android/documentsui/testing/TestDirectoryDetails.java index 28416775a..fb1a7b6db 100644 --- a/tests/common/com/android/documentsui/testing/TestDirectoryDetails.java +++ b/tests/common/com/android/documentsui/testing/TestDirectoryDetails.java @@ -24,6 +24,7 @@ import com.android.documentsui.MenuManager.DirectoryDetails; public class TestDirectoryDetails extends DirectoryDetails { public boolean isInRecents; + public boolean isInArchive; public boolean hasRootSettings; public boolean hasItemsToPaste; public boolean canCreateDoc; @@ -50,6 +51,11 @@ public class TestDirectoryDetails extends DirectoryDetails { } @Override + public boolean isInArchive() { + return isInArchive; + } + + @Override public boolean canCreateDoc() { return canCreateDoc; } diff --git a/tests/common/com/android/documentsui/testing/TestDocumentsProvider.java b/tests/common/com/android/documentsui/testing/TestDocumentsProvider.java index 3e4dffd49..5c5ed856f 100644 --- a/tests/common/com/android/documentsui/testing/TestDocumentsProvider.java +++ b/tests/common/com/android/documentsui/testing/TestDocumentsProvider.java @@ -17,6 +17,7 @@ package com.android.documentsui.testing; import android.annotation.NonNull; +import android.content.Context; import android.content.pm.ProviderInfo; import android.database.Cursor; import android.database.MatrixCursor; @@ -51,10 +52,10 @@ public class TestDocumentsProvider extends DocumentsProvider { private Cursor mNextChildDocuments; private Cursor mNextRecentDocuments; - public TestDocumentsProvider(String authority) { + public TestDocumentsProvider(Context context, String authority) { ProviderInfo info = new ProviderInfo(); info.authority = authority; - attachInfoForTesting(null, info); + attachInfoForTesting(context, info); } @Override diff --git a/tests/common/com/android/documentsui/testing/TestEnv.java b/tests/common/com/android/documentsui/testing/TestEnv.java index 3249c8cf1..8f74647d3 100644 --- a/tests/common/com/android/documentsui/testing/TestEnv.java +++ b/tests/common/com/android/documentsui/testing/TestEnv.java @@ -117,7 +117,8 @@ public class TestEnv { private void registerProviders() { for (RootInfo root : providers.getRootsBlocking()) { if (!mockProviders.containsKey(root.authority)) { - TestDocumentsProvider provider = new TestDocumentsProvider(root.authority); + Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + TestDocumentsProvider provider = new TestDocumentsProvider(context, root.authority); contentResolver.addProvider(root.authority, provider); mockProviders.put(root.authority, provider); } diff --git a/tests/common/com/android/documentsui/testing/TestIconHelper.java b/tests/common/com/android/documentsui/testing/TestIconHelper.java index d9bf9ab5a..754eea1d2 100644 --- a/tests/common/com/android/documentsui/testing/TestIconHelper.java +++ b/tests/common/com/android/documentsui/testing/TestIconHelper.java @@ -19,6 +19,7 @@ package com.android.documentsui.testing; import android.content.Context; import android.graphics.drawable.Drawable; +import com.android.documentsui.ConfigStore; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.dirlist.IconHelper; @@ -28,8 +29,8 @@ public class TestIconHelper extends IconHelper { public Drawable nextDocumentIcon; - private TestIconHelper() { - super(null, 0, false); + private TestIconHelper(ConfigStore configStore) { + super(null, 0, false, configStore); } @Override diff --git a/tests/common/com/android/documentsui/testing/TestMenu.java b/tests/common/com/android/documentsui/testing/TestMenu.java index 5181c730b..9795fd373 100644 --- a/tests/common/com/android/documentsui/testing/TestMenu.java +++ b/tests/common/com/android/documentsui/testing/TestMenu.java @@ -44,6 +44,7 @@ public abstract class TestMenu implements Menu { R.id.dir_menu_open_with, R.id.dir_menu_cut_to_clipboard, R.id.dir_menu_copy_to_clipboard, + R.id.dir_menu_compress, R.id.dir_menu_paste_from_clipboard, R.id.dir_menu_create_dir, R.id.dir_menu_select_all, @@ -76,6 +77,7 @@ public abstract class TestMenu implements Menu { R.id.option_menu_debug, R.id.option_menu_new_window, R.id.option_menu_create_dir, + R.id.option_menu_extract_all, R.id.option_menu_select_all, R.id.option_menu_settings, R.id.option_menu_inspect, @@ -100,6 +102,11 @@ public abstract class TestMenu implements Menu { if (id == R.id.option_menu_search) { item.setActionView(Mockito.mock(SearchView.class)); } + + if (id == R.id.option_menu_extract_all) { + item.setEnabled(false); + item.setVisible(false); + } } return menu; } diff --git a/tests/common/com/android/documentsui/testing/TestModel.java b/tests/common/com/android/documentsui/testing/TestModel.java index 452238189..83ece2ebb 100644 --- a/tests/common/com/android/documentsui/testing/TestModel.java +++ b/tests/common/com/android/documentsui/testing/TestModel.java @@ -40,7 +40,8 @@ public class TestModel extends Model { Document.COLUMN_FLAGS, Document.COLUMN_DISPLAY_NAME, Document.COLUMN_SIZE, - Document.COLUMN_MIME_TYPE + Document.COLUMN_MIME_TYPE, + Document.COLUMN_LAST_MODIFIED }; public final UserId mUserId; @@ -104,7 +105,7 @@ public class TestModel extends Model { } public DocumentInfo createDocumentForUser(String name, String mimeType, int flags, - UserId userId) { + long lastModified, UserId userId) { DocumentInfo doc = new DocumentInfo(); doc.userId = userId; doc.authority = mAuthority; @@ -114,6 +115,7 @@ public class TestModel extends Model { doc.mimeType = mimeType; doc.flags = flags; doc.size = mRand.nextInt(); + doc.lastModified = lastModified; addToCursor(doc); @@ -121,7 +123,7 @@ public class TestModel extends Model { } public DocumentInfo createDocument(String name, String mimeType, int flags) { - return createDocumentForUser(name, mimeType, flags, mUserId); + return createDocumentForUser(name, mimeType, flags, System.currentTimeMillis(), mUserId); } private void addToCursor(DocumentInfo doc) { @@ -133,9 +135,17 @@ public class TestModel extends Model { row.add(Document.COLUMN_MIME_TYPE, doc.mimeType); row.add(Document.COLUMN_FLAGS, doc.flags); row.add(Document.COLUMN_SIZE, doc.size); + row.add(Document.COLUMN_LAST_MODIFIED, doc.lastModified); } - private static String guessMimeType(String name) { + /** + * Attempts to guess the MIME type of the file based on its name. If unable to guess, returns + * "text/plain". + * + * @param name The name of the file whose MIME type is guessed. + * @return A guessed MIME type of "text/plain". + */ + public static String guessMimeType(String name) { int i = name.indexOf('.'); while(i != -1) { diff --git a/tests/common/com/android/documentsui/testing/TestProvidersAccess.java b/tests/common/com/android/documentsui/testing/TestProvidersAccess.java index 4fae7a715..5a138ea9f 100644 --- a/tests/common/com/android/documentsui/testing/TestProvidersAccess.java +++ b/tests/common/com/android/documentsui/testing/TestProvidersAccess.java @@ -111,7 +111,7 @@ public class TestProvidersAccess implements ProvidersAccess { INSPECTOR.rootId = InspectorProvider.ROOT_ID; INSPECTOR.title = "Inspector"; INSPECTOR.flags = Root.FLAG_LOCAL_ONLY - | Root.FLAG_SUPPORTS_CREATE; + | Root.FLAG_SUPPORTS_CREATE; IMAGE = new RootInfo(); IMAGE.userId = userId; @@ -229,6 +229,67 @@ public class TestProvidersAccess implements ProvidersAccess { } } + public static class AnotherUser { + public static final UserHandle USER_HANDLE = UserHandle.of( + TestProvidersAccess.USER_ID.getIdentifier() + 2); + public static final UserId USER_ID = UserId.of(AnotherUser.USER_HANDLE); + + public static final RootInfo DOWNLOADS; + public static final RootInfo HOME; + public static final RootInfo IMAGE; + public static final RootInfo PICKLES; + public static final RootInfo MTP_ROOT; + + static { + UserId userId = AnotherUser.USER_ID; + + DOWNLOADS = new RootInfo(); + DOWNLOADS.userId = userId; + DOWNLOADS.authority = Providers.AUTHORITY_DOWNLOADS; + DOWNLOADS.rootId = Providers.ROOT_ID_DOWNLOADS; + DOWNLOADS.title = "Downloads"; + DOWNLOADS.derivedType = RootInfo.TYPE_DOWNLOADS; + DOWNLOADS.flags = Root.FLAG_LOCAL_ONLY + | Root.FLAG_SUPPORTS_CREATE + | Root.FLAG_SUPPORTS_RECENTS; + + HOME = new RootInfo(); + HOME.userId = userId; + HOME.authority = Providers.AUTHORITY_STORAGE; + HOME.rootId = Providers.ROOT_ID_HOME; + HOME.title = "Home"; + HOME.derivedType = RootInfo.TYPE_LOCAL; + HOME.flags = Root.FLAG_LOCAL_ONLY + | Root.FLAG_SUPPORTS_CREATE + | Root.FLAG_SUPPORTS_IS_CHILD + | Root.FLAG_SUPPORTS_RECENTS; + + IMAGE = new RootInfo(); + IMAGE.userId = userId; + IMAGE.authority = Providers.AUTHORITY_MEDIA; + IMAGE.rootId = Providers.ROOT_ID_IMAGES; + IMAGE.title = "Images"; + IMAGE.derivedType = RootInfo.TYPE_IMAGES; + + PICKLES = new RootInfo(); + PICKLES.userId = userId; + PICKLES.authority = "yummies"; + PICKLES.rootId = "pickles"; + PICKLES.title = "Pickles"; + PICKLES.summary = "Yummy pickles"; + + MTP_ROOT = new RootInfo(); + MTP_ROOT.userId = userId; + MTP_ROOT.authority = Providers.AUTHORITY_MTP; + MTP_ROOT.rootId = Providers.ROOT_ID_DOCUMENTS; + MTP_ROOT.title = "MTP"; + MTP_ROOT.derivedType = RootInfo.TYPE_MTP; + MTP_ROOT.flags = Root.FLAG_SUPPORTS_CREATE + | Root.FLAG_LOCAL_ONLY + | Root.FLAG_SUPPORTS_IS_CHILD; + } + } + public final Map<String, Collection<RootInfo>> roots = new HashMap<>(); private @Nullable RootInfo nextRoot; diff --git a/tests/common/com/android/documentsui/testing/TestSelectionDetails.java b/tests/common/com/android/documentsui/testing/TestSelectionDetails.java index c63fdee59..e798174f8 100644 --- a/tests/common/com/android/documentsui/testing/TestSelectionDetails.java +++ b/tests/common/com/android/documentsui/testing/TestSelectionDetails.java @@ -32,7 +32,7 @@ public class TestSelectionDetails implements SelectionDetails { public boolean containFiles; public boolean canPasteInto; public boolean canExtract; - public boolean canOpenWith; + public boolean canOpen; public boolean canViewInOwner; @Override @@ -76,8 +76,8 @@ public class TestSelectionDetails implements SelectionDetails { } @Override - public boolean canOpenWith() { - return canOpenWith; + public boolean canOpen() { + return canOpen; } @Override diff --git a/tests/functional/com/android/documentsui/ActionCreateDocumentUiTest.java b/tests/functional/com/android/documentsui/ActionCreateDocumentUiTest.java index 1a355b90a..fd17f72fd 100644 --- a/tests/functional/com/android/documentsui/ActionCreateDocumentUiTest.java +++ b/tests/functional/com/android/documentsui/ActionCreateDocumentUiTest.java @@ -16,28 +16,30 @@ package com.android.documentsui; -import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static android.app.Activity.RESULT_OK; +import static android.content.Intent.ACTION_CREATE_DOCUMENT; +import static android.content.Intent.CATEGORY_DEFAULT; +import static android.content.Intent.CATEGORY_OPENABLE; +import static android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; +import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION; +import static android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION; import static com.android.documentsui.base.Providers.AUTHORITY_STORAGE; import static com.google.common.truth.Truth.assertThat; -import android.app.Activity; import android.app.Instrumentation; -import android.app.UiAutomation; -import android.content.Context; import android.content.Intent; import android.net.Uri; import android.provider.DocumentsContract; -import android.support.test.uiautomator.UiDevice; import androidx.test.filters.LargeTest; import androidx.test.rule.ActivityTestRule; import androidx.test.runner.AndroidJUnit4; -import com.android.documentsui.bots.Bots; import com.android.documentsui.picker.PickActivity; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -48,62 +50,54 @@ import java.util.UUID; @LargeTest @RunWith(AndroidJUnit4.class) -public class ActionCreateDocumentUiTest { +public class ActionCreateDocumentUiTest extends DocumentsUiTestBase { @Rule public final ActivityTestRule<PickActivity> mRule = new ActivityTestRule<>(PickActivity.class, false, false); - private Context mTargetContext; - private Context mContext; - private Bots mBots; - private UiDevice mDevice; - @Before - public void setup() { - UiAutomation automation = getInstrumentation().getUiAutomation(); + public void setup() throws Exception { + super.setUp(); + } - mDevice = UiDevice.getInstance(getInstrumentation()); - mTargetContext = getInstrumentation().getTargetContext(); - mContext = getInstrumentation().getContext(); - mBots = new Bots(mDevice, automation, mTargetContext, 5000); + @After + public void tearDown() throws Exception { + super.tearDown(); } @Test public void testActionCreate_TextFile() throws Exception { - Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); - intent.addCategory(Intent.CATEGORY_DEFAULT); - intent.addCategory(Intent.CATEGORY_OPENABLE); + final Intent intent = new Intent(ACTION_CREATE_DOCUMENT); + intent.addCategory(CATEGORY_DEFAULT); + intent.addCategory(CATEGORY_OPENABLE); intent.setType("*/*"); - - Uri hintUri = DocumentsContract.buildRootUri(AUTHORITY_STORAGE, "primary"); - intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, hintUri); + intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, + DocumentsContract.buildRootUri(AUTHORITY_STORAGE, "primary")); mRule.launchActivity(intent); - String fileName = UUID.randomUUID().toString() + ".txt"; + final String fileName = UUID.randomUUID() + ".txt"; - mBots.main.setDialogText(fileName); - mBots.main.clickSaveButton(); - mDevice.waitForIdle(); + bots.main.setDialogText(fileName); + device.waitForIdle(); + bots.main.clickSaveButton(); - Instrumentation.ActivityResult activityResult = mRule.getActivityResult(); + final Instrumentation.ActivityResult activityResult = mRule.getActivityResult(); + assertThat(activityResult.getResultCode()).isEqualTo(RESULT_OK); - Intent result = activityResult.getResultData(); - Uri uri = result.getData(); - int flags = result.getFlags(); + final Intent resultData = activityResult.getResultData(); + final Uri uri = resultData.getData(); - assertThat(activityResult.getResultCode()).isEqualTo(Activity.RESULT_OK); assertThat(uri.getAuthority()).isEqualTo(AUTHORITY_STORAGE); assertThat(uri.getPath()).contains(fileName); - int expectedFlags = - Intent.FLAG_GRANT_READ_URI_PERMISSION - | Intent.FLAG_GRANT_WRITE_URI_PERMISSION - | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; + assertThat(resultData.getFlags()).isEqualTo(FLAG_GRANT_READ_URI_PERMISSION + | FLAG_GRANT_WRITE_URI_PERMISSION + | FLAG_GRANT_PERSISTABLE_URI_PERMISSION); - assertThat(flags).isEqualTo(expectedFlags); - assertThat(DocumentsContract.deleteDocument(mContext.getContentResolver(), uri)).isTrue(); + final boolean deletedSuccessfully = + DocumentsContract.deleteDocument(context.getContentResolver(), uri); + assertThat(deletedSuccessfully).isTrue(); } - }
\ No newline at end of file diff --git a/tests/functional/com/android/documentsui/ActivityTest.java b/tests/functional/com/android/documentsui/ActivityTest.java index ec4e6cbea..bda672b79 100644 --- a/tests/functional/com/android/documentsui/ActivityTest.java +++ b/tests/functional/com/android/documentsui/ActivityTest.java @@ -16,6 +16,8 @@ package com.android.documentsui; +import static java.util.Objects.requireNonNull; + import android.app.Activity; import android.app.UiAutomation; import android.app.UiModeManager; @@ -28,19 +30,22 @@ import android.os.Bundle; import android.os.RemoteException; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; -import android.support.test.uiautomator.Configurator; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiObjectNotFoundException; import android.test.ActivityInstrumentationTestCase2; import android.view.KeyEvent; import android.view.MotionEvent; +import androidx.test.uiautomator.Configurator; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObjectNotFoundException; + import com.android.documentsui.base.Features; import com.android.documentsui.base.RootInfo; import com.android.documentsui.base.UserId; import com.android.documentsui.bots.Bots; import com.android.documentsui.files.FilesActivity; +import java.io.IOException; + import javax.annotation.Nullable; /** @@ -77,6 +82,9 @@ public abstract class ActivityTest<T extends Activity> extends ActivityInstrumen protected ContentProviderClient mClient; protected UiModeManager mUiModeManager; + private String initialScreenOffTimeoutValue = null; + private String initialSleepTimeoutValue = null; + public ActivityTest(Class<T> activityClass) { super(activityClass); } @@ -128,6 +136,9 @@ public abstract class ActivityTest<T extends Activity> extends ActivityInstrumen device.setOrientationNatural(); device.pressKeyCode(KeyEvent.KEYCODE_WAKEUP); device.pressKeyCode(KeyEvent.KEYCODE_MENU); + + disableScreenOffAndSleepTimeouts(); + setupTestingRoots(); launchActivity(); @@ -147,6 +158,7 @@ public abstract class ActivityTest<T extends Activity> extends ActivityInstrumen public void tearDown() throws Exception { device.unfreezeRotation(); mDocsHelper.cleanUp(); + restoreScreenOffAndSleepTimeouts(); super.tearDown(); } @@ -210,4 +222,27 @@ public abstract class ActivityTest<T extends Activity> extends ActivityInstrumen device.waitForIdle(NIGHT_MODE_CHANGE_WAIT_TIME); } } + + private void disableScreenOffAndSleepTimeouts() throws IOException { + initialScreenOffTimeoutValue = device.executeShellCommand( + "settings get system screen_off_timeout"); + initialSleepTimeoutValue = device.executeShellCommand( + "settings get secure sleep_timeout"); + device.executeShellCommand("settings put system screen_off_timeout -1"); + device.executeShellCommand("settings put secure sleep_timeout -1"); + } + + private void restoreScreenOffAndSleepTimeouts() throws IOException { + requireNonNull(initialScreenOffTimeoutValue); + requireNonNull(initialSleepTimeoutValue); + try { + device.executeShellCommand( + "settings put system screen_off_timeout " + initialScreenOffTimeoutValue); + device.executeShellCommand( + "settings put secure sleep_timeout " + initialSleepTimeoutValue); + } finally { + initialScreenOffTimeoutValue = null; + initialSleepTimeoutValue = null; + } + } } diff --git a/tests/functional/com/android/documentsui/ActivityTestJunit4.kt b/tests/functional/com/android/documentsui/ActivityTestJunit4.kt new file mode 100644 index 000000000..daab0cdb4 --- /dev/null +++ b/tests/functional/com/android/documentsui/ActivityTestJunit4.kt @@ -0,0 +1,211 @@ +/* + * 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.documentsui + +import android.app.Activity +import android.app.UiAutomation +import android.content.ContentResolver +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.os.RemoteException +import android.provider.DocumentsContract +import android.view.KeyEvent +import android.view.MotionEvent +import androidx.test.core.app.ActivityScenario +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.Configurator +import androidx.test.uiautomator.UiDevice +import com.android.documentsui.base.Features +import com.android.documentsui.base.Features.RuntimeFeatures +import com.android.documentsui.base.RootInfo +import com.android.documentsui.base.UserId +import com.android.documentsui.bots.Bots +import com.android.documentsui.files.FilesActivity +import java.io.IOException +import java.util.Objects + +/** + * Provides basic test environment for UI tests: + * - Launches activity + * - Creates and gives access to test root directories and test files + * - Cleans up the test environment + */ +abstract class ActivityTestJunit4<T : Activity?> { + @JvmField + var bots: Bots? = null + var device: UiDevice? = null + var context: Context? = null + var userId: UserId? = null + var automation: UiAutomation? = null + + var features: Features? = null + + /** + * Returns the root that will be opened within the activity. + * By default tests are started with one of the test roots. + * Override the method if you want to open different root on start. + * @return Root that will be opened. Return null if you want to open activity's default root. + */ + protected var initialRoot: RootInfo? = null + var rootDir1: RootInfo? = null + protected var mResolver: ContentResolver? = null + + @JvmField + protected var mDocsHelper: DocumentsProviderHelper? = null + protected var mActivityScenario: ActivityScenario<T?>? = null + private var initialScreenOffTimeoutValue: String? = null + private var initialSleepTimeoutValue: String? = null + + protected val testingProviderAuthority: String + /** + * Returns the authority of the testing provider begin used. + * By default it's StubProvider's authority. + * @return Authority of the provider. + */ + get() = StubProvider.DEFAULT_AUTHORITY + + /** + * Resolves testing roots. + */ + @Throws(RemoteException::class) + protected fun setupTestingRoots() { + this.initialRoot = mDocsHelper!!.getRoot(StubProvider.ROOT_0_ID) + rootDir1 = mDocsHelper!!.getRoot(StubProvider.ROOT_1_ID) + } + + @Throws(Exception::class) + open fun setUp() { + device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + // NOTE: Must be the "target" context, else security checks in content provider will fail. + context = InstrumentationRegistry.getInstrumentation().getTargetContext() + userId = UserId.DEFAULT_USER + automation = InstrumentationRegistry.getInstrumentation().getUiAutomation() + features = RuntimeFeatures(context!!.getResources(), null) + + bots = Bots(device, automation, context, TIMEOUT) + + Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_MOUSE) + + mResolver = context!!.getContentResolver() + mDocsHelper = DocumentsProviderHelper( + userId, this.testingProviderAuthority, context, + this.testingProviderAuthority + ) + + device!!.setOrientationNatural() + device!!.pressKeyCode(KeyEvent.KEYCODE_WAKEUP) + + disableScreenOffAndSleepTimeouts() + + setupTestingRoots() + + launchActivity() + resetStorage() + + // Since at the launch of activity, ROOT_0 and ROOT_1 have no files, drawer will + // automatically open for phone devices. Espresso register click() as (x, y) MotionEvents, + // so if a drawer is on top of a file we want to select, it will actually click the drawer. + // Thus to start a clean state, we always try to close first. + bots!!.roots!!.closeDrawer() + + // Configure the provider back to default. + mDocsHelper!!.configure(null, Bundle.EMPTY) + } + + @Throws(Exception::class) + open fun tearDown() { + device!!.unfreezeRotation() + mDocsHelper!!.cleanUp() + restoreScreenOffAndSleepTimeouts() + mActivityScenario!!.close() + } + + protected fun launchActivity() { + val intent = Intent(context, FilesActivity::class.java) + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK) + if (this.initialRoot != null) { + intent.setAction(Intent.ACTION_VIEW) + intent.setDataAndType( + this.initialRoot!!.uri, + DocumentsContract.Root.MIME_TYPE_ITEM + ) + } + mActivityScenario = ActivityScenario.launch(intent) + } + + @Throws(RemoteException::class) + protected fun resetStorage() { + mDocsHelper!!.clear(null, null) + device!!.waitForIdle() + } + + @Throws(RemoteException::class) + protected fun initTestFiles() { + mDocsHelper!!.createFolder(this.initialRoot, dirName1) + mDocsHelper!!.createDocument(this.initialRoot, "text/plain", fileName1) + mDocsHelper!!.createDocument(this.initialRoot, "image/png", fileName2) + mDocsHelper!!.createDocumentWithFlags( + initialRoot!!.documentId, + "text/plain", + fileNameNoRename, + DocumentsContract.Document.FLAG_SUPPORTS_WRITE + ) + + mDocsHelper!!.createDocument(rootDir1, "text/plain", fileName3) + mDocsHelper!!.createDocument(rootDir1, "text/plain", fileName4) + } + + @Throws(IOException::class) + private fun disableScreenOffAndSleepTimeouts() { + initialScreenOffTimeoutValue = device!!.executeShellCommand( + "settings get system screen_off_timeout" + ) + initialSleepTimeoutValue = device!!.executeShellCommand( + "settings get secure sleep_timeout" + ) + device!!.executeShellCommand("settings put system screen_off_timeout -1") + device!!.executeShellCommand("settings put secure sleep_timeout -1") + } + + @Throws(IOException::class) + private fun restoreScreenOffAndSleepTimeouts() { + Objects.requireNonNull<String?>(initialScreenOffTimeoutValue) + Objects.requireNonNull<String?>(initialSleepTimeoutValue) + try { + device!!.executeShellCommand( + "settings put system screen_off_timeout $initialScreenOffTimeoutValue" + ) + device!!.executeShellCommand( + "settings put secure sleep_timeout $initialSleepTimeoutValue" + ) + } finally { + initialScreenOffTimeoutValue = null + initialSleepTimeoutValue = null + } + } + + companion object { + // Testing files. For custom ones, override initTestFiles(). + const val dirName1 = "Dir1" + const val fileName1 = "file1.log" + const val fileName2 = "file12.png" + const val fileName3 = "anotherFile0.log" + const val fileName4 = "poodles.text" + const val fileNameNoRename = "NO_RENAMEfile.txt" + const val TIMEOUT = 5000 + } +} diff --git a/tests/functional/com/android/documentsui/DialogUiTest.java b/tests/functional/com/android/documentsui/DialogUiTest.java index c9c9a7731..d1bd2a2d3 100644 --- a/tests/functional/com/android/documentsui/DialogUiTest.java +++ b/tests/functional/com/android/documentsui/DialogUiTest.java @@ -29,7 +29,6 @@ import android.content.pm.ActivityInfo; import android.graphics.Paint; import android.os.Build; import android.os.ParcelFileDescriptor; -import android.support.test.uiautomator.UiDevice; import android.view.KeyEvent; import androidx.fragment.app.FragmentManager; @@ -37,6 +36,7 @@ import androidx.test.filters.LargeTest; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.rule.ActivityTestRule; import androidx.test.runner.AndroidJUnit4; +import androidx.test.uiautomator.UiDevice; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.dirlist.RenameDocumentFragment; @@ -50,6 +50,7 @@ import com.google.android.material.textfield.TextInputEditText; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -192,6 +193,7 @@ public class DialogUiTest { } @Test + @Ignore public void testCreateDirectoryFragmentShows_textInputEditText_shouldNotTruncateOnLandscape() throws Throwable { switchOrientation(mActivityTestRule.getActivity()); diff --git a/tests/functional/com/android/documentsui/DocumentsUiTestBase.java b/tests/functional/com/android/documentsui/DocumentsUiTestBase.java new file mode 100644 index 000000000..75e03bcb1 --- /dev/null +++ b/tests/functional/com/android/documentsui/DocumentsUiTestBase.java @@ -0,0 +1,89 @@ +/* + * 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.documentsui; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static java.util.Objects.requireNonNull; + +import android.app.Instrumentation; +import android.content.Context; +import android.view.KeyEvent; + +import androidx.test.uiautomator.UiDevice; + +import com.android.documentsui.bots.Bots; + +import java.io.IOException; + + +/** Base class for instrumentation tests for DocumentsUI Activities. */ +class DocumentsUiTestBase { + private static final int BOTS_TIMEOUT = 5000; // 5 seconds + + protected Context targetContext; + protected Context context; + protected UiDevice device; + protected Bots bots; + + private String initialScreenOffTimeoutValue = null; + private String initialSleepTimeoutValue = null; + + protected void setUp() throws Exception { + final Instrumentation instrumentation = getInstrumentation(); + targetContext = instrumentation.getTargetContext(); + context = instrumentation.getContext(); + device = UiDevice.getInstance(instrumentation); + + disableScreenOffAndSleepTimeouts(); + + device.setOrientationNatural(); + + // "Wake-up" the device and navigate to the home page. + device.pressKeyCode(KeyEvent.KEYCODE_WAKEUP); + device.pressKeyCode(KeyEvent.KEYCODE_MENU); + + bots = new Bots(device, instrumentation.getUiAutomation(), targetContext, BOTS_TIMEOUT); + } + + protected void tearDown() throws Exception { + restoreScreenOffAndSleepTimeouts(); + } + + private void disableScreenOffAndSleepTimeouts() throws IOException { + initialScreenOffTimeoutValue = device.executeShellCommand( + "settings get system screen_off_timeout"); + initialSleepTimeoutValue = device.executeShellCommand( + "settings get secure sleep_timeout"); + device.executeShellCommand("settings put system screen_off_timeout -1"); + device.executeShellCommand("settings put secure sleep_timeout -1"); + } + + private void restoreScreenOffAndSleepTimeouts() throws IOException { + requireNonNull(initialScreenOffTimeoutValue); + requireNonNull(initialSleepTimeoutValue); + try { + device.executeShellCommand( + "settings put system screen_off_timeout " + initialScreenOffTimeoutValue); + device.executeShellCommand( + "settings put secure sleep_timeout " + initialSleepTimeoutValue); + } finally { + initialScreenOffTimeoutValue = null; + initialSleepTimeoutValue = null; + } + } +} diff --git a/tests/functional/com/android/documentsui/FileCopyUiTest.java b/tests/functional/com/android/documentsui/FileCopyUiTest.java index eba480924..65a5d257f 100644 --- a/tests/functional/com/android/documentsui/FileCopyUiTest.java +++ b/tests/functional/com/android/documentsui/FileCopyUiTest.java @@ -33,11 +33,11 @@ import android.os.RemoteException; import android.os.SystemClock; import android.provider.MediaStore; import android.provider.Settings; -import android.support.test.uiautomator.UiObjectNotFoundException; import android.text.TextUtils; import android.util.Log; import androidx.test.filters.LargeTest; +import androidx.test.uiautomator.UiObjectNotFoundException; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.RootInfo; @@ -57,9 +57,9 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; /** -* This class test the below points -* - Copy large number of files on the internal/external storage -*/ + * This class test the below points + * - Copy large number of files on the internal/external storage + */ @LargeTest public class FileCopyUiTest extends ActivityTest<FilesActivity> { private static final String TAG = "FileCopyUiTest"; @@ -320,7 +320,7 @@ public class FileCopyUiTest extends ActivityTest<FilesActivity> { if (in != null) { try { in.close(); - in = null; + in = null; } catch (Exception e) { Log.d(TAG, "Error occurs when close ZipInputStream. ", e); } @@ -375,12 +375,12 @@ public class FileCopyUiTest extends ActivityTest<FilesActivity> { private void initStorageRootInfo() throws RemoteException { List<RootInfo> rootList = mStorageDocsHelper.getRootList(); for (RootInfo info : rootList) { - if (ROOT_ID_DEVICE.equals(info.rootId)) { - mPrimaryRoot = info; - } else if (info.isSd()) { - mSdCardRoot = info; - mSdCardLabel = info.title; - } + if (ROOT_ID_DEVICE.equals(info.rootId)) { + mPrimaryRoot = info; + } else if (info.isSd()) { + mSdCardRoot = info; + mSdCardLabel = info.title; + } } } @@ -425,7 +425,7 @@ public class FileCopyUiTest extends ActivityTest<FilesActivity> { // Copy Internal Storage -> Internal Storage // @HugeLongTest - public void testCopyDocuments_InternalStorage() throws Exception { + public void ignored_testCopyDocuments_InternalStorage() throws Exception { createDocuments(StubProvider.ROOT_0_ID, rootDir0, mDocsHelper); copyFiles(StubProvider.ROOT_0_ID, StubProvider.ROOT_1_ID); @@ -472,7 +472,7 @@ public class FileCopyUiTest extends ActivityTest<FilesActivity> { } @HugeLongTest - public void testCopyDocuments_documentsDisabled() throws Exception { + public void ignored_testCopyDocuments_documentsDisabled() throws Exception { mDocsHelper.createDocument(rootDir0, "text/plain", fileName1); bots.roots.openRoot(StubProvider.ROOT_0_ID); bots.directory.selectDocument(fileName1, 1); @@ -489,7 +489,8 @@ public class FileCopyUiTest extends ActivityTest<FilesActivity> { } @HugeLongTest - public void testRecursiveCopyDocuments_InternalStorageToDownloadsProvider() throws Exception { + public void ignored_testRecursiveCopyDocuments_InternalStorageToDownloadsProvider() + throws Exception { // Create Download folder if it doesn't exist. DocumentInfo info = mStorageDocsHelper.findFile(mPrimaryRoot.documentId, "Download"); diff --git a/tests/functional/com/android/documentsui/FilesActivityDefaultsUiTest.java b/tests/functional/com/android/documentsui/FilesActivityDefaultsUiTest.java index b8ef8d651..a33cca37a 100644 --- a/tests/functional/com/android/documentsui/FilesActivityDefaultsUiTest.java +++ b/tests/functional/com/android/documentsui/FilesActivityDefaultsUiTest.java @@ -21,7 +21,6 @@ import static com.android.documentsui.StubProvider.ROOT_1_ID; import android.os.RemoteException; -import androidx.recyclerview.R; import androidx.test.filters.LargeTest; import com.android.documentsui.base.RootInfo; diff --git a/tests/functional/com/android/documentsui/IntegratedDownloadsUiTest.java b/tests/functional/com/android/documentsui/IntegratedDownloadsUiTest.java index 9302e52aa..aa55be9d2 100644 --- a/tests/functional/com/android/documentsui/IntegratedDownloadsUiTest.java +++ b/tests/functional/com/android/documentsui/IntegratedDownloadsUiTest.java @@ -20,12 +20,12 @@ import android.app.DownloadManager; import android.app.DownloadManager.Request; import android.content.Context; import android.net.Uri; -import android.support.test.uiautomator.Configurator; -import android.support.test.uiautomator.UiObject; import android.view.MotionEvent; import androidx.test.filters.LargeTest; import androidx.test.filters.Suppress; +import androidx.test.uiautomator.Configurator; +import androidx.test.uiautomator.UiObject; import com.android.documentsui.files.FilesActivity; diff --git a/tests/functional/com/android/documentsui/PickActivityTest.java b/tests/functional/com/android/documentsui/PickActivityTest.java index cd042b1f5..5d3203679 100644 --- a/tests/functional/com/android/documentsui/PickActivityTest.java +++ b/tests/functional/com/android/documentsui/PickActivityTest.java @@ -37,12 +37,20 @@ import com.android.documentsui.picker.PickActivity; import com.android.documentsui.testing.TestProvidersAccess; import com.android.documentsui.ui.TestDialogController; import com.android.documentsui.util.VersionUtils; +import com.android.modules.utils.build.SdkLevel; + +import com.google.common.collect.Lists; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; @SmallTest +@RunWith(Parameterized.class) public class PickActivityTest { private static final String RESULT_EXTRA = "test_result_extra"; @@ -51,6 +59,19 @@ public class PickActivityTest { private Context mTargetContext; private Intent mIntentGetContent; private TestDialogController mTestDialogs; + private TestConfigStore mTestConfigStore; + + @Parameter(0) + public boolean isPrivateSpaceEnabled; + + /** + * Parametrize values for {@code isPrivateSpaceEnabled} to run all the tests twice once with + * private space flag enabled and once with it disabled. + */ + @Parameters(name = "privateSpaceEnabled={0}") + public static Iterable<?> data() { + return Lists.newArrayList(true, false); + } @Rule public final ActivityTestRule<PickActivity> mRule = @@ -67,6 +88,9 @@ public class PickActivityTest { mIntentGetContent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, hintUri); mTestDialogs = new TestDialogController(); + mTestConfigStore = new TestConfigStore(); + + isPrivateSpaceEnabled = SdkLevel.isAtLeastS() && isPrivateSpaceEnabled; } @Test @@ -77,7 +101,13 @@ public class PickActivityTest { doc.documentId = "documentId"; PickActivity pickActivity = mRule.launchActivity(mIntentGetContent); - pickActivity.mState.canShareAcrossProfile = true; + pickActivity.mState.configStore = mTestConfigStore; + if (isPrivateSpaceEnabled) { + mTestConfigStore.enablePrivateSpaceInPhotoPicker(); + pickActivity.mState.canForwardToProfileIdMap.put(TestProvidersAccess.USER_ID, true); + } else { + pickActivity.mState.canShareAcrossProfile = true; + } pickActivity.onDocumentPicked(doc); SystemClock.sleep(3000); @@ -96,7 +126,15 @@ public class PickActivityTest { doc.documentId = "documentId"; PickActivity pickActivity = mRule.launchActivity(mIntentGetContent); - pickActivity.mState.canShareAcrossProfile = true; + pickActivity.mState.configStore = mTestConfigStore; + if (isPrivateSpaceEnabled) { + mTestConfigStore.enablePrivateSpaceInPhotoPicker(); + pickActivity.mState.canForwardToProfileIdMap.put(TestProvidersAccess.USER_ID, true); + pickActivity.mState.canForwardToProfileIdMap.put( + TestProvidersAccess.OtherUser.USER_ID, true); + } else { + pickActivity.mState.canShareAcrossProfile = true; + } pickActivity.onDocumentPicked(doc); SystemClock.sleep(3000); @@ -114,7 +152,13 @@ public class PickActivityTest { doc.documentId = "documentId"; PickActivity pickActivity = mRule.launchActivity(mIntentGetContent); - pickActivity.mState.canShareAcrossProfile = false; + pickActivity.mState.configStore = mTestConfigStore; + if (isPrivateSpaceEnabled) { + mTestConfigStore.enablePrivateSpaceInPhotoPicker(); + pickActivity.mState.canForwardToProfileIdMap.put(TestProvidersAccess.USER_ID, true); + } else { + pickActivity.mState.canShareAcrossProfile = false; + } pickActivity.getInjector().dialogs = mTestDialogs; pickActivity.onDocumentPicked(doc); SystemClock.sleep(3000); diff --git a/tests/functional/com/android/documentsui/RenameDocumentUiTest.java b/tests/functional/com/android/documentsui/RenameDocumentUiTest.java index 585df5e74..e992ac95f 100644 --- a/tests/functional/com/android/documentsui/RenameDocumentUiTest.java +++ b/tests/functional/com/android/documentsui/RenameDocumentUiTest.java @@ -16,9 +16,8 @@ package com.android.documentsui; -import android.support.test.uiautomator.UiObjectNotFoundException; - import androidx.test.filters.LargeTest; +import androidx.test.uiautomator.UiObjectNotFoundException; import com.android.documentsui.files.FilesActivity; import com.android.documentsui.util.VersionUtils; diff --git a/tests/functional/com/android/documentsui/SearchViewUiTest.java b/tests/functional/com/android/documentsui/SearchViewUiTest.java index 04ea87a41..78ce44a5e 100644 --- a/tests/functional/com/android/documentsui/SearchViewUiTest.java +++ b/tests/functional/com/android/documentsui/SearchViewUiTest.java @@ -19,7 +19,6 @@ package com.android.documentsui; import static com.android.documentsui.StubProvider.ROOT_0_ID; import static com.android.documentsui.StubProvider.ROOT_1_ID; -import androidx.recyclerview.R; import androidx.test.filters.LargeTest; import androidx.test.filters.Suppress; diff --git a/tests/functional/com/android/documentsui/SortDocumentUiTest.java b/tests/functional/com/android/documentsui/SortDocumentUiTest.java index 05878bbe7..b277884e3 100644 --- a/tests/functional/com/android/documentsui/SortDocumentUiTest.java +++ b/tests/functional/com/android/documentsui/SortDocumentUiTest.java @@ -16,16 +16,30 @@ package com.android.documentsui; +import static com.android.documentsui.flags.Flags.FLAG_USE_MATERIAL3; + import android.net.Uri; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.view.KeyEvent; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.LargeTest; import com.android.documentsui.files.FilesActivity; import com.android.documentsui.sorting.SortDimension; import com.android.documentsui.sorting.SortModel; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + @LargeTest -public class SortDocumentUiTest extends ActivityTest<FilesActivity> { +@RunWith(AndroidJUnit4.class) +public class SortDocumentUiTest extends ActivityTestJunit4<FilesActivity> { private static final String DIR_1 = "folder_1"; private static final String DIR_2 = "dir_2"; @@ -38,63 +52,76 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> { private static final String MIME_2 = "text/html"; // HTML document private static final String MIME_3 = "image/jpeg"; // JPG image - private static final String[] FILES = { FILE_1, FILE_3, FILE_2 }; - private static final String[] MIMES = { MIME_1, MIME_3, MIME_2 }; - private static final String[] DIRS = { DIR_1, DIR_2 }; - - private static final String[] DIRS_IN_NAME_ASC = { DIR_2, DIR_1 }; + private static final String[] FILES = {FILE_1, FILE_3, FILE_2}; + private static final String[] FILES_IN_MODIFIED_DESC = reverse(FILES); + private static final String[] MIMES = {MIME_1, MIME_3, MIME_2}; + private static final String[] DIRS = {DIR_1, DIR_2}; + private static final String[] DIRS_IN_MODIFIED_DESC = reverse(DIRS); + private static final String[] DIRS_IN_NAME_ASC = {DIR_2, DIR_1}; private static final String[] DIRS_IN_NAME_DESC = reverse(DIRS_IN_NAME_ASC); - private static final String[] FILES_IN_NAME_ASC = { FILE_2, FILE_1, FILE_3 }; + private static final String[] FILES_IN_NAME_ASC = {FILE_2, FILE_1, FILE_3}; private static final String[] FILES_IN_NAME_DESC = reverse(FILES_IN_NAME_ASC); - - private static final String[] FILES_IN_SIZE_ASC = { FILE_2, FILE_1, FILE_3 }; + private static final String[] FILES_IN_SIZE_ASC = {FILE_2, FILE_1, FILE_3}; private static final String[] FILES_IN_SIZE_DESC = reverse(FILES_IN_SIZE_ASC); + private static final String[] FILES_IN_TYPE_ASC = {FILE_2, FILE_3, FILE_1}; + private static final String[] FILES_IN_TYPE_DESC = reverse(FILES_IN_TYPE_ASC); - private static final String[] DIRS_IN_MODIFIED_DESC = reverse(DIRS); - private static final String[] FILES_IN_MODIFIED_DESC = reverse(FILES); + private static String[] reverse(String[] array) { + String[] ret = new String[array.length]; - private static final String[] FILES_IN_TYPE_ASC = { FILE_2, FILE_3, FILE_1 }; - private static final String[] FILES_IN_TYPE_DESC = reverse(FILES_IN_TYPE_ASC); + for (int i = 0; i < array.length; ++i) { + ret[ret.length - i - 1] = array[i]; + } - public SortDocumentUiTest() { - super(FilesActivity.class); + return ret; } - @Override + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + + @Before public void setUp() throws Exception { super.setUp(); bots.roots.closeDrawer(); } + @After + public void tearDown() throws Exception { + super.tearDown(); + } + private void initFiles() throws Exception { initFiles(0); } /** - * Initiate test files. It allows waiting between creations of files, so that we can assure - * the modified date of each document is different. + * Initiate test files. It allows waiting between creations of files, so that we can assure the + * modified date of each document is different. + * * @param sleep time to sleep in ms */ private void initFiles(long sleep) throws Exception { for (int i = 0; i < FILES.length; ++i) { - Uri uri = mDocsHelper.createDocument(rootDir0, MIMES[i], FILES[i]); + Uri uri = mDocsHelper.createDocument(getInitialRoot(), MIMES[i], FILES[i]); mDocsHelper.writeDocument(uri, FILES[i].getBytes()); Thread.sleep(sleep); } for (String dir : DIRS) { - mDocsHelper.createFolder(rootDir0, dir); + mDocsHelper.createFolder(getInitialRoot(), dir); Thread.sleep(sleep); } } + @Test public void testDefaultSortByNameAscending() throws Exception { initFiles(); bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_NAME_ASC); } + @Test public void testSortByName_Descending_listMode() throws Exception { initFiles(); @@ -105,46 +132,47 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> { bots.directory.assertOrder(DIRS_IN_NAME_DESC, FILES_IN_NAME_DESC); } + @Test public void testSortBySize_Ascending_listMode() throws Exception { initFiles(); bots.main.switchToListMode(); - bots.sort.sortBy( - SortModel.SORT_DIMENSION_ID_SIZE, SortDimension.SORT_DIRECTION_ASCENDING); + bots.sort.sortBy(SortModel.SORT_DIMENSION_ID_SIZE, SortDimension.SORT_DIRECTION_ASCENDING); bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_SIZE_ASC); } + @Test public void testSortBySize_Descending_listMode() throws Exception { initFiles(); bots.main.switchToListMode(); - bots.sort.sortBy( - SortModel.SORT_DIMENSION_ID_SIZE, SortDimension.SORT_DIRECTION_DESCENDING); + bots.sort.sortBy(SortModel.SORT_DIMENSION_ID_SIZE, SortDimension.SORT_DIRECTION_DESCENDING); bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_SIZE_DESC); } + @Test public void testSortByModified_Ascending_listMode() throws Exception { initFiles(1000); bots.main.switchToListMode(); - bots.sort.sortBy( - SortModel.SORT_DIMENSION_ID_DATE, SortDimension.SORT_DIRECTION_ASCENDING); + bots.sort.sortBy(SortModel.SORT_DIMENSION_ID_DATE, SortDimension.SORT_DIRECTION_ASCENDING); bots.directory.assertOrder(DIRS, FILES); } + @Test public void testSortByModified_Descending_listMode() throws Exception { initFiles(1000); bots.main.switchToListMode(); - bots.sort.sortBy( - SortModel.SORT_DIMENSION_ID_DATE, SortDimension.SORT_DIRECTION_DESCENDING); + bots.sort.sortBy(SortModel.SORT_DIMENSION_ID_DATE, SortDimension.SORT_DIRECTION_DESCENDING); bots.directory.assertOrder(DIRS_IN_MODIFIED_DESC, FILES_IN_MODIFIED_DESC); } + @Test public void testSortByType_Ascending_listMode() throws Exception { initFiles(); @@ -155,6 +183,7 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> { bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_TYPE_ASC); } + @Test public void testSortByType_Descending_listMode() throws Exception { initFiles(); @@ -165,6 +194,7 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> { bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_TYPE_DESC); } + @Test public void testSortByName_Descending_gridMode() throws Exception { initFiles(); @@ -175,46 +205,47 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> { bots.directory.assertOrder(DIRS_IN_NAME_DESC, FILES_IN_NAME_DESC); } + @Test public void testSortBySize_Ascending_gridMode() throws Exception { initFiles(); bots.main.switchToGridMode(); - bots.sort.sortBy( - SortModel.SORT_DIMENSION_ID_SIZE, SortDimension.SORT_DIRECTION_ASCENDING); + bots.sort.sortBy(SortModel.SORT_DIMENSION_ID_SIZE, SortDimension.SORT_DIRECTION_ASCENDING); bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_SIZE_ASC); } + @Test public void testSortBySize_Descending_gridMode() throws Exception { initFiles(); bots.main.switchToGridMode(); - bots.sort.sortBy( - SortModel.SORT_DIMENSION_ID_SIZE, SortDimension.SORT_DIRECTION_DESCENDING); + bots.sort.sortBy(SortModel.SORT_DIMENSION_ID_SIZE, SortDimension.SORT_DIRECTION_DESCENDING); bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_SIZE_DESC); } + @Test public void testSortByModified_Ascending_gridMode() throws Exception { initFiles(1000); bots.main.switchToGridMode(); - bots.sort.sortBy( - SortModel.SORT_DIMENSION_ID_DATE, SortDimension.SORT_DIRECTION_ASCENDING); + bots.sort.sortBy(SortModel.SORT_DIMENSION_ID_DATE, SortDimension.SORT_DIRECTION_ASCENDING); bots.directory.assertOrder(DIRS, FILES); } + @Test public void testSortByModified_Descending_gridMode() throws Exception { initFiles(1000); bots.main.switchToGridMode(); - bots.sort.sortBy( - SortModel.SORT_DIMENSION_ID_DATE, SortDimension.SORT_DIRECTION_DESCENDING); + bots.sort.sortBy(SortModel.SORT_DIMENSION_ID_DATE, SortDimension.SORT_DIRECTION_DESCENDING); bots.directory.assertOrder(DIRS_IN_MODIFIED_DESC, FILES_IN_MODIFIED_DESC); } + @Test public void testSortByType_Ascending_gridMode() throws Exception { initFiles(); @@ -225,6 +256,7 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> { bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_TYPE_ASC); } + @Test public void testSortByType_Descending_gridMode() throws Exception { initFiles(); @@ -235,13 +267,31 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> { bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_TYPE_DESC); } - private static String[] reverse(String[] array) { - String[] ret = new String[array.length]; + @Test + @RequiresFlagsEnabled(FLAG_USE_MATERIAL3) + public void testSortByArrowIcon() throws Exception { + initFiles(); - for (int i = 0; i < array.length; ++i) { - ret[ret.length - i - 1] = array[i]; + bots.main.switchToListMode(); + + // Set up the sort in descending direction to allow deterministic behaviour of the sort + // icon. + bots.sort.sortBy( + SortModel.SORT_DIMENSION_ID_TITLE, SortDimension.SORT_DIRECTION_DESCENDING); + bots.directory.assertOrder(DIRS_IN_NAME_DESC, FILES_IN_NAME_DESC); + + // Tab in reverse order until the sort icon is the focus (this avoids tabbing through the + // roots list which is quite long in tests). + while (!bots.sort.isSortIconFocused()) { + bots.keyboard.pressKey(KeyEvent.KEYCODE_TAB, KeyEvent.META_SHIFT_LEFT_ON); } - return ret; + // Press enter on the sort icon and ensure the sort direction is changed. + bots.keyboard.pressKey(KeyEvent.KEYCODE_ENTER); + bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_NAME_ASC); + + // Space should also work in the same way as the ENTER key. + bots.keyboard.pressKey(KeyEvent.KEYCODE_SPACE); + bots.directory.assertOrder(DIRS_IN_NAME_DESC, FILES_IN_NAME_DESC); } } diff --git a/tests/functional/com/android/documentsui/TrampolineActivityTest.kt b/tests/functional/com/android/documentsui/TrampolineActivityTest.kt new file mode 100644 index 000000000..c2201789b --- /dev/null +++ b/tests/functional/com/android/documentsui/TrampolineActivityTest.kt @@ -0,0 +1,218 @@ +/* + * 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.documentsui + +import android.content.Intent +import android.os.Build.VERSION_CODES +import android.platform.test.annotations.RequiresFlagsEnabled +import android.platform.test.flag.junit.CheckFlagsRule +import android.platform.test.flag.junit.DeviceFlagsValueProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SdkSuppress +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.By +import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.Until +import com.android.documentsui.flags.Flags.FLAG_REDIRECT_GET_CONTENT +import com.android.documentsui.picker.TrampolineActivity +import java.util.regex.Pattern +import org.junit.Assert.assertNotNull +import org.junit.Before +import org.junit.BeforeClass +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized +import org.junit.runners.Suite +import org.junit.runners.Suite.SuiteClasses + +@SmallTest +@RunWith(Suite::class) +@SuiteClasses( + TrampolineActivityTest.ShouldLaunchCorrectPackageTest::class, + TrampolineActivityTest.RedirectTest::class +) +class TrampolineActivityTest() { + companion object { + const val UI_TIMEOUT = 5000L + val PHOTOPICKER_PACKAGE_REGEX: Pattern = Pattern.compile(".*photopicker.*") + val DOCUMENTSUI_PACKAGE_REGEX: Pattern = Pattern.compile(".*documentsui.*") + + private var device: UiDevice? = null + + @BeforeClass + @JvmStatic + fun setUp() { + device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + } + } + + @RunWith(Parameterized::class) + @RequiresFlagsEnabled(FLAG_REDIRECT_GET_CONTENT) + class ShouldLaunchCorrectPackageTest { + enum class AppType { + PHOTOPICKER, + DOCUMENTSUI, + } + + data class GetContentIntentData( + val mimeType: String, + val expectedApp: AppType, + val extraMimeTypes: Array<String>? = null, + ) { + override fun toString(): String { + if (extraMimeTypes != null) { + return "${mimeType}_${extraMimeTypes.joinToString("_")}" + } + return mimeType + } + } + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun parameters() = + listOf( + GetContentIntentData( + mimeType = "*/*", + expectedApp = AppType.DOCUMENTSUI, + ), + GetContentIntentData( + mimeType = "image/*", + expectedApp = AppType.PHOTOPICKER, + ), + GetContentIntentData( + mimeType = "video/*", + expectedApp = AppType.PHOTOPICKER, + ), + GetContentIntentData( + mimeType = "image/*", + extraMimeTypes = arrayOf("video/*"), + expectedApp = AppType.PHOTOPICKER, + ), + GetContentIntentData( + mimeType = "video/*", + extraMimeTypes = arrayOf("image/*"), + expectedApp = AppType.PHOTOPICKER, + ), + GetContentIntentData( + mimeType = "video/*", + extraMimeTypes = arrayOf("text/*"), + expectedApp = AppType.DOCUMENTSUI, + ), + GetContentIntentData( + mimeType = "video/*", + extraMimeTypes = arrayOf("image/*", "text/*"), + expectedApp = AppType.DOCUMENTSUI, + ), + GetContentIntentData( + mimeType = "*/*", + extraMimeTypes = arrayOf("image/*", "video/*"), + expectedApp = AppType.DOCUMENTSUI, + ), + GetContentIntentData( + mimeType = "image/*", + extraMimeTypes = arrayOf(), + expectedApp = AppType.DOCUMENTSUI, + ) + ) + } + + @Parameterized.Parameter(0) + lateinit var testData: GetContentIntentData + + @get:Rule + val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + + @Before + fun setUp() { + val context = InstrumentationRegistry.getInstrumentation().targetContext + val intent = Intent(Intent.ACTION_GET_CONTENT) + intent.setClass(context, TrampolineActivity::class.java) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + intent.setType(testData.mimeType) + testData.extraMimeTypes?.let { intent.putExtra(Intent.EXTRA_MIME_TYPES, it) } + + context.startActivity(intent) + } + + @Test + fun testCorrectAppIsLaunched() { + val bySelector = when (testData.expectedApp) { + AppType.PHOTOPICKER -> By.pkg(PHOTOPICKER_PACKAGE_REGEX) + else -> By.pkg(DOCUMENTSUI_PACKAGE_REGEX) + } + + assertNotNull(device?.wait(Until.findObject(bySelector), UI_TIMEOUT)) + } + } + + @RunWith(AndroidJUnit4::class) + @RequiresFlagsEnabled(FLAG_REDIRECT_GET_CONTENT) + class RedirectTest { + @get:Rule + val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + + @Test + fun testReferredGetContentFromPhotopickerShouldNotRedirectBack() { + val context = InstrumentationRegistry.getInstrumentation().targetContext + val intent = Intent(Intent.ACTION_GET_CONTENT) + intent.setClass(context, TrampolineActivity::class.java) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + intent.setType("image/*") + + context.startActivity(intent) + val moreButton = device?.wait(Until.findObject(By.desc("More")), UI_TIMEOUT) + moreButton?.click() + + val browseButton = device?.wait(Until.findObject(By.textContains("Browse")), UI_TIMEOUT) + browseButton?.click() + + assertNotNull( + "DocumentsUI has not launched", + device?.wait(Until.findObject(By.pkg(DOCUMENTSUI_PACKAGE_REGEX)), UI_TIMEOUT) + ) + } + + @Test + @SdkSuppress(minSdkVersion = VERSION_CODES.S, maxSdkVersion = VERSION_CODES.S_V2) + fun testAndroidSWithTakeoverGetContentDisabledShouldNotReferToDocumentsUI() { + val context = InstrumentationRegistry.getInstrumentation().targetContext + val intent = Intent(Intent.ACTION_GET_CONTENT) + intent.setClass(context, TrampolineActivity::class.java) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + intent.setType("image/*") + + try { + // Disable Photopicker from taking over `ACTION_GET_CONTENT`. In this situation, it + // should ALWAYS defer to DocumentsUI regardless if the mimetype satisfies the + // conditions. + device?.executeShellCommand( + "device_config put mediaprovider take_over_get_content false" + ) + context.startActivity(intent) + assertNotNull( + device?.wait(Until.findObject(By.pkg(DOCUMENTSUI_PACKAGE_REGEX)), UI_TIMEOUT) + ) + } finally { + device?.executeShellCommand( + "device_config delete mediaprovider take_over_get_content" + ) + } + } + } +} diff --git a/tests/functional/com/android/documentsui/archives/ArchiveHandleTest.java b/tests/functional/com/android/documentsui/archives/ArchiveHandleTest.java index 29ed8e431..d8a1f4225 100644 --- a/tests/functional/com/android/documentsui/archives/ArchiveHandleTest.java +++ b/tests/functional/com/android/documentsui/archives/ArchiveHandleTest.java @@ -142,6 +142,45 @@ public class ArchiveHandleTest { new ArchiveEntryRecord("hello/inside_folder/hello_insside.txt", 14, false), new ArchiveEntryRecord("hello/hello2.txt", 48, false)); + private static String getNormalizedPath(String in, boolean isDir) { + return Archive.getEntryPath(new ArchiveEntryRecord(in, -1, isDir)); + } + + @Test + public void normalizePath() { + assertThat(getNormalizedPath("", true)).isEqualTo("/"); + assertThat(getNormalizedPath("", false)).isEqualTo("/?"); + assertThat(getNormalizedPath("/", true)).isEqualTo("/"); + assertThat(getNormalizedPath("/", false)).isEqualTo("/?"); + assertThat(getNormalizedPath("///", true)).isEqualTo("/"); + assertThat(getNormalizedPath("///", false)).isEqualTo("/?"); + assertThat(getNormalizedPath(".", true)).isEqualTo("/"); + assertThat(getNormalizedPath(".", false)).isEqualTo("/?"); + assertThat(getNormalizedPath("./", true)).isEqualTo("/"); + assertThat(getNormalizedPath("./", false)).isEqualTo("/?"); + assertThat(getNormalizedPath("./foo", true)).isEqualTo("/foo/"); + assertThat(getNormalizedPath("./foo", false)).isEqualTo("/foo"); + assertThat(getNormalizedPath("./foo/", true)).isEqualTo("/foo/"); + assertThat(getNormalizedPath("./foo/", false)).isEqualTo("/foo/?"); + assertThat(getNormalizedPath("..", true)).isEqualTo("/"); + assertThat(getNormalizedPath("..", false)).isEqualTo("/?"); + assertThat(getNormalizedPath("../", true)).isEqualTo("/"); + assertThat(getNormalizedPath("../", false)).isEqualTo("/?"); + assertThat(getNormalizedPath("foo", true)).isEqualTo("/foo/"); + assertThat(getNormalizedPath("foo", false)).isEqualTo("/foo"); + assertThat(getNormalizedPath("foo/", true)).isEqualTo("/foo/"); + assertThat(getNormalizedPath("foo/", false)).isEqualTo("/foo/?"); + assertThat(getNormalizedPath("foo/.", true)).isEqualTo("/foo/"); + assertThat(getNormalizedPath("foo/.", false)).isEqualTo("/foo/?"); + assertThat(getNormalizedPath("foo/..", true)).isEqualTo("/"); + assertThat(getNormalizedPath("foo/..", false)).isEqualTo("/?"); + assertThat(getNormalizedPath("/foo", true)).isEqualTo("/foo/"); + assertThat(getNormalizedPath("/foo", false)).isEqualTo("/foo"); + assertThat(getNormalizedPath("//./../a//b///../c.ext", true)).isEqualTo("/a/c.ext/"); + assertThat(getNormalizedPath("//./../a//b///../c.ext", false)).isEqualTo("/a/c.ext"); + assertThat(getNormalizedPath("//./../a//b///../c.ext/", true)).isEqualTo("/a/c.ext/"); + assertThat(getNormalizedPath("//./../a//b///../c.ext/", false)).isEqualTo("/a/c.ext/?"); + } @Test public void buildArchiveHandle_withoutFileDescriptor_shouldBeIllegal() throws Exception { @@ -241,7 +280,7 @@ public class ArchiveHandleTest { public void buildArchiveHandle_tarBrFile_shouldNotNull() throws Exception { ArchiveHandle archiveHandle = prepareArchiveHandle("archives/brotli/hello.tar.br", ".tar.br", - "application/x-brotli-compressed-tar"); + "application/x-brotli-compressed-tar"); assertThat(archiveHandle).isNotNull(); } @@ -346,7 +385,7 @@ public class ArchiveHandleTest { @Test public void close_zipFile_shouldNotOpen() throws Exception { - ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule + ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule .openAssetFile("archives/zip/hello.zip", ".zip"); ArchiveHandle archiveHandle = ArchiveHandle.create(parcelFileDescriptor, @@ -557,7 +596,7 @@ public class ArchiveHandleTest { public void getEntries_tarFile_shouldTheSameWithList() throws Exception { ArchiveHandle archiveHandle = prepareArchiveHandle("archives/tar/hello.tar", ".tar", - "application/x-gtar"); + "application/x-gtar"); assertThat(transformToIterable(archiveHandle.getEntries())) .containsAtLeastElementsIn(sExpectEntries); diff --git a/tests/functional/com/android/documentsui/archives/WriteableArchiveTest.java b/tests/functional/com/android/documentsui/archives/WriteableArchiveTest.java index 7092d1294..da470daa3 100644 --- a/tests/functional/com/android/documentsui/archives/WriteableArchiveTest.java +++ b/tests/functional/com/android/documentsui/archives/WriteableArchiveTest.java @@ -21,9 +21,9 @@ import android.net.Uri; import android.os.ParcelFileDescriptor; import android.provider.DocumentsContract.Document; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.MediumTest; import androidx.test.InstrumentationRegistry; +import androidx.test.filters.MediumTest; import java.io.File; import java.io.IOException; diff --git a/tests/functional/com/android/documentsui/dirlist/DirectoryAddonsAdapterPrivateSpaceTest.java b/tests/functional/com/android/documentsui/dirlist/DirectoryAddonsAdapterPrivateSpaceTest.java new file mode 100644 index 000000000..cf057dec0 --- /dev/null +++ b/tests/functional/com/android/documentsui/dirlist/DirectoryAddonsAdapterPrivateSpaceTest.java @@ -0,0 +1,237 @@ +/* + * 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.documentsui.dirlist; + +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.UserProperties; +import android.os.Bundle; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.DocumentsContract; +import android.test.AndroidTestCase; +import android.view.ViewGroup; + +import androidx.recyclerview.widget.RecyclerView; +import androidx.test.filters.SdkSuppress; + +import com.android.documentsui.ActionHandler; +import com.android.documentsui.ModelId; +import com.android.documentsui.TestConfigStore; +import com.android.documentsui.base.DocumentInfo; +import com.android.documentsui.base.State; +import com.android.documentsui.base.UserId; +import com.android.documentsui.testing.TestActionHandler; +import com.android.documentsui.testing.TestEnv; +import com.android.documentsui.testing.TestFileTypeLookup; +import com.android.documentsui.testing.TestProvidersAccess; +import com.android.documentsui.testing.UserManagers; +import com.android.documentsui.util.VersionUtils; + +import java.util.HashMap; +import java.util.Map; + +@SdkSuppress(minSdkVersion = 35, codeName = "V") +public class DirectoryAddonsAdapterPrivateSpaceTest extends AndroidTestCase { + + private static final String AUTHORITY = "test_authority"; + private static final UserId CURRENT_USER = TestProvidersAccess.USER_ID; + private static final UserId SELECTED_USER = TestProvidersAccess.OtherUser.USER_ID; + + private TestEnv mEnv; + private DirectoryAddonsAdapter mAdapter; + private ActionHandler mActionHandler; + private TestConfigStore mTestConfigStore; + private UserManager mUserManager; + + /** + * set up for the test assuming that private space is enabled. + */ + public void setUp() { + + mEnv = TestEnv.create(AUTHORITY); + mActionHandler = new TestActionHandler(); + mEnv.clear(); + mTestConfigStore = new TestConfigStore(); + mTestConfigStore.enablePrivateSpaceInPhotoPicker(); + mUserManager = UserManagers.create(); + + UserProperties selectedUserProperties = new UserProperties.Builder().setShowInQuietMode( + UserProperties.SHOW_IN_QUIET_MODE_HIDDEN).build(); + when(mUserManager.getUserProperties( + UserHandle.of(SELECTED_USER.getIdentifier()))).thenReturn(selectedUserProperties); + + final Context testContext = TestContext.createStorageTestContext(getContext(), AUTHORITY); + DocumentsAdapter.Environment env = new TestEnvironment(testContext, mEnv, mActionHandler); + Map<UserId, String> userIdToLabelMap = new HashMap<>(); + userIdToLabelMap.put(CURRENT_USER, "Personal"); + userIdToLabelMap.put(SELECTED_USER, "Profile"); + + mAdapter = new DirectoryAddonsAdapter( + env, + new ModelBackedDocumentsAdapter( + env, + new IconHelper(testContext, State.MODE_GRID, /* maybeShowBadge= */ false, + mTestConfigStore), + new TestFileTypeLookup(), mTestConfigStore), + CURRENT_USER, SELECTED_USER, userIdToLabelMap, mUserManager, mTestConfigStore); + + mEnv.model.addUpdateListener(mAdapter.getModelUpdateListener()); + } + + // Tests that the item count is correct for a directory containing files and subdirs. + public void testItemCount_mixed() { + mEnv.reset(); // creates a mix of folders and files for us. + + assertEquals(mEnv.model.getItemCount() + 1, mAdapter.getItemCount()); + } + + public void testGetPosition() { + mEnv.model.createFolder("a"); // id will be "1"...derived from insert position. + mEnv.model.createFile("b"); // id will be "2" + mEnv.model.update(); + + assertEquals(0, mAdapter.getPosition(ModelId.build(mEnv.model.mUserId, AUTHORITY, "1"))); + // adapter inserts a view between item 0 and 1 to force layout + // break between folders and files. This is reflected by an offset position. + assertEquals(2, mAdapter.getPosition(ModelId.build(mEnv.model.mUserId, AUTHORITY, "2"))); + } + + // Tests that the item count is correct for a directory containing only subdirs. + public void testItemCount_allDirs() { + String[] names = {"Trader Joe's", "Alphabeta", "Lucky", "Vons", "Gelson's"}; + for (String name : names) { + mEnv.model.createFolder(name); + } + mEnv.model.update(); + assertEquals(mEnv.model.getItemCount(), mAdapter.getItemCount()); + } + + // Tests that the item count is correct for a directory containing only files. + public void testItemCount_allFiles() { + String[] names = {"123.txt", "234.jpg", "abc.pdf"}; + for (String name : names) { + mEnv.model.createFile(name); + } + mEnv.model.update(); + assertEquals(mEnv.model.getItemCount(), mAdapter.getItemCount()); + } + + public void testAddsInfoMessage_WithDirectoryChildren() { + String[] names = {"123.txt", "234.jpg", "abc.pdf"}; + for (String name : names) { + mEnv.model.createFile(name); + } + Bundle bundle = new Bundle(); + bundle.putString(DocumentsContract.EXTRA_INFO, "some info"); + mEnv.model.setCursorExtras(bundle); + mEnv.model.update(); + assertEquals(mEnv.model.getItemCount() + 1, mAdapter.getItemCount()); + assertHolderType(0, DocumentsAdapter.ITEM_TYPE_HEADER_MESSAGE); + } + + public void testItemCount_none() { + mEnv.model.update(); + assertEquals(1, mAdapter.getItemCount()); + assertHolderType(0, DocumentsAdapter.ITEM_TYPE_INFLATED_MESSAGE); + } + + public void testAddsInfoMessage_WithNoItem() { + Bundle bundle = new Bundle(); + bundle.putString(DocumentsContract.EXTRA_INFO, "some info"); + mEnv.model.setCursorExtras(bundle); + + mEnv.model.update(); + assertEquals(2, mAdapter.getItemCount()); + assertHolderType(0, DocumentsAdapter.ITEM_TYPE_HEADER_MESSAGE); + } + + public void testAddsErrorMessage_WithNoItem() { + Bundle bundle = new Bundle(); + bundle.putString(DocumentsContract.EXTRA_ERROR, "some error"); + mEnv.model.setCursorExtras(bundle); + + mEnv.model.update(); + assertEquals(2, mAdapter.getItemCount()); + assertHolderType(0, DocumentsAdapter.ITEM_TYPE_HEADER_MESSAGE); + } + + public void testOpenTreeMessage_shouldBlockChild() { + if (!VersionUtils.isAtLeastR()) { + return; + } + + mEnv.state.action = State.ACTION_OPEN_TREE; + mEnv.state.restrictScopeStorage = true; + DocumentInfo info = new DocumentInfo(); + info.flags += DocumentsContract.Document.FLAG_DIR_BLOCKS_OPEN_DOCUMENT_TREE; + mEnv.state.stack.push(info); + + mEnv.model.update(); + assertEquals(2, mAdapter.getItemCount()); + assertHolderType(0, DocumentsAdapter.ITEM_TYPE_HEADER_MESSAGE); + } + + public void testOpenTreeMessage_normalChild() { + mEnv.state.action = State.ACTION_OPEN_TREE; + DocumentInfo info = new DocumentInfo(); + mEnv.state.stack.push(info); + + mEnv.model.update(); + // Should only no items message show + assertEquals(1, mAdapter.getItemCount()); + assertHolderType(0, DocumentsAdapter.ITEM_TYPE_INFLATED_MESSAGE); + } + + public void testOpenTreeMessage_restrictStorageAccessFalse_blockTreeChild() { + if (!VersionUtils.isAtLeastR()) { + return; + } + + mEnv.state.action = State.ACTION_OPEN_TREE; + DocumentInfo info = new DocumentInfo(); + info.flags += DocumentsContract.Document.FLAG_DIR_BLOCKS_OPEN_DOCUMENT_TREE; + mEnv.state.stack.push(info); + + mEnv.model.update(); + // Should only no items message show + assertEquals(1, mAdapter.getItemCount()); + assertHolderType(0, DocumentsAdapter.ITEM_TYPE_INFLATED_MESSAGE); + } + + private void assertHolderType(int index, int type) { + assertTrue(mAdapter.getItemViewType(index) == type); + } + + private static class StubAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { + + @Override + public int getItemCount() { + return 0; + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return null; + } + } +} diff --git a/tests/functional/com/android/documentsui/dirlist/DirectoryAddonsAdapterTest.java b/tests/functional/com/android/documentsui/dirlist/DirectoryAddonsAdapterTest.java index bcd1131b7..49c316581 100644 --- a/tests/functional/com/android/documentsui/dirlist/DirectoryAddonsAdapterTest.java +++ b/tests/functional/com/android/documentsui/dirlist/DirectoryAddonsAdapterTest.java @@ -27,11 +27,13 @@ import androidx.test.filters.MediumTest; import com.android.documentsui.ActionHandler; import com.android.documentsui.ModelId; +import com.android.documentsui.TestConfigStore; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.State; import com.android.documentsui.testing.TestActionHandler; import com.android.documentsui.testing.TestEnv; import com.android.documentsui.testing.TestFileTypeLookup; +import com.android.documentsui.testing.TestProvidersAccess; import com.android.documentsui.util.VersionUtils; @MediumTest @@ -42,12 +44,14 @@ public class DirectoryAddonsAdapterTest extends AndroidTestCase { private TestEnv mEnv; private DirectoryAddonsAdapter mAdapter; private ActionHandler mActionHandler; + private TestConfigStore mTestConfigStore; public void setUp() { mEnv = TestEnv.create(AUTHORITY); mActionHandler = new TestActionHandler(); mEnv.clear(); + mTestConfigStore = new TestConfigStore(); final Context testContext = TestContext.createStorageTestContext(getContext(), AUTHORITY); DocumentsAdapter.Environment env = new TestEnvironment(testContext, mEnv, mActionHandler); @@ -56,8 +60,10 @@ public class DirectoryAddonsAdapterTest extends AndroidTestCase { env, new ModelBackedDocumentsAdapter( env, - new IconHelper(testContext, State.MODE_GRID, /* maybeShowBadge= */ false), - new TestFileTypeLookup())); + new IconHelper(testContext, State.MODE_GRID, /* maybeShowBadge= */ false, + null, TestProvidersAccess.OtherUser.USER_ID, null, + mTestConfigStore), + new TestFileTypeLookup(), mTestConfigStore), mTestConfigStore); mEnv.model.addUpdateListener(mAdapter.getModelUpdateListener()); } @@ -202,4 +208,4 @@ public class DirectoryAddonsAdapterTest extends AndroidTestCase { return null; } } -} +}
\ No newline at end of file diff --git a/tests/functional/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterPrivateSpaceTest.java b/tests/functional/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterPrivateSpaceTest.java new file mode 100644 index 000000000..34a6d6f51 --- /dev/null +++ b/tests/functional/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterPrivateSpaceTest.java @@ -0,0 +1,69 @@ +/* + * 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.documentsui.dirlist; + +import android.content.Context; +import android.test.AndroidTestCase; + +import androidx.test.filters.MediumTest; +import androidx.test.filters.SdkSuppress; + +import com.android.documentsui.ActionHandler; +import com.android.documentsui.Model; +import com.android.documentsui.TestConfigStore; +import com.android.documentsui.base.State; +import com.android.documentsui.testing.TestActionHandler; +import com.android.documentsui.testing.TestEnv; +import com.android.documentsui.testing.TestFileTypeLookup; + +@MediumTest +public class ModelBackedDocumentsAdapterPrivateSpaceTest extends AndroidTestCase { + + private static final String AUTHORITY = "test_authority"; + + private TestEnv mEnv; + private ActionHandler mActionHandler; + private TestConfigStore mTestConfigStore; + private ModelBackedDocumentsAdapter mAdapter; + + /** + * set up for the test assuming that private space is enabled. + */ + @SdkSuppress(minSdkVersion = 35, codeName = "V") + public void setUp() { + + final Context testContext = TestContext.createStorageTestContext(getContext(), AUTHORITY); + mEnv = TestEnv.create(AUTHORITY); + mActionHandler = new TestActionHandler(); + mTestConfigStore = new TestConfigStore(); + mTestConfigStore.enablePrivateSpaceInPhotoPicker(); + + DocumentsAdapter.Environment env = new TestEnvironment(testContext, mEnv, mActionHandler); + + mAdapter = new ModelBackedDocumentsAdapter( + env, + new IconHelper(testContext, State.MODE_GRID, /* maybeShowBadge= */ false, + mTestConfigStore), + new TestFileTypeLookup(), mTestConfigStore); + mAdapter.getModelUpdateListener().accept(Model.Update.UPDATE); + } + + // Tests that the item count is correct. + public void testItemCount() { + assertEquals(mEnv.model.getItemCount(), mAdapter.getItemCount()); + } +} diff --git a/tests/functional/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java b/tests/functional/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java index 72014f63b..cf699d366 100644 --- a/tests/functional/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java +++ b/tests/functional/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java @@ -23,10 +23,12 @@ import androidx.test.filters.MediumTest; import com.android.documentsui.ActionHandler; import com.android.documentsui.Model; +import com.android.documentsui.TestConfigStore; import com.android.documentsui.base.State; import com.android.documentsui.testing.TestActionHandler; import com.android.documentsui.testing.TestEnv; import com.android.documentsui.testing.TestFileTypeLookup; +import com.android.documentsui.testing.TestProvidersAccess; @MediumTest public class ModelBackedDocumentsAdapterTest extends AndroidTestCase { @@ -35,6 +37,7 @@ public class ModelBackedDocumentsAdapterTest extends AndroidTestCase { private TestEnv mEnv; private ActionHandler mActionHandler; + private TestConfigStore mTestConfigStore; private ModelBackedDocumentsAdapter mAdapter; public void setUp() { @@ -42,13 +45,15 @@ public class ModelBackedDocumentsAdapterTest extends AndroidTestCase { final Context testContext = TestContext.createStorageTestContext(getContext(), AUTHORITY); mEnv = TestEnv.create(AUTHORITY); mActionHandler = new TestActionHandler(); + mTestConfigStore = new TestConfigStore(); DocumentsAdapter.Environment env = new TestEnvironment(testContext, mEnv, mActionHandler); mAdapter = new ModelBackedDocumentsAdapter( env, - new IconHelper(testContext, State.MODE_GRID, /* maybeShowBadge= */ false), - new TestFileTypeLookup()); + new IconHelper(testContext, State.MODE_GRID, /* maybeShowBadge= */ false, null, + TestProvidersAccess.OtherUser.USER_ID, null, mTestConfigStore), + new TestFileTypeLookup(), mTestConfigStore); mAdapter.getModelUpdateListener().accept(Model.Update.UPDATE); } @@ -56,4 +61,4 @@ public class ModelBackedDocumentsAdapterTest extends AndroidTestCase { public void testItemCount() { assertEquals(mEnv.model.getItemCount(), mAdapter.getItemCount()); } -} +}
\ No newline at end of file diff --git a/tests/functional/com/android/documentsui/inspector/DocumentLoaderTest.java b/tests/functional/com/android/documentsui/inspector/DocumentLoaderTest.java index 8a2b21f10..ac417c90a 100644 --- a/tests/functional/com/android/documentsui/inspector/DocumentLoaderTest.java +++ b/tests/functional/com/android/documentsui/inspector/DocumentLoaderTest.java @@ -25,8 +25,8 @@ import android.net.Uri; import android.os.Bundle; import android.os.Looper; import android.provider.DocumentsContract; -import android.test.suitebuilder.annotation.MediumTest; +import androidx.test.filters.MediumTest; import androidx.test.rule.provider.ProviderTestRule; import com.android.documentsui.InspectorProvider; diff --git a/tests/functional/com/android/documentsui/overlay/OverlayableTest.java b/tests/functional/com/android/documentsui/overlay/OverlayableTest.java index d56470a61..092f4a15d 100644 --- a/tests/functional/com/android/documentsui/overlay/OverlayableTest.java +++ b/tests/functional/com/android/documentsui/overlay/OverlayableTest.java @@ -44,12 +44,6 @@ public class OverlayableTest extends ThemeUiTestBase { } @Test - public void testConfig_isLauncherEnable_isNotNull() { - assertThat( - mTargetContext.getResources().getBoolean(R.bool.is_launcher_enabled)).isNotNull(); - } - - @Test public void testConfig_defaultRootUri_isNotEmpty() { assertThat( mTargetContext.getResources().getString(R.string.default_root_uri)).isNotEmpty(); diff --git a/tests/functional/com/android/documentsui/services/AbstractCopyJobTest.java b/tests/functional/com/android/documentsui/services/AbstractCopyJobTest.java index 7b2cb828c..525397bc0 100644 --- a/tests/functional/com/android/documentsui/services/AbstractCopyJobTest.java +++ b/tests/functional/com/android/documentsui/services/AbstractCopyJobTest.java @@ -23,9 +23,10 @@ import static org.junit.Assert.assertNotEquals; import android.app.Notification; import android.net.Uri; import android.provider.DocumentsContract; -import android.test.suitebuilder.annotation.MediumTest; import android.text.format.DateUtils; +import androidx.test.filters.MediumTest; + import com.android.documentsui.R; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.services.FileOperationService.OpType; diff --git a/tests/lint-baseline.xml b/tests/lint-baseline.xml new file mode 100644 index 000000000..ed87eb9c8 --- /dev/null +++ b/tests/lint-baseline.xml @@ -0,0 +1,147 @@ +<?xml version="1.0" encoding="UTF-8"?> +<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01"> + + <issue + id="NewApi" + message="Call requires API level 34 (current min is 29): `android.content.om.OverlayManager#getOverlayInfosForTarget`" + errorLine1=" when(mOverlayManager.getOverlayInfosForTarget(getEnabledTargetPackageId()," + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/apps/DocumentsUI/tests/functional/com/android/documentsui/ThemeOverlayManagerTest.java" + line="85" + column="30"/> + </issue> + + <issue + id="NewApi" + message="Call requires API level 34 (current min is 29): `android.content.om.OverlayManager#getOverlayInfosForTarget`" + errorLine1=" when(mOverlayManager.getOverlayInfosForTarget(getDisabledTargetPackageId()," + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/apps/DocumentsUI/tests/functional/com/android/documentsui/ThemeOverlayManagerTest.java" + line="89" + column="30"/> + </issue> + + <issue + id="NewApi" + message="Call requires API level 34 (current min is 29): `android.content.om.OverlayManager#setEnabled`" + errorLine1=" verify(mOverlayManager, times(1)).setEnabled(getOverlayPackageId(), enabled," + errorLine2=" ~~~~~~~~~~"> + <location + file="packages/apps/DocumentsUI/tests/functional/com/android/documentsui/ThemeOverlayManagerTest.java" + line="104" + column="43"/> + </issue> + + <issue + id="NewApi" + message="Call requires API level 34 (current min is 29): `android.content.om.OverlayManager#getOverlayInfosForTarget`" + errorLine1=" verify(mOverlayManager, times(1)).getOverlayInfosForTarget(getEnabledTargetPackageId()," + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/apps/DocumentsUI/tests/functional/com/android/documentsui/ThemeOverlayManagerTest.java" + line="116" + column="43"/> + </issue> + + <issue + id="NewApi" + message="Call requires API level 34 (current min is 29): `android.content.om.OverlayManager#setEnabled`" + errorLine1=" verify(mOverlayManager, never()).setEnabled(getOverlayPackageId(), enabled," + errorLine2=" ~~~~~~~~~~"> + <location + file="packages/apps/DocumentsUI/tests/functional/com/android/documentsui/ThemeOverlayManagerTest.java" + line="129" + column="42"/> + </issue> + + <issue + id="NewApi" + message="Call requires API level 34 (current min is 29): `android.content.om.OverlayManager#getOverlayInfosForTarget`" + errorLine1=" assertThat(mOverlayManager.getOverlayInfosForTarget(getDisabledTargetPackageId()," + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/apps/DocumentsUI/tests/functional/com/android/documentsui/ThemeOverlayManagerTest.java" + line="137" + column="36"/> + </issue> + + <issue + id="NewApi" + message="Call requires API level 34 (current min is 29): `android.content.om.OverlayInfo#isEnabled`" + errorLine1=" mUserHandle).get(0).isEnabled()).isEqualTo(!enabled);" + errorLine2=" ~~~~~~~~~"> + <location + file="packages/apps/DocumentsUI/tests/functional/com/android/documentsui/ThemeOverlayManagerTest.java" + line="138" + column="37"/> + </issue> + + <issue + id="NewApi" + message="Call requires API level 34 (current min is 29): `android.content.om.OverlayManager#setEnabled`" + errorLine1=" verify(mOverlayManager, times(1)).setEnabled(getOverlayPackageId(), enabled," + errorLine2=" ~~~~~~~~~~"> + <location + file="packages/apps/DocumentsUI/tests/functional/com/android/documentsui/ThemeOverlayManagerTest.java" + line="146" + column="43"/> + </issue> + + <issue + id="NewApi" + message="Call requires API level 34 (current min is 29): `android.content.om.OverlayManager#getOverlayInfosForTarget`" + errorLine1=" assertThat(mOverlayManager.getOverlayInfosForTarget(getEnabledTargetPackageId()," + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/apps/DocumentsUI/tests/functional/com/android/documentsui/ThemeOverlayManagerTest.java" + line="154" + column="36"/> + </issue> + + <issue + id="NewApi" + message="Call requires API level 34 (current min is 29): `android.content.om.OverlayInfo#isEnabled`" + errorLine1=" mUserHandle).get(0).isEnabled()).isEqualTo(!enabled);" + errorLine2=" ~~~~~~~~~"> + <location + file="packages/apps/DocumentsUI/tests/functional/com/android/documentsui/ThemeOverlayManagerTest.java" + line="155" + column="37"/> + </issue> + + <issue + id="NewApi" + message="Call requires API level 34 (current min is 29): `android.content.om.OverlayManager#setEnabled`" + errorLine1=" verify(mOverlayManager, times(1)).setEnabled(getOverlayPackageId(), enabled," + errorLine2=" ~~~~~~~~~~"> + <location + file="packages/apps/DocumentsUI/tests/functional/com/android/documentsui/ThemeOverlayManagerTest.java" + line="163" + column="43"/> + </issue> + + <issue + id="NewApi" + message="Call requires API level 34 (current min is 29): `android.content.om.OverlayManager#getOverlayInfosForTarget`" + errorLine1=" mOverlayManager.getOverlayInfosForTarget(getEnabledTargetPackageId()," + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/apps/DocumentsUI/tests/functional/com/android/documentsui/ThemeOverlayManagerTest.java" + line="192" + column="33"/> + </issue> + + <issue + id="NewApi" + message="Call requires API level 34 (current min is 29): `new android.content.om.OverlayInfo`" + errorLine1=' return new OverlayInfo(packageName, targetPackageName, null, null, "",' + errorLine2=" ~~~~~~~~~~~~~~~"> + <location + file="packages/apps/DocumentsUI/tests/functional/com/android/documentsui/ThemeOverlayManagerTest.java" + line="211" + column="16"/> + </issue> + +</issues>
\ No newline at end of file diff --git a/tests/unit/com/android/documentsui/AbstractActionHandlerTest.java b/tests/unit/com/android/documentsui/AbstractActionHandlerTest.java index 3eb8ab2fd..104a8d789 100644 --- a/tests/unit/com/android/documentsui/AbstractActionHandlerTest.java +++ b/tests/unit/com/android/documentsui/AbstractActionHandlerTest.java @@ -32,7 +32,6 @@ import android.provider.DocumentsContract.Path; import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails; import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.EventListener; @@ -48,10 +47,16 @@ import com.android.documentsui.testing.TestEnv; import com.android.documentsui.testing.TestEventHandler; import com.android.documentsui.testing.TestProvidersAccess; import com.android.documentsui.testing.UserManagers; +import com.android.modules.utils.build.SdkLevel; + +import com.google.android.collect.Lists; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; import java.util.Arrays; import java.util.concurrent.CountDownLatch; @@ -60,19 +65,39 @@ import java.util.concurrent.TimeUnit; /** * A unit test *for* AbstractActionHandler, not an abstract test baseclass. */ -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) @MediumTest public class AbstractActionHandlerTest { + private final TestConfigStore mTestConfigStore = new TestConfigStore(); private TestActivity mActivity; private TestEnv mEnv; private AbstractActionHandler<TestActivity> mHandler; + @Parameter(0) + public boolean isPrivateSpaceEnabled; + + /** + * Parametrize values for {@code isPrivateSpaceEnabled} to run all the tests twice once with + * private space flag enabled and once with it disabled. + */ + @Parameters(name = "privateSpaceEnabled={0}") + public static Iterable<?> data() { + return Lists.newArrayList(true, false); + } + @Before public void setUp() { mEnv = TestEnv.create(); mActivity = TestActivity.create(mEnv); mActivity.userManager = UserManagers.create(); + mEnv.state.configStore = mTestConfigStore; + + isPrivateSpaceEnabled = SdkLevel.isAtLeastS() && isPrivateSpaceEnabled; + if (isPrivateSpaceEnabled) { + mTestConfigStore.enablePrivateSpaceInPhotoPicker(); + mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.USER_ID, true); + } mHandler = new AbstractActionHandler<TestActivity>( mActivity, mEnv.state, @@ -281,7 +306,11 @@ public class AbstractActionHandlerTest { @Test public void testCrossProfileDocuments_success() throws Exception { mEnv.state.action = State.ACTION_GET_CONTENT; - mEnv.state.canShareAcrossProfile = true; + if (isPrivateSpaceEnabled) { + mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.OtherUser.USER_ID, true); + } else { + mEnv.state.canShareAcrossProfile = true; + } mEnv.state.stack.changeRoot(TestProvidersAccess.OtherUser.HOME); mEnv.state.stack.push(TestEnv.OtherUser.FOLDER_0); @@ -308,7 +337,11 @@ public class AbstractActionHandlerTest { @Test public void testLoadCrossProfileDoc_failsWithQuietModeException() throws Exception { mEnv.state.action = State.ACTION_GET_CONTENT; - mEnv.state.canShareAcrossProfile = true; + if (isPrivateSpaceEnabled) { + mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.OtherUser.USER_ID, true); + } else { + mEnv.state.canShareAcrossProfile = true; + } mEnv.state.stack.changeRoot(TestProvidersAccess.OtherUser.HOME); mEnv.state.stack.push(TestEnv.OtherUser.FOLDER_0); // Turn off the other user. @@ -389,7 +422,11 @@ public class AbstractActionHandlerTest { .setNextChildDocumentsReturns(TestEnv.OtherUser.FILE_PNG); // Disallow sharing across profile - mEnv.state.canShareAcrossProfile = false; + if (isPrivateSpaceEnabled) { + mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.OtherUser.USER_ID, false); + } else { + mEnv.state.canShareAcrossProfile = false; + } TestEventHandler<Model.Update> listener = new TestEventHandler<>(); mEnv.model.addUpdateListener(listener::accept); @@ -404,7 +441,11 @@ public class AbstractActionHandlerTest { .isInstanceOf(CrossProfileNoPermissionException.class); // Allow sharing across profile. - mEnv.state.canShareAcrossProfile = true; + if (isPrivateSpaceEnabled) { + mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.OtherUser.USER_ID, true); + } else { + mEnv.state.canShareAcrossProfile = true; + } CountDownLatch latch2 = new CountDownLatch(1); mEnv.model.addUpdateListener(update -> latch2.countDown()); diff --git a/tests/unit/com/android/documentsui/DocumentsAccessTest.java b/tests/unit/com/android/documentsui/DocumentsAccessTest.java index 8a08d431b..f52c21b4f 100644 --- a/tests/unit/com/android/documentsui/DocumentsAccessTest.java +++ b/tests/unit/com/android/documentsui/DocumentsAccessTest.java @@ -18,27 +18,47 @@ package com.android.documentsui; import static junit.framework.Assert.fail; +import static org.mockito.Mockito.mock; + +import android.content.ContentProviderClient; import android.content.pm.PackageManager; import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; import com.android.documentsui.testing.TestEnv; import com.android.documentsui.testing.TestProvidersAccess; +import com.android.modules.utils.build.SdkLevel; import com.google.common.collect.Lists; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) @MediumTest public class DocumentsAccessTest { + private final TestConfigStore mTestConfigStore = new TestConfigStore(); private TestActivity mActivity; private DocumentsAccess mDocumentsAccess; private TestEnv mEnv; + private ContentProviderClient mMockContentProviderClient = mock(ContentProviderClient.class); + + @Parameter(0) + public boolean isPrivateSpaceEnabled; + + /** + * Parametrize values for {@code isPrivateSpaceEnabled} to run all the tests twice once with + * private space flag enabled and once with it disabled. + */ + @Parameters(name = "privateSpaceEnabled={0}") + public static Iterable<?> data() { + return Lists.newArrayList(true, false); + } @Before public void setUp() throws PackageManager.NameNotFoundException { @@ -46,6 +66,11 @@ public class DocumentsAccessTest { mEnv.reset(); mActivity = TestActivity.create(mEnv); mDocumentsAccess = DocumentsAccess.create(mActivity, mEnv.state); + mEnv.state.configStore = mTestConfigStore; + isPrivateSpaceEnabled = SdkLevel.isAtLeastS() && isPrivateSpaceEnabled; + if (isPrivateSpaceEnabled) { + mTestConfigStore.enablePrivateSpaceInPhotoPicker(); + } } @Test diff --git a/tests/unit/com/android/documentsui/FocusManagerTest.java b/tests/unit/com/android/documentsui/FocusManagerTest.java index 67e70005e..36637f3cb 100644 --- a/tests/unit/com/android/documentsui/FocusManagerTest.java +++ b/tests/unit/com/android/documentsui/FocusManagerTest.java @@ -17,10 +17,10 @@ package com.android.documentsui; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; import androidx.recyclerview.selection.SelectionTracker; import androidx.recyclerview.widget.RecyclerView; +import androidx.test.filters.SmallTest; import com.android.documentsui.base.UserId; import com.android.documentsui.dirlist.TestData; diff --git a/tests/unit/com/android/documentsui/GlobalSearchLoaderTest.java b/tests/unit/com/android/documentsui/GlobalSearchLoaderTest.java index c52dbd3de..3cbed8009 100644 --- a/tests/unit/com/android/documentsui/GlobalSearchLoaderTest.java +++ b/tests/unit/com/android/documentsui/GlobalSearchLoaderTest.java @@ -27,7 +27,6 @@ import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.State; @@ -38,13 +37,19 @@ import com.android.documentsui.testing.TestEnv; import com.android.documentsui.testing.TestFileTypeLookup; import com.android.documentsui.testing.TestImmediateExecutor; import com.android.documentsui.testing.TestProvidersAccess; +import com.android.modules.utils.build.SdkLevel; + +import com.google.common.collect.Lists; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) @MediumTest public class GlobalSearchLoaderTest { @@ -55,13 +60,34 @@ public class GlobalSearchLoaderTest { private TestEnv mEnv; private TestActivity mActivity; private GlobalSearchLoader mLoader; + private TestConfigStore mTestConfigStore; private Bundle mQueryArgs = new Bundle(); + @Parameter(0) + public boolean isPrivateSpaceEnabled; + + /** + * Parametrize values for {@code isPrivateSpaceEnabled} to run all the tests twice once with + * private space flag enabled and once with it disabled. + */ + @Parameters(name = "privateSpaceEnabled={0}") + public static Iterable<?> data() { + return Lists.newArrayList(true, false); + } + @Before public void setUp() { mEnv = TestEnv.create(); mActivity = TestActivity.create(mEnv); mActivity.activityManager = ActivityManagers.create(false); + mTestConfigStore = new TestConfigStore(); + mEnv.state.configStore = mTestConfigStore; + + isPrivateSpaceEnabled &= SdkLevel.isAtLeastS(); + if (isPrivateSpaceEnabled) { + mTestConfigStore.enablePrivateSpaceInPhotoPicker(); + mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.USER_ID, true); + } mEnv.state.action = State.ACTION_BROWSE; mEnv.state.acceptMimes = new String[]{"*/*"}; @@ -93,6 +119,7 @@ public class GlobalSearchLoaderTest { @Test public void testNotLocalOnlyRoot_beIgnored() { + if (isPrivateSpaceEnabled) return; TestProvidersAccess.PICKLES.flags |= DocumentsContract.Root.FLAG_SUPPORTS_SEARCH; assertTrue(mLoader.shouldIgnoreRoot(TestProvidersAccess.PICKLES)); TestProvidersAccess.PICKLES.flags &= ~DocumentsContract.Root.FLAG_SUPPORTS_SEARCH; @@ -301,7 +328,11 @@ public class GlobalSearchLoaderTest { @Test public void testSearchResult_includeBothUsersRoots() { - mEnv.state.canShareAcrossProfile = true; + if (isPrivateSpaceEnabled) { + mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.OtherUser.USER_ID, true); + } else { + mEnv.state.canShareAcrossProfile = true; + } mEnv.state.supportsCrossProfile = true; final DocumentInfo pdfDoc = mEnv.model.createFile(SEARCH_STRING + ".pdf"); diff --git a/tests/unit/com/android/documentsui/ProfileTabsTest.java b/tests/unit/com/android/documentsui/ProfileTabsTest.java index 373f4e5cd..ad674656a 100644 --- a/tests/unit/com/android/documentsui/ProfileTabsTest.java +++ b/tests/unit/com/android/documentsui/ProfileTabsTest.java @@ -32,20 +32,27 @@ import com.android.documentsui.base.State; import com.android.documentsui.base.UserId; import com.android.documentsui.testing.TestEnv; import com.android.documentsui.testing.TestProvidersAccess; +import com.android.modules.utils.build.SdkLevel; -import com.google.android.collect.Lists; import com.google.android.material.tabs.TabLayout; +import com.google.common.collect.Lists; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; -import java.util.Collections; import java.util.List; +import java.util.Map; +@RunWith(Parameterized.class) public class ProfileTabsTest { - private final UserId systemUser = UserId.of(UserHandle.SYSTEM); - private final UserId managedUser = UserId.of(100); + private final UserId mPrimaryUser = UserId.of(UserHandle.myUserId()); + private final UserId mManagedUser = UserId.of(100); + private final UserId mPrivateUser = UserId.of(101); private ProfileTabs mProfileTabs; @@ -55,8 +62,22 @@ public class ProfileTabsTest { private TestEnvironment mTestEnv; private State mState; private TestUserIdManager mTestUserIdManager; + private TestUserManagerState mTestUserManagerState; private TestCommonAddons mTestCommonAddons; private boolean mIsListenerInvoked; + private TestConfigStore mTestConfigStore; + + @Parameter(0) + public boolean isPrivateSpaceEnabled; + + /** + * Parametrize values for {@code isPrivateSpaceEnabled} to run all the tests twice once with + * private space flag enabled and once with it disabled. + */ + @Parameters(name = "privateSpaceEnabled={0}") + public static Iterable<?> data() { + return Lists.newArrayList(true, false); + } @Before public void setUp() { @@ -76,14 +97,21 @@ public class ProfileTabsTest { mTestEnv = new TestEnvironment(); mTestEnv.isSearchExpanded = false; - mTestUserIdManager = new TestUserIdManager(); + if (isPrivateSpaceEnabled && SdkLevel.isAtLeastS()) { + mTestUserManagerState = new TestUserManagerState(); + } else { + mTestUserIdManager = new TestUserIdManager(); + } + isPrivateSpaceEnabled = SdkLevel.isAtLeastS() && isPrivateSpaceEnabled; + mTestCommonAddons = new TestCommonAddons(); mTestCommonAddons.mCurrentRoot = TestProvidersAccess.DOWNLOADS; + mTestConfigStore = new TestConfigStore(); } @Test public void testUpdateView_singleUser_shouldHide() { - initializeWithUsers(systemUser); + initializeWithUsers(isPrivateSpaceEnabled, mPrimaryUser); assertThat(mTabLayoutContainer.getVisibility()).isEqualTo(View.GONE); assertThat(mTabLayout.getTabCount()).isEqualTo(0); @@ -91,23 +119,40 @@ public class ProfileTabsTest { @Test public void testUpdateView_twoUsers_shouldShow() { - initializeWithUsers(systemUser, managedUser); + initializeWithUsers(isPrivateSpaceEnabled, mPrimaryUser, mManagedUser); assertThat(mTabLayoutContainer.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mTabLayout.getTabCount()).isEqualTo(2); TabLayout.Tab tab1 = mTabLayout.getTabAt(0); - assertThat(tab1.getTag()).isEqualTo(systemUser); + assertThat(tab1.getTag()).isEqualTo(mPrimaryUser); assertThat(tab1.getText()).isEqualTo(mContext.getString(R.string.personal_tab)); TabLayout.Tab tab2 = mTabLayout.getTabAt(1); - assertThat(tab2.getTag()).isEqualTo(managedUser); + assertThat(tab2.getTag()).isEqualTo(mManagedUser); assertThat(tab2.getText()).isEqualTo(mContext.getString(R.string.work_tab)); } @Test + public void testUpdateView_multiUsers_shouldShow() { + if (!SdkLevel.isAtLeastV() || !isPrivateSpaceEnabled) return; + initializeWithUsers(true, mPrimaryUser, mManagedUser, mPrivateUser); + + assertThat(mTabLayoutContainer.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mTabLayout.getTabCount()).isEqualTo(3); + + final Map<UserId, String> userIdToLabelMap = mTestUserManagerState.getUserIdToLabelMap(); + for (int i = 0; i < 3; ++i) { + TabLayout.Tab tab = mTabLayout.getTabAt(i); + assertThat(tab).isNotNull(); + UserId userId = (UserId) tab.getTag(); + assertThat(tab.getText()).isEqualTo(userIdToLabelMap.get(userId)); + } + } + + @Test public void testUpdateView_twoUsers_doesNotSupportCrossProfile_shouldHide() { - initializeWithUsers(systemUser, managedUser); + initializeWithUsers(isPrivateSpaceEnabled, mPrimaryUser, mManagedUser); mState.supportsCrossProfile = false; mProfileTabs.updateView(); @@ -117,7 +162,7 @@ public class ProfileTabsTest { @Test public void testUpdateView_twoUsers_subFolder_shouldHide() { - initializeWithUsers(systemUser, managedUser); + initializeWithUsers(isPrivateSpaceEnabled, mPrimaryUser, mManagedUser); // Push 1 more folder. Now the stack has size of 2. mState.stack.push(TestEnv.FOLDER_1); @@ -129,7 +174,7 @@ public class ProfileTabsTest { @Test public void testUpdateView_twoUsers_recents_subFolder_shouldHide() { - initializeWithUsers(systemUser, managedUser); + initializeWithUsers(isPrivateSpaceEnabled, mPrimaryUser, mManagedUser); mState.stack.changeRoot(TestProvidersAccess.RECENTS); // This(stack of size 2 in Recents) may not happen in real world. @@ -142,7 +187,7 @@ public class ProfileTabsTest { @Test public void testUpdateView_twoUsers_thirdParty_shouldHide() { - initializeWithUsers(systemUser, managedUser); + initializeWithUsers(isPrivateSpaceEnabled, mPrimaryUser, mManagedUser); mState.stack.changeRoot(TestProvidersAccess.PICKLES); mState.stack.push((TestEnv.FOLDER_0)); @@ -155,7 +200,7 @@ public class ProfileTabsTest { @Test public void testUpdateView_twoUsers_isSearching_shouldHide() { mTestEnv.isSearchExpanded = true; - initializeWithUsers(systemUser, managedUser); + initializeWithUsers(isPrivateSpaceEnabled, mPrimaryUser, mManagedUser); assertThat(mTabLayoutContainer.getVisibility()).isEqualTo(View.GONE); assertThat(mTabLayout.getTabCount()).isEqualTo(2); @@ -163,78 +208,150 @@ public class ProfileTabsTest { @Test public void testUpdateView_getSelectedUser_afterUsersChanged() { - initializeWithUsers(systemUser, managedUser); + initializeWithUsers(isPrivateSpaceEnabled, mPrimaryUser, mManagedUser); mProfileTabs.updateView(); mTabLayout.selectTab(mTabLayout.getTabAt(1)); assertThat(mTabLayoutContainer.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(mProfileTabs.getSelectedUser()).isEqualTo(managedUser); + assertThat(mProfileTabs.getSelectedUser()).isEqualTo(mManagedUser); - mTestUserIdManager.userIds = Collections.singletonList(systemUser); + if (SdkLevel.isAtLeastS() && isPrivateSpaceEnabled) { + mTestUserManagerState.userIds = Lists.newArrayList(mPrimaryUser); + } else { + mTestUserIdManager.userIds = Lists.newArrayList(mPrimaryUser); + } mProfileTabs.updateView(); assertThat(mTabLayoutContainer.getVisibility()).isEqualTo(View.GONE); - assertThat(mProfileTabs.getSelectedUser()).isEqualTo(systemUser); + assertThat(mProfileTabs.getSelectedUser()).isEqualTo(mPrimaryUser); } @Test public void testUpdateView_afterCurrentRootChanged_shouldChangeSelectedUser() { - initializeWithUsers(systemUser, managedUser); + initializeWithUsers(isPrivateSpaceEnabled, mPrimaryUser, mManagedUser); mProfileTabs.updateView(); - assertThat(mProfileTabs.getSelectedUser()).isEqualTo(systemUser); + assertThat(mProfileTabs.getSelectedUser()).isEqualTo(mPrimaryUser); RootInfo newRoot = RootInfo.copyRootInfo(mTestCommonAddons.mCurrentRoot); - newRoot.userId = managedUser; + newRoot.userId = mManagedUser; mTestCommonAddons.mCurrentRoot = newRoot; mProfileTabs.updateView(); - assertThat(mProfileTabs.getSelectedUser()).isEqualTo(managedUser); + assertThat(mProfileTabs.getSelectedUser()).isEqualTo(mManagedUser); // updating view should not trigger listener callback. assertThat(mIsListenerInvoked).isFalse(); } @Test - public void testgetSelectedUser_twoUsers() { - initializeWithUsers(systemUser, managedUser); + public void testUpdateView_afterCurrentRootChangedMultiUser_shouldChangeSelectedUser() { + if (!SdkLevel.isAtLeastV() || !isPrivateSpaceEnabled) return; + initializeWithUsers(true, mPrimaryUser, mManagedUser, mPrivateUser); + mProfileTabs.updateView(); + + assertThat(mProfileTabs.getSelectedUser()).isEqualTo(mPrimaryUser); + + for (UserId userId : Lists.newArrayList(mManagedUser, mPrivateUser)) { + RootInfo newRoot = RootInfo.copyRootInfo(mTestCommonAddons.mCurrentRoot); + newRoot.userId = userId; + mTestCommonAddons.mCurrentRoot = newRoot; + mProfileTabs.updateView(); + + assertThat(mProfileTabs.getSelectedUser()).isEqualTo(userId); + // updating view should not trigger listener callback. + assertThat(mIsListenerInvoked).isFalse(); + } + } + + @Test + public void testUpdateView_afterSelectedUserBecomesUnavailable_shouldSwitchToCurrentUser() { + // here current user refers to UserId.CURRENT_USER, which in this case will be mPrimaryUser + if (!SdkLevel.isAtLeastS() || !isPrivateSpaceEnabled) return; + initializeWithUsers(true, mPrimaryUser, mManagedUser, mPrivateUser); + + mTabLayout.selectTab(mTabLayout.getTabAt(2)); + assertThat(mProfileTabs.getSelectedUser()).isEqualTo(mPrivateUser); + + mTestUserManagerState.userIds.remove(mPrivateUser); + mTestUserManagerState.userIdToLabelMap.remove(mPrivateUser); + mProfileTabs.updateView(); + + assertThat(mProfileTabs.getSelectedUser()).isEqualTo(mPrimaryUser); + } + + @Test + public void testGetSelectedUser_twoUsers() { + initializeWithUsers(isPrivateSpaceEnabled, mPrimaryUser, mManagedUser); mTabLayout.selectTab(mTabLayout.getTabAt(0)); - assertThat(mProfileTabs.getSelectedUser()).isEqualTo(systemUser); + assertThat(mProfileTabs.getSelectedUser()).isEqualTo(mPrimaryUser); mTabLayout.selectTab(mTabLayout.getTabAt(1)); - assertThat(mProfileTabs.getSelectedUser()).isEqualTo(managedUser); + assertThat(mProfileTabs.getSelectedUser()).isEqualTo(mManagedUser); assertThat(mIsListenerInvoked).isTrue(); } @Test + public void testGetSelectedUser_multiUsers() { + if (!SdkLevel.isAtLeastV() || !isPrivateSpaceEnabled) return; + initializeWithUsers(true, mPrimaryUser, mManagedUser, mPrivateUser); + + List<UserId> expectedProfiles = Lists.newArrayList(mPrimaryUser, mManagedUser, + mPrivateUser); + + for (int i = 0; i < 3; ++i) { + mTabLayout.selectTab(mTabLayout.getTabAt(i)); + assertThat(mProfileTabs.getSelectedUser()).isEqualTo(expectedProfiles.get(i)); + if (i == 0) continue; + assertThat(mIsListenerInvoked).isTrue(); + } + } + + @Test public void testReselectedUser_doesNotInvokeListener() { - initializeWithUsers(systemUser, managedUser); + initializeWithUsers(isPrivateSpaceEnabled, mPrimaryUser, mManagedUser); assertThat(mTabLayout.getSelectedTabPosition()).isAtLeast(0); - assertThat(mProfileTabs.getSelectedUser()).isEqualTo(systemUser); + assertThat(mProfileTabs.getSelectedUser()).isEqualTo(mPrimaryUser); mTabLayout.selectTab(mTabLayout.getTabAt(0)); - assertThat(mProfileTabs.getSelectedUser()).isEqualTo(systemUser); + assertThat(mProfileTabs.getSelectedUser()).isEqualTo(mPrimaryUser); assertThat(mIsListenerInvoked).isFalse(); } @Test - public void testgetSelectedUser_singleUsers() { - initializeWithUsers(systemUser); + public void testGetSelectedUser_singleUsers() { + initializeWithUsers(isPrivateSpaceEnabled, mPrimaryUser); - assertThat(mProfileTabs.getSelectedUser()).isEqualTo(systemUser); + assertThat(mProfileTabs.getSelectedUser()).isEqualTo(mPrimaryUser); } - private void initializeWithUsers(UserId... userIds) { - mTestUserIdManager.userIds = Lists.newArrayList(userIds); - for (UserId userId : userIds) { - if (userId.isSystem()) { - mTestUserIdManager.systemUser = userId; - } else { - mTestUserIdManager.managedUser = userId; + private void initializeWithUsers(boolean isPrivateSpaceEnabled, UserId... userIds) { + if (SdkLevel.isAtLeastS() && isPrivateSpaceEnabled) { + mTestConfigStore.enablePrivateSpaceInPhotoPicker(); + mTestUserManagerState.userIds = Lists.newArrayList(userIds); + for (UserId userId : userIds) { + if (userId.equals(UserId.of(UserHandle.myUserId()))) { + mTestUserManagerState.userIdToLabelMap.put(userId, "Personal"); + } else if (userId.getIdentifier() == 100) { + mTestUserManagerState.userIdToLabelMap.put(userId, "Work"); + } else { + mTestUserManagerState.userIdToLabelMap.put(userId, "Private"); + } } + mProfileTabs = new ProfileTabs(mTabLayoutContainer, mState, mTestUserManagerState, + mTestEnv, mTestCommonAddons, mTestConfigStore); + } else { + mTestConfigStore.disablePrivateSpaceInPhotoPicker(); + mTestUserIdManager.userIds = Lists.newArrayList(userIds); + for (UserId userId : userIds) { + if (userId.equals(UserId.of(UserHandle.myUserId()))) { + mTestUserIdManager.systemUser = userId; + } else { + mTestUserIdManager.managedUser = userId; + } + } + mProfileTabs = new ProfileTabs(mTabLayoutContainer, mState, mTestUserIdManager, + mTestEnv, mTestCommonAddons, mTestConfigStore); } - - mProfileTabs = new ProfileTabs(mTabLayoutContainer, mState, mTestUserIdManager, mTestEnv, - mTestCommonAddons); mProfileTabs.updateView(); mProfileTabs.setListener(userId -> mIsListenerInvoked = true); } diff --git a/tests/unit/com/android/documentsui/RecentsLoaderTests.java b/tests/unit/com/android/documentsui/RecentsLoaderTests.java index d95e9243c..bf8c97ea5 100644 --- a/tests/unit/com/android/documentsui/RecentsLoaderTests.java +++ b/tests/unit/com/android/documentsui/RecentsLoaderTests.java @@ -29,7 +29,6 @@ import android.database.Cursor; import android.provider.DocumentsContract.Document; import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.State; @@ -41,22 +40,40 @@ import com.android.documentsui.testing.TestFileTypeLookup; import com.android.documentsui.testing.TestImmediateExecutor; import com.android.documentsui.testing.TestProvidersAccess; import com.android.documentsui.testing.UserManagers; +import com.android.modules.utils.build.SdkLevel; + +import com.google.common.collect.Lists; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) @MediumTest public class RecentsLoaderTests { private TestEnv mEnv; private TestActivity mActivity; private RecentsLoader mLoader; - private boolean mContentChanged; + private TestConfigStore mTestConfigStore; + + @Parameter(0) + public boolean isPrivateSpaceEnabled; + + /** + * Parameterized test to run all the tests in this class twice, once with private space enabled + * and once with private space disabled. + */ + @Parameters(name = "privateSpaceEnabled={0}") + public static Iterable<?> data() { + return Lists.newArrayList(true, false); + } @Before public void setUp() { @@ -64,14 +81,23 @@ public class RecentsLoaderTests { mActivity = TestActivity.create(mEnv); mActivity.activityManager = ActivityManagers.create(false); mActivity.userManager = UserManagers.create(); + mTestConfigStore = new TestConfigStore(); + mEnv.state.configStore = mTestConfigStore; mEnv.state.action = State.ACTION_BROWSE; - mEnv.state.acceptMimes = new String[] { "*/*" }; - mEnv.state.canShareAcrossProfile = true; + mEnv.state.acceptMimes = new String[]{"*/*"}; + isPrivateSpaceEnabled = SdkLevel.isAtLeastS() && isPrivateSpaceEnabled; + if (isPrivateSpaceEnabled) { + mTestConfigStore.enablePrivateSpaceInPhotoPicker(); + mEnv.state.canForwardToProfileIdMap.put(UserId.DEFAULT_USER, true); + mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.OtherUser.USER_ID, true); + } else { + mEnv.state.canShareAcrossProfile = true; + } mLoader = new RecentsLoader(mActivity, mEnv.providers, mEnv.state, TestImmediateExecutor.createLookup(), new TestFileTypeLookup(), - UserId.DEFAULT_USER); + TestProvidersAccess.USER_ID); } @Test @@ -114,7 +140,7 @@ public class RecentsLoaderTests { mEnv.mockProviders.get(TestProvidersAccess.HOME.authority) .setNextRecentDocumentsReturns(doc1, doc2); - assertEquals(false, mLoader.mState.showHiddenFiles); + assertFalse(mLoader.mState.showHiddenFiles); DirectoryResult result = mLoader.loadInBackground(); assertEquals(0, result.getCursor().getCount()); @@ -148,12 +174,13 @@ public class RecentsLoaderTests { @Test public void testContentsUpdate_observable() throws Exception { - CountDownLatch latch = new CountDownLatch(1); - Runnable callback = () -> { - latch.countDown(); - mContentChanged = true; - }; - mLoader.setObserver(new LockingContentObserver(new ContentLock(), callback)); + final CountDownLatch latch = new CountDownLatch(1); + + // Please be mindful of the fact that the callback will be invoked on the Main (aka UI) + // thread, while the test itself is running on another (dedicated) thread. + final Runnable onContentChangedCallback = latch::countDown; + mLoader.setObserver(new LockingContentObserver( + new ContentLock(), onContentChangedCallback)); final DocumentInfo doc = mEnv.model.createFile("freddy.jpg"); doc.lastModified = System.currentTimeMillis(); @@ -162,17 +189,21 @@ public class RecentsLoaderTests { mLoader.loadInBackground(); - TestCursor c = (TestCursor) mEnv.mockProviders.get(TestProvidersAccess.HOME.authority) + final TestCursor c = (TestCursor) mEnv.mockProviders.get(TestProvidersAccess.HOME.authority) .queryRecentDocuments(null, null); c.mockOnChange(); - latch.await(1, TimeUnit.SECONDS); - assertTrue(mContentChanged); + final boolean onContentChangedCallbackInvoked = latch.await(1, TimeUnit.SECONDS); + assertTrue(onContentChangedCallbackInvoked); } @Test public void testLoaderOnUserWithoutPermission() { - mEnv.state.canShareAcrossProfile = false; + if (isPrivateSpaceEnabled) { + mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.OtherUser.USER_ID, false); + } else { + mEnv.state.canShareAcrossProfile = false; + } mLoader = new RecentsLoader(mActivity, mEnv.providers, mEnv.state, TestImmediateExecutor.createLookup(), new TestFileTypeLookup(), TestProvidersAccess.OtherUser.USER_ID); diff --git a/tests/unit/com/android/documentsui/UserIdManagerTest.java b/tests/unit/com/android/documentsui/UserIdManagerTest.java index 31fe7d166..36ff8ac68 100644 --- a/tests/unit/com/android/documentsui/UserIdManagerTest.java +++ b/tests/unit/com/android/documentsui/UserIdManagerTest.java @@ -131,10 +131,12 @@ public class UserIdManagerTest { @Test public void testGetUserIds_deviceNotSupported() { // we should return the current user when device is not supported. - UserId currentUser = UserId.of(systemUser); - when(mockUserManager.getUserProfiles()).thenReturn(Arrays.asList(systemUser, managedUser1)); - mUserIdManager = new UserIdManager.RuntimeUserIdManager(mockContext, currentUser, false); - assertThat(mUserIdManager.getUserIds()).containsExactly(UserId.of(systemUser)); + UserHandle currentUser = UserHandle.of(UserHandle.myUserId()); + when(mockUserManager.getUserProfiles()).thenReturn( + Arrays.asList(currentUser, managedUser1)); + mUserIdManager = new UserIdManager.RuntimeUserIdManager(mockContext, UserId.of(currentUser), + false); + assertThat(mUserIdManager.getUserIds()).containsExactly(UserId.of(currentUser)); } @Test @@ -142,13 +144,14 @@ public class UserIdManagerTest { // This test only tests for Android R or later. This test case always passes before R. if (VersionUtils.isAtLeastR()) { // When permission is denied, only returns the current user. - when(mockContext.checkSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS)) - .thenReturn(PackageManager.PERMISSION_DENIED); - UserId currentUser = UserId.of(systemUser); + when(mockContext.checkSelfPermission( + Manifest.permission.INTERACT_ACROSS_USERS)).thenReturn( + PackageManager.PERMISSION_DENIED); + UserHandle currentUser = UserHandle.of(UserHandle.myUserId()); when(mockUserManager.getUserProfiles()).thenReturn( - Arrays.asList(systemUser, managedUser1)); + Arrays.asList(currentUser, managedUser1)); mUserIdManager = UserIdManager.create(mockContext); - assertThat(mUserIdManager.getUserIds()).containsExactly(UserId.of(systemUser)); + assertThat(mUserIdManager.getUserIds()).containsExactly(UserId.of(currentUser)); } } diff --git a/tests/unit/com/android/documentsui/UserManagerStateTest.java b/tests/unit/com/android/documentsui/UserManagerStateTest.java new file mode 100644 index 000000000..574d65552 --- /dev/null +++ b/tests/unit/com/android/documentsui/UserManagerStateTest.java @@ -0,0 +1,867 @@ +/* + * Copyright (C) 2020 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.documentsui; + +import static com.android.documentsui.DevicePolicyResources.Drawables.Style.SOLID_COLORED; +import static com.android.documentsui.DevicePolicyResources.Drawables.WORK_PROFILE_ICON; +import static com.android.documentsui.DevicePolicyResources.Strings.PERSONAL_TAB; +import static com.android.documentsui.DevicePolicyResources.Strings.WORK_TAB; + +import static com.google.common.truth.Truth.assertWithMessage; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.Manifest; +import android.app.admin.DevicePolicyManager; +import android.app.admin.DevicePolicyResourcesManager; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.UserProperties; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; +import android.os.UserManager; + +import androidx.test.filters.SdkSuppress; +import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.documentsui.base.UserId; +import com.android.documentsui.testing.UserManagers; +import com.android.documentsui.util.VersionUtils; +import com.android.modules.utils.build.SdkLevel; + +import com.google.common.collect.Lists; + +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@SmallTest +@SdkSuppress(minSdkVersion = 31, codeName = "S") +public class UserManagerStateTest { + + private static final String PERSONAL = "Personal"; + private static final String WORK = "Work"; + private static final String PRIVATE = "Private"; + + /** + * Assume that the current user is SYSTEM_USER. + * For HSUM targets, the primary user is set as the system user. + */ + private final int mCurrentUserId = UserHandle.myUserId(); + private final UserHandle mPrimaryUser = UserHandle.of(mCurrentUserId); + private final UserHandle mSystemUser = mPrimaryUser == null ? UserHandle.SYSTEM : mPrimaryUser; + private final UserHandle mManagedUser = UserHandle.of(mCurrentUserId + 10); + private final UserHandle mPrivateUser = UserHandle.of(mCurrentUserId + 20); + private final UserHandle mOtherUser = UserHandle.of(mCurrentUserId + 30); + private final UserHandle mNormalUser = UserHandle.of(mCurrentUserId + 40); + + private final ResolveInfo mMockInfo1 = mock(ResolveInfo.class); + private final ResolveInfo mMockInfo2 = mock(ResolveInfo.class); + private final ResolveInfo mMockInfo3 = mock(ResolveInfo.class); + + private final Context mMockContext = mock(Context.class); + private final Intent mMockIntent = mock(Intent.class); + private final UserManager mMockUserManager = UserManagers.create(); + private final PackageManager mMockPackageManager = mock(PackageManager.class); + private final DevicePolicyManager mDevicePolicyManager = mock(DevicePolicyManager.class); + private UserManagerState mUserManagerState; + + @Before + public void setup() throws Exception { + when(mMockContext.getApplicationContext()).thenReturn(mMockContext); + + when(mMockUserManager.isManagedProfile(mManagedUser.getIdentifier())).thenReturn(true); + when(mMockUserManager.isManagedProfile(mSystemUser.getIdentifier())).thenReturn(false); + when(mMockUserManager.isManagedProfile(mPrivateUser.getIdentifier())).thenReturn(false); + when(mMockUserManager.isManagedProfile(mOtherUser.getIdentifier())).thenReturn(false); + + if (SdkLevel.isAtLeastV()) { + UserProperties systemUserProperties = new UserProperties.Builder() + .setShowInSharingSurfaces(UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE) + .setCrossProfileContentSharingStrategy( + UserProperties.CROSS_PROFILE_CONTENT_SHARING_NO_DELEGATION) + .build(); + UserProperties managedUserProperties = new UserProperties.Builder() + .setShowInSharingSurfaces(UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE) + .setCrossProfileContentSharingStrategy( + UserProperties.CROSS_PROFILE_CONTENT_SHARING_NO_DELEGATION) + .setShowInQuietMode(UserProperties.SHOW_IN_QUIET_MODE_PAUSED) + .build(); + UserProperties privateUserProperties = new UserProperties.Builder() + .setShowInSharingSurfaces(UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE) + .setCrossProfileContentSharingStrategy( + UserProperties.CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT) + .setShowInQuietMode(UserProperties.SHOW_IN_QUIET_MODE_HIDDEN) + .build(); + UserProperties otherUserProperties = new UserProperties.Builder() + .setShowInSharingSurfaces(UserProperties.SHOW_IN_SHARING_SURFACES_WITH_PARENT) + .setCrossProfileContentSharingStrategy( + UserProperties.CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT) + .build(); + UserProperties normalUserProperties = new UserProperties.Builder() + .setShowInSharingSurfaces(UserProperties.SHOW_IN_SHARING_SURFACES_NO) + .setCrossProfileContentSharingStrategy( + UserProperties.CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT) + .build(); + when(mMockUserManager.getUserProperties(mSystemUser)).thenReturn(systemUserProperties); + when(mMockUserManager.getUserProperties(mManagedUser)).thenReturn( + managedUserProperties); + when(mMockUserManager.getUserProperties(mPrivateUser)).thenReturn( + privateUserProperties); + when(mMockUserManager.getUserProperties(mOtherUser)).thenReturn(otherUserProperties); + when(mMockUserManager.getUserProperties(mNormalUser)).thenReturn(normalUserProperties); + } + + when(mMockUserManager.getProfileParent(mSystemUser)).thenReturn(null); + when(mMockUserManager.getProfileParent(mManagedUser)).thenReturn(mSystemUser); + when(mMockUserManager.getProfileParent(mPrivateUser)).thenReturn(mSystemUser); + when(mMockUserManager.getProfileParent(mOtherUser)).thenReturn(mSystemUser); + when(mMockUserManager.getProfileParent(mNormalUser)).thenReturn(null); + + if (SdkLevel.isAtLeastR()) { + when(mMockInfo1.isCrossProfileIntentForwarderActivity()).thenReturn(true); + when(mMockInfo2.isCrossProfileIntentForwarderActivity()).thenReturn(false); + when(mMockInfo3.isCrossProfileIntentForwarderActivity()).thenReturn(false); + } + + when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager); + when(mMockContext.getSystemServiceName(UserManager.class)).thenReturn("mMockUserManager"); + when(mMockContext.getSystemService(UserManager.class)).thenReturn(mMockUserManager); + when(mMockContext.getSystemServiceName(DevicePolicyManager.class)) + .thenReturn(Context.DEVICE_POLICY_SERVICE); + when(mMockContext.getSystemService(Context.DEVICE_POLICY_SERVICE)) + .thenReturn(mDevicePolicyManager); + when(mMockContext.getResources()).thenReturn( + InstrumentationRegistry.getInstrumentation().getTargetContext().getResources()); + } + + @Test + public void testGetUserIds_onlySystemUser_returnsSystemUser() { + UserId currentUser = UserId.of(mSystemUser); + initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser)); + + assertWithMessage("getUserIds returns unexpected list of user ids") + .that(mUserManagerState.getUserIds()).containsExactly(UserId.of(mSystemUser)); + } + + @Test + public void testGetUserIds_allProfilesCurrentUserSystem_allShowInSharingSurfacesSeparate() { + if (!SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mSystemUser); + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser, mOtherUser, + mNormalUser)); + + assertWithMessage("getUserIds returns unexpected list of user ids") + .that(mUserManagerState.getUserIds()) + .containsExactly(UserId.of(mSystemUser), UserId.of(mManagedUser), + UserId.of(mPrivateUser)); + } + + @Test + public void testGetUserIds_allProfilesCurrentUserManaged_allShowInSharingSurfacesSeparate() { + if (!SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mManagedUser); + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser, mOtherUser, + mNormalUser)); + + assertWithMessage("getUserIds returns unexpected list of user ids") + .that(mUserManagerState.getUserIds()) + .containsExactly(UserId.of(mSystemUser), UserId.of(mManagedUser), + UserId.of(mPrivateUser)); + } + + @Test + public void testGetUserIds_allProfilesCurrentUserPrivate_allShowInSharingSurfacesSeparate() { + if (!SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mPrivateUser); + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser, mOtherUser)); + + assertWithMessage("getUserIds returns unexpected list of user ids") + .that(mUserManagerState.getUserIds()) + .containsExactly(UserId.of(mSystemUser), UserId.of(mManagedUser), + UserId.of(mPrivateUser)); + } + + @Test + public void testGetUserIds_systemAndManagedUserCurrentUserSystem_returnsBoth() { + UserId currentUser = UserId.of(mSystemUser); + initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mManagedUser)); + + assertWithMessage("getUserIds returns unexpected list of user ids") + .that(mUserManagerState.getUserIds()) + .containsExactly(UserId.of(mSystemUser), UserId.of(mManagedUser)); + } + + @Test + public void testGetUserIds_systemAndManagedUserCurrentUserManaged_returnsBoth() { + UserId currentUser = UserId.of(mManagedUser); + initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mManagedUser)); + + assertWithMessage("getUserIds returns unexpected list of user ids") + .that(mUserManagerState.getUserIds()) + .containsExactly(UserId.of(mSystemUser), UserId.of(mManagedUser)); + } + + @Test + public void testGetUserIds_systemAndPrivateUserCurrentUserSystem_returnsBoth() { + if (!SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mSystemUser); + initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mPrivateUser)); + + assertWithMessage("getUserIds returns unexpected list of user ids") + .that(mUserManagerState.getUserIds()) + .containsExactly(UserId.of(mSystemUser), UserId.of(mPrivateUser)); + } + + @Test + public void testGetUserIds_systemAndPrivateUserCurrentUserPrivate_returnsBoth() { + if (!SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mPrivateUser); + initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mPrivateUser)); + + assertWithMessage("getUserIds returns unexpected list of user ids") + .that(mUserManagerState.getUserIds()) + .containsExactly(UserId.of(mSystemUser), UserId.of(mPrivateUser)); + } + + @Test + public void testGetUserIds_systemAndOtherUserCurrentUserOtherPreV_returnsCurrentUser() { + if (SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mOtherUser); + initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mOtherUser)); + + assertWithMessage("getUserIds returns unexpected list of user ids") + .that(mUserManagerState.getUserIds()) + .containsExactly(currentUser); + } + + @Test + public void testGetUserIds_systemAndOtherUserCurrentUserOtherPostV_returnsSystemUser() { + if (!SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mOtherUser); + initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mOtherUser)); + + assertWithMessage("getUserIds returns unexpected list of user ids") + .that(mUserManagerState.getUserIds()) + .containsExactly(UserId.of(mSystemUser)); + } + + @Test + public void testGetUserIds_normalAndOtherUserCurrentUserNormal_returnsCurrentUser() { + // since both users do not have show in sharing surfaces separate, returns current user + UserId currentUser = UserId.of(mNormalUser); + initializeUserManagerState(currentUser, Lists.newArrayList(mOtherUser, mNormalUser)); + + assertWithMessage("getUserIds returns unexpected list of user ids") + .that(mUserManagerState.getUserIds()) + .containsExactly(UserId.of(mNormalUser)); + } + + @Test + public void testGetUserIds_systemAndManagedUserCurrentUserSystem_returnsBothInOrder() { + // Returns the both if there are system and managed users. + if (SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mSystemUser); + initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mManagedUser)); + assertWithMessage("getUserIds returns unexpected list of user ids") + .that(mUserManagerState.getUserIds()) + .containsExactly(UserId.of(mSystemUser), UserId.of(mManagedUser)).inOrder(); + } + + @Test + public void testGetUserIds_systemAndManagedUserCurrentUserManaged_returnsBothInOrder() { + // Returns the both if there are system and managed users. + if (SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mManagedUser); + initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mManagedUser)); + assertWithMessage("getUserIds returns unexpected list of user ids") + .that(mUserManagerState.getUserIds()) + .containsExactly(UserId.of(mSystemUser), UserId.of(mManagedUser)).inOrder(); + } + + @Test + public void testGetUserIds_managedAndSystemUserCurrentUserSystem_returnsBothInOrder() { + // Returns the both if there are system and managed users, regardless of input list order. + if (SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mSystemUser); + initializeUserManagerState(currentUser, Lists.newArrayList(mManagedUser, mSystemUser)); + assertWithMessage("getUserIds returns unexpected list of user ids") + .that(mUserManagerState.getUserIds()) + .containsExactly(UserId.of(mSystemUser), UserId.of(mManagedUser)).inOrder(); + } + + @Test + public void testGetUserIds_otherAndManagedUserCurrentUserOtherPreV_returnsCurrentUser() { + // When there is no system user, returns the current user. + // This is a case theoretically can happen but we don't expect. So we return the current + // user only. + if (SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mOtherUser); + initializeUserManagerState(currentUser, Lists.newArrayList(mOtherUser, mManagedUser)); + assertWithMessage("getUserIds returns unexpected list of user ids") + .that(mUserManagerState.getUserIds()).containsExactly(currentUser); + } + + @Test + public void testGetUserIds_otherAndManagedUserCurrentUserOtherPostV_returnsManagedUser() { + // Only the users with show in sharing surfaces separate are eligible to be returned + if (!SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mOtherUser); + initializeUserManagerState(currentUser, Lists.newArrayList(mOtherUser, mManagedUser)); + assertWithMessage("getUserIds returns unexpected list of user ids") + .that(mUserManagerState.getUserIds()).containsExactly(UserId.of(mManagedUser)); + } + + @Test + public void testGetUserIds_otherAndManagedUserCurrentUserManaged_returnsCurrentUser() { + // When there is no system user, returns the current user. + // This is a case theoretically can happen, but we don't expect. So we return the current + // user only. + UserId currentUser = UserId.of(mManagedUser); + initializeUserManagerState(currentUser, Lists.newArrayList(mOtherUser, mManagedUser)); + assertWithMessage("getUserIds returns unexpected list of user ids") + .that(mUserManagerState.getUserIds()).containsExactly(currentUser); + } + + @Test + public void testGetUserIds_unsupportedDeviceCurrent_returnsCurrentUser() { + // This test only tests for Android R or later. This test case always passes before R. + if (VersionUtils.isAtLeastR()) { + // When permission is denied, only returns the current user. + when(mMockContext.checkSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS)) + .thenReturn(PackageManager.PERMISSION_DENIED); + UserId currentUser = UserId.of(mSystemUser); + when(mMockUserManager.getUserProfiles()).thenReturn( + Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser, mOtherUser)); + mUserManagerState = UserManagerState.create(mMockContext); + assertWithMessage("Unsupported device should have returned only the current user") + .that(mUserManagerState.getUserIds()).containsExactly(currentUser); + } + } + + @Test + public void testGetUserIds_returnCachedList() { + // Returns all three if there are system, managed and private users. + UserId currentUser = UserId.of(mSystemUser); + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser, mOtherUser)); + assertWithMessage("getUserIds does not return cached instance") + .that(mUserManagerState.getUserIds()) + .isSameInstanceAs(mUserManagerState.getUserIds()); + } + + @Test + public void testGetCanForwardToProfileIdMap_systemUserCanForwardToAll() { + UserId currentUser = UserId.of(mSystemUser); + final List<ResolveInfo> mMockResolveInfoList = Lists.newArrayList(mMockInfo1, mMockInfo2); + if (SdkLevel.isAtLeastV()) { + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser)); + when(mMockPackageManager.queryIntentActivitiesAsUser(mMockIntent, + PackageManager.MATCH_DEFAULT_ONLY, mSystemUser)).thenReturn( + mMockResolveInfoList); + } else { + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser)); + when(mMockPackageManager.queryIntentActivities(mMockIntent, + PackageManager.MATCH_DEFAULT_ONLY)).thenReturn(mMockResolveInfoList); + } + + Map<UserId, Boolean> expectedCanForwardToProfileIdMap = new HashMap<>(); + expectedCanForwardToProfileIdMap.put(UserId.of(mSystemUser), true); + expectedCanForwardToProfileIdMap.put(UserId.of(mManagedUser), true); + if (SdkLevel.isAtLeastV()) { + expectedCanForwardToProfileIdMap.put(UserId.of(mPrivateUser), true); + } + + assertWithMessage("getCanForwardToProfileIdMap returns incorrect mappings") + .that(mUserManagerState.getCanForwardToProfileIdMap(mMockIntent)) + .isEqualTo(expectedCanForwardToProfileIdMap); + } + + @Test + public void testGetCanForwardToProfileIdMap_systemUserCanForwardToManaged() { + UserId currentUser = UserId.of(mSystemUser); + initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mManagedUser)); + final List<ResolveInfo> mMockResolveInfoList = Lists.newArrayList(mMockInfo1, mMockInfo2); + if (SdkLevel.isAtLeastV()) { + when(mMockPackageManager.queryIntentActivitiesAsUser(mMockIntent, + PackageManager.MATCH_DEFAULT_ONLY, mSystemUser)).thenReturn( + mMockResolveInfoList); + } else { + when(mMockPackageManager.queryIntentActivities(mMockIntent, + PackageManager.MATCH_DEFAULT_ONLY)).thenReturn(mMockResolveInfoList); + } + + Map<UserId, Boolean> expectedCanForwardToProfileIdMap = new HashMap<>(); + expectedCanForwardToProfileIdMap.put(UserId.of(mSystemUser), true); + expectedCanForwardToProfileIdMap.put(UserId.of(mManagedUser), true); + + assertWithMessage("getCanForwardToProfileIdMap returns incorrect mappings") + .that(mUserManagerState.getCanForwardToProfileIdMap(mMockIntent)) + .isEqualTo(expectedCanForwardToProfileIdMap); + } + + @Test + public void testGetCanForwardToProfileIdMap_systemUserCanAlwaysForwardToPrivate() { + if (!SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mSystemUser); + initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mPrivateUser)); + + Map<UserId, Boolean> expectedCanForwardToProfileIdMap = new HashMap<>(); + expectedCanForwardToProfileIdMap.put(UserId.of(mSystemUser), true); + expectedCanForwardToProfileIdMap.put(UserId.of(mPrivateUser), true); + + assertWithMessage("getCanForwardToProfileIdMap returns incorrect mappings") + .that(mUserManagerState.getCanForwardToProfileIdMap(mMockIntent)) + .isEqualTo(expectedCanForwardToProfileIdMap); + } + + @Test + public void testGetCanForwardToProfileIdMap_systemUserCanNotForwardToManagedUser() { + UserId currentUser = UserId.of(mSystemUser); + final List<ResolveInfo> mMockResolveInfoList = Lists.newArrayList(mMockInfo2, mMockInfo3); + if (SdkLevel.isAtLeastV()) { + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser)); + when(mMockPackageManager.queryIntentActivitiesAsUser(mMockIntent, + PackageManager.MATCH_DEFAULT_ONLY, mSystemUser)).thenReturn( + mMockResolveInfoList); + } else { + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser)); + when(mMockPackageManager.queryIntentActivities(mMockIntent, + PackageManager.MATCH_DEFAULT_ONLY)).thenReturn(mMockResolveInfoList); + } + + Map<UserId, Boolean> expectedCanForwardToProfileIdMap = new HashMap<>(); + expectedCanForwardToProfileIdMap.put(UserId.of(mSystemUser), true); + expectedCanForwardToProfileIdMap.put(UserId.of(mManagedUser), false); + if (SdkLevel.isAtLeastV()) { + expectedCanForwardToProfileIdMap.put(UserId.of(mPrivateUser), true); + } + + assertWithMessage("getCanForwardToProfileIdMap returns incorrect mappings") + .that(mUserManagerState.getCanForwardToProfileIdMap(mMockIntent)) + .isEqualTo(expectedCanForwardToProfileIdMap); + } + + @Test + public void testGetCanForwardToProfileIdMap_managedCanForwardToAll() { + UserId currentUser = UserId.of(mManagedUser); + final List<ResolveInfo> mMockResolveInfoList = Lists.newArrayList(mMockInfo1, mMockInfo2); + if (SdkLevel.isAtLeastV()) { + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser)); + when(mMockPackageManager.queryIntentActivitiesAsUser(mMockIntent, + PackageManager.MATCH_DEFAULT_ONLY, mManagedUser)).thenReturn( + mMockResolveInfoList); + } else { + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser)); + when(mMockPackageManager.queryIntentActivities(mMockIntent, + PackageManager.MATCH_DEFAULT_ONLY)).thenReturn(mMockResolveInfoList); + } + + Map<UserId, Boolean> expectedCanForwardToProfileIdMap = new HashMap<>(); + expectedCanForwardToProfileIdMap.put(UserId.of(mSystemUser), true); + expectedCanForwardToProfileIdMap.put(UserId.of(mManagedUser), true); + if (SdkLevel.isAtLeastV()) { + expectedCanForwardToProfileIdMap.put(UserId.of(mPrivateUser), true); + } + + assertWithMessage("getCanForwardToProfileIdMap returns incorrect mappings") + .that(mUserManagerState.getCanForwardToProfileIdMap(mMockIntent)) + .isEqualTo(expectedCanForwardToProfileIdMap); + } + + @Test + public void testGetCanForwardToProfileIdMap_managedCanNotForwardToAll() { + UserId currentUser = UserId.of(mManagedUser); + final List<ResolveInfo> mMockResolveInfoList = Lists.newArrayList(mMockInfo2, mMockInfo3); + + if (SdkLevel.isAtLeastV()) { + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser)); + when(mMockPackageManager.queryIntentActivitiesAsUser(mMockIntent, + PackageManager.MATCH_DEFAULT_ONLY, mSystemUser)).thenReturn( + mMockResolveInfoList); + } else { + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser)); + when(mMockPackageManager.queryIntentActivities(mMockIntent, + PackageManager.MATCH_DEFAULT_ONLY)).thenReturn(mMockResolveInfoList); + } + + Map<UserId, Boolean> expectedCanForwardToProfileIdMap = new HashMap<>(); + expectedCanForwardToProfileIdMap.put(UserId.of(mSystemUser), false); + expectedCanForwardToProfileIdMap.put(UserId.of(mManagedUser), true); + if (SdkLevel.isAtLeastV()) { + expectedCanForwardToProfileIdMap.put(UserId.of(mPrivateUser), false); + } + + assertWithMessage("getCanForwardToProfileIdMap returns incorrect mappings") + .that(mUserManagerState.getCanForwardToProfileIdMap(mMockIntent)) + .isEqualTo(expectedCanForwardToProfileIdMap); + } + + @Test + public void testGetCanForwardToProfileIdMap_privateCanForwardToAll() { + if (!SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mPrivateUser); + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser)); + final List<ResolveInfo> mMockResolveInfoList = Lists.newArrayList(mMockInfo1, mMockInfo2); + when(mMockPackageManager.queryIntentActivitiesAsUser(mMockIntent, + PackageManager.MATCH_DEFAULT_ONLY, mSystemUser)).thenReturn(mMockResolveInfoList); + + Map<UserId, Boolean> expectedCanForwardToProfileIdMap = new HashMap<>(); + expectedCanForwardToProfileIdMap.put(UserId.of(mSystemUser), true); + expectedCanForwardToProfileIdMap.put(UserId.of(mManagedUser), true); + expectedCanForwardToProfileIdMap.put(UserId.of(mPrivateUser), true); + + assertWithMessage("getCanForwardToProfileIdMap returns incorrect mappings") + .that(mUserManagerState.getCanForwardToProfileIdMap(mMockIntent)) + .isEqualTo(expectedCanForwardToProfileIdMap); + } + + @Test + public void testGetCanForwardToProfileIdMap_privateCanNotForwardToManagedUser() { + if (!SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mPrivateUser); + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser)); + final List<ResolveInfo> mMockResolveInfoList = Lists.newArrayList(mMockInfo2, mMockInfo3); + when(mMockPackageManager.queryIntentActivitiesAsUser(mMockIntent, + PackageManager.MATCH_DEFAULT_ONLY, mSystemUser)).thenReturn(mMockResolveInfoList); + + Map<UserId, Boolean> expectedCanForwardToProfileIdMap = new HashMap<>(); + expectedCanForwardToProfileIdMap.put(UserId.of(mSystemUser), true); + expectedCanForwardToProfileIdMap.put(UserId.of(mManagedUser), false); + expectedCanForwardToProfileIdMap.put(UserId.of(mPrivateUser), true); + + assertWithMessage("getCanForwardToProfileIdMap returns incorrect mappings") + .that(mUserManagerState.getCanForwardToProfileIdMap(mMockIntent)) + .isEqualTo(expectedCanForwardToProfileIdMap); + } + + @Test + public void testGetCanForwardToProfileIdMap_privateCanAlwaysForwardToSystemUser() { + if (!SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mPrivateUser); + initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mPrivateUser)); + + Map<UserId, Boolean> expectedCanForwardToProfileIdMap = new HashMap<>(); + expectedCanForwardToProfileIdMap.put(UserId.of(mSystemUser), true); + expectedCanForwardToProfileIdMap.put(UserId.of(mPrivateUser), true); + + assertWithMessage("getCanForwardToProfileIdMap returns incorrect mappings") + .that(mUserManagerState.getCanForwardToProfileIdMap(mMockIntent)) + .isEqualTo(expectedCanForwardToProfileIdMap); + } + + @Test + public void testOnProfileStatusChange_anyIntentActionForManagedProfile() { + if (!SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mSystemUser); + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser)); + + // UserManagerState#mUserId and UserManagerState#mCanForwardToProfileIdMap will empty + // by default if the getters of these member variables have not been called + List<UserId> userIdsBeforeIntent = new ArrayList<>(mUserManagerState.getUserIds()); + Map<UserId, Boolean> canForwardToProfileIdMapBeforeIntent = new HashMap<>( + mUserManagerState.getCanForwardToProfileIdMap(mMockIntent)); + + String action = "any_intent"; + mUserManagerState.onProfileActionStatusChange(action, UserId.of(mManagedUser)); + + assertWithMessage("Unexpected changes to user id list on receiving intent: " + action) + .that(mUserManagerState.getUserIds()).isEqualTo(userIdsBeforeIntent); + assertWithMessage( + "Unexpected changes to canForwardToProfileIdMap on receiving intent: " + action) + .that(mUserManagerState.getCanForwardToProfileIdMap(mMockIntent)).isEqualTo( + canForwardToProfileIdMapBeforeIntent); + } + + @Test + public void testOnProfileStatusChange_actionProfileUnavailableForPrivateProfile() { + if (!SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mSystemUser); + UserId managedUser = UserId.of(mManagedUser); + UserId privateUser = UserId.of(mPrivateUser); + final List<ResolveInfo> mMockResolveInfoList = Lists.newArrayList(mMockInfo1, mMockInfo2); + when(mMockPackageManager.queryIntentActivitiesAsUser(mMockIntent, + PackageManager.MATCH_DEFAULT_ONLY, mSystemUser)).thenReturn( + mMockResolveInfoList); + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser)); + + // UserManagerState#mUserId and UserManagerState#mCanForwardToProfileIdMap will empty + // by default if the getters of these member variables have not been called + List<UserId> userIdsBeforeIntent = new ArrayList<>(mUserManagerState.getUserIds()); + Map<UserId, Boolean> canForwardToProfileIdMapBeforeIntent = new HashMap<>( + mUserManagerState.getCanForwardToProfileIdMap(mMockIntent)); + + List<UserId> expectedUserIdsAfterIntent = Lists.newArrayList(currentUser, managedUser); + + String action = Intent.ACTION_PROFILE_UNAVAILABLE; + mUserManagerState.onProfileActionStatusChange(action, privateUser); + + assertWithMessage( + "UserIds list should not be same before and after receiving intent: " + action) + .that(mUserManagerState.getUserIds()).isNotEqualTo(userIdsBeforeIntent); + assertWithMessage("Unexpected changes to user id list on receiving intent: " + action) + .that(mUserManagerState.getUserIds()).isEqualTo(expectedUserIdsAfterIntent); + assertWithMessage("CanForwardToLabelMap should be same before and after receiving intent: " + + action) + .that(mUserManagerState.getCanForwardToProfileIdMap(mMockIntent)).isEqualTo( + canForwardToProfileIdMapBeforeIntent); + } + + @Test + public void testOnProfileStatusChange_actionProfileAvailable_profileInitialised() { + if (!SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mSystemUser); + UserId managedUser = UserId.of(mManagedUser); + UserId privateUser = UserId.of(mPrivateUser); + final List<ResolveInfo> mMockResolveInfoList = Lists.newArrayList(mMockInfo1, mMockInfo2); + when(mMockPackageManager.queryIntentActivitiesAsUser(mMockIntent, + PackageManager.MATCH_DEFAULT_ONLY, mSystemUser)).thenReturn( + mMockResolveInfoList); + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser)); + + // initialising the userIds list and canForwardToProfileIdMap + mUserManagerState.getUserIds(); + mUserManagerState.getCanForwardToProfileIdMap(mMockIntent); + + // Making the private profile unavailable after it has been initialised + mUserManagerState.onProfileActionStatusChange(Intent.ACTION_PROFILE_UNAVAILABLE, + privateUser); + + List<UserId> userIdsBeforeIntent = new ArrayList<>(mUserManagerState.getUserIds()); + Map<UserId, Boolean> canForwardToProfileIdMapBeforeIntent = new HashMap<>( + mUserManagerState.getCanForwardToProfileIdMap(mMockIntent)); + + List<UserId> expectedUserIdsAfterIntent = Lists.newArrayList(currentUser, managedUser, + privateUser); + + String action = Intent.ACTION_PROFILE_AVAILABLE; + mUserManagerState.onProfileActionStatusChange(action, privateUser); + + assertWithMessage( + "UserIds list should not be same before and after receiving intent: " + action) + .that(mUserManagerState.getUserIds()).isNotEqualTo(userIdsBeforeIntent); + assertWithMessage("Unexpected changes to user id list on receiving intent: " + action) + .that(mUserManagerState.getUserIds()).isEqualTo(expectedUserIdsAfterIntent); + assertWithMessage("CanForwardToLabelMap should be same before and after receiving intent: " + + action) + .that(mUserManagerState.getCanForwardToProfileIdMap(mMockIntent)).isEqualTo( + canForwardToProfileIdMapBeforeIntent); + } + + @Test + public void testOnProfileStatusChange_actionProfileAvailable_profileNotInitialised() { + if (!SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mSystemUser); + UserId managedUser = UserId.of(mManagedUser); + UserId privateUser = UserId.of(mPrivateUser); + final List<ResolveInfo> mMockResolveInfoList = Lists.newArrayList(mMockInfo1, mMockInfo2); + when(mMockPackageManager.queryIntentActivitiesAsUser(mMockIntent, + PackageManager.MATCH_DEFAULT_ONLY, mSystemUser)).thenReturn( + mMockResolveInfoList); + + // Private user will not be initialised if it is in quiet mode + when(mMockUserManager.isQuietModeEnabled(mPrivateUser)).thenReturn(true); + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser)); + + // UserManagerState#mUserId and UserManagerState#mCanForwardToProfileIdMap will be empty + // by default if the getters of these member variables have not been called + List<UserId> userIdsBeforeIntent = new ArrayList<>(mUserManagerState.getUserIds()); + Map<UserId, Boolean> canForwardToProfileIdMapBeforeIntent = new HashMap<>( + mUserManagerState.getCanForwardToProfileIdMap(mMockIntent)); + + List<UserId> expectedUserIdsAfterIntent = Lists.newArrayList(currentUser, managedUser, + privateUser); + Map<UserId, Boolean> expectedCanForwardToProfileIdMapAfterIntent = new HashMap<>(); + expectedCanForwardToProfileIdMapAfterIntent.put(currentUser, true); + expectedCanForwardToProfileIdMapAfterIntent.put(managedUser, true); + expectedCanForwardToProfileIdMapAfterIntent.put(privateUser, true); + + String action = Intent.ACTION_PROFILE_AVAILABLE; + mUserManagerState.onProfileActionStatusChange(action, privateUser); + + assertWithMessage( + "UserIds list should not be same before and after receiving intent: " + action) + .that(mUserManagerState.getUserIds()).isNotEqualTo(userIdsBeforeIntent); + assertWithMessage("Unexpected changes to user id list on receiving intent: " + action) + .that(mUserManagerState.getUserIds()).isEqualTo(expectedUserIdsAfterIntent); + assertWithMessage( + "CanForwardToLabelMap should not be same before and after receiving intent: " + + action) + .that(mUserManagerState.getCanForwardToProfileIdMap(mMockIntent)).isNotEqualTo( + canForwardToProfileIdMapBeforeIntent); + assertWithMessage( + "Unexpected changes to canForwardToProfileIdMap on receiving intent: " + action) + .that(mUserManagerState.getCanForwardToProfileIdMap(mMockIntent)).isEqualTo( + expectedCanForwardToProfileIdMapAfterIntent); + } + + @Test + public void testGetUserIdToLabelMap_systemUserAndManagedUser_PreV() { + if (SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mSystemUser); + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser)); + if (SdkLevel.isAtLeastT()) { + DevicePolicyResourcesManager devicePolicyResourcesManager = mock( + DevicePolicyResourcesManager.class); + when(mDevicePolicyManager.getResources()).thenReturn(devicePolicyResourcesManager); + when(devicePolicyResourcesManager.getString(eq(PERSONAL_TAB), any())).thenReturn( + PERSONAL); + when(devicePolicyResourcesManager.getString(eq(WORK_TAB), any())).thenReturn(WORK); + } + + Map<UserId, String> userIdToLabelMap = mUserManagerState.getUserIdToLabelMap(); + + assertWithMessage("Incorrect label returned for user id " + mSystemUser) + .that(userIdToLabelMap.get(UserId.of(mSystemUser))).isEqualTo(PERSONAL); + assertWithMessage("Incorrect label returned for user id " + mManagedUser) + .that(userIdToLabelMap.get(UserId.of(mManagedUser))).isEqualTo(WORK); + } + + @Test + public void testGetUserIdToLabelMap_systemUserManagedUserPrivateUser_PostV() { + if (!SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mSystemUser); + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser)); + if (SdkLevel.isAtLeastT()) { + DevicePolicyResourcesManager devicePolicyResourcesManager = mock( + DevicePolicyResourcesManager.class); + when(mDevicePolicyManager.getResources()).thenReturn(devicePolicyResourcesManager); + when(devicePolicyResourcesManager.getString(eq(PERSONAL_TAB), any())).thenReturn( + PERSONAL); + } + UserManager managedUserManager = getUserManagerForManagedUser(); + UserManager privateUserManager = getUserManagerForPrivateUser(); + when(managedUserManager.getProfileLabel()).thenReturn(WORK); + when(privateUserManager.getProfileLabel()).thenReturn(PRIVATE); + + Map<UserId, String> userIdToLabelMap = mUserManagerState.getUserIdToLabelMap(); + + assertWithMessage("Incorrect label returned for user id " + mSystemUser) + .that(userIdToLabelMap.get(UserId.of(mSystemUser))).isEqualTo(PERSONAL); + assertWithMessage("Incorrect label returned for user id " + mManagedUser) + .that(userIdToLabelMap.get(UserId.of(mManagedUser))).isEqualTo(WORK); + assertWithMessage("Incorrect label returned for user id " + mPrivateUser) + .that(userIdToLabelMap.get(UserId.of(mPrivateUser))).isEqualTo(PRIVATE); + } + + @Test + public void testGetUserIdToBadgeMap_systemUserManagedUser_PreV() { + if (SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mSystemUser); + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser)); + Drawable workBadge = mock(Drawable.class); + Resources resources = mock(Resources.class); + when(mMockContext.getResources()).thenReturn(resources); + when(mMockContext.getDrawable(R.drawable.ic_briefcase)).thenReturn(workBadge); + if (SdkLevel.isAtLeastT()) { + DevicePolicyResourcesManager devicePolicyResourcesManager = mock( + DevicePolicyResourcesManager.class); + when(mDevicePolicyManager.getResources()).thenReturn(devicePolicyResourcesManager); + when(devicePolicyResourcesManager.getDrawable(eq(WORK_PROFILE_ICON), eq(SOLID_COLORED), + any())).thenReturn(workBadge); + } + + Map<UserId, Drawable> userIdToBadgeMap = mUserManagerState.getUserIdToBadgeMap(); + + assertWithMessage("There should be no badge present for personal user") + .that(userIdToBadgeMap.containsKey(UserId.of(mSystemUser))).isFalse(); + assertWithMessage("Incorrect badge returned for user id " + mManagedUser) + .that(userIdToBadgeMap.get(UserId.of(mManagedUser))).isEqualTo(workBadge); + } + + @Test + public void testGetUserIdToBadgeMap_systemUserManagedUserPrivateUser_PostV() { + if (!SdkLevel.isAtLeastV()) return; + UserId currentUser = UserId.of(mSystemUser); + initializeUserManagerState(currentUser, + Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser)); + Drawable workBadge = mock(Drawable.class); + Drawable privateBadge = mock(Drawable.class); + UserManager managedUserManager = getUserManagerForManagedUser(); + UserManager privateUserManager = getUserManagerForPrivateUser(); + when(managedUserManager.getUserBadge()).thenReturn(workBadge); + when(privateUserManager.getUserBadge()).thenReturn(privateBadge); + + Map<UserId, Drawable> userIdToBadgeMap = mUserManagerState.getUserIdToBadgeMap(); + + assertWithMessage("There should be no badge present for personal user") + .that(userIdToBadgeMap.get(UserId.of(mSystemUser))).isNull(); + assertWithMessage("Incorrect badge returned for user id " + mManagedUser) + .that(userIdToBadgeMap.get(UserId.of(mManagedUser))).isEqualTo(workBadge); + assertWithMessage("Incorrect badge returned for user id " + mPrivateUser) + .that(userIdToBadgeMap.get(UserId.of(mPrivateUser))).isEqualTo(privateBadge); + } + + private void initializeUserManagerState(UserId current, List<UserHandle> usersOnDevice) { + when(mMockUserManager.getUserProfiles()).thenReturn(usersOnDevice); + TestConfigStore testConfigStore = new TestConfigStore(); + testConfigStore.enablePrivateSpaceInPhotoPicker(); + mUserManagerState = new UserManagerState.RuntimeUserManagerState(mMockContext, current, + true, testConfigStore); + } + + private UserManager getUserManagerForManagedUser() { + Context managedUserContext = mock(Context.class); + when(mMockContext.createContextAsUser(mManagedUser, 0)).thenReturn(managedUserContext); + UserManager managedUserManager = mock(UserManager.class); + when(managedUserContext.getSystemServiceName(UserManager.class)) + .thenReturn("managedUserManager"); + when(managedUserContext.getSystemService(UserManager.class)).thenReturn(managedUserManager); + return managedUserManager; + } + + private UserManager getUserManagerForPrivateUser() { + Context privateUserContext = mock(Context.class); + when(mMockContext.createContextAsUser(mPrivateUser, 0)).thenReturn(privateUserContext); + UserManager privateUserManager = mock(UserManager.class); + when(privateUserContext.getSystemServiceName(UserManager.class)) + .thenReturn("privateUserManager"); + when(privateUserContext.getSystemService(UserManager.class)).thenReturn(privateUserManager); + return privateUserManager; + } +} diff --git a/tests/unit/com/android/documentsui/base/DocumentInfoTest.java b/tests/unit/com/android/documentsui/base/DocumentInfoTest.java index eba30d2e5..4e73333d8 100644 --- a/tests/unit/com/android/documentsui/base/DocumentInfoTest.java +++ b/tests/unit/com/android/documentsui/base/DocumentInfoTest.java @@ -28,8 +28,8 @@ import android.content.Context; import android.net.Uri; import android.provider.DocumentsContract; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; +import androidx.test.filters.SmallTest; import androidx.test.rule.provider.ProviderTestRule; import com.android.documentsui.InspectorProvider; diff --git a/tests/unit/com/android/documentsui/dirlist/AccessibilityTest.java b/tests/unit/com/android/documentsui/dirlist/AccessibilityTest.java index 07a55f89b..09b193344 100644 --- a/tests/unit/com/android/documentsui/dirlist/AccessibilityTest.java +++ b/tests/unit/com/android/documentsui/dirlist/AccessibilityTest.java @@ -18,13 +18,14 @@ package com.android.documentsui.dirlist; import android.database.Cursor; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; import android.view.View; import android.widget.Space; import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; import androidx.recyclerview.widget.RecyclerView; +import androidx.test.filters.SmallTest; +import com.android.documentsui.TestConfigStore; import com.android.documentsui.testing.TestRecyclerView; import com.android.documentsui.testing.Views; @@ -61,12 +62,36 @@ public class AccessibilityTest extends AndroidTestCase { assertTrue(info.isSelected()); } - public void testNullItemDetails_NoActionClick() throws Exception { + public void testNullItemDetails_NoActionClick_PrivateSpaceEnabled() throws Exception { View item = Views.createTestView(true); AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); List<RecyclerView.ViewHolder> holders = new ArrayList<>(); - holders.add(new MessageHolder(mView.getContext(), new Space(mView.getContext())) { + TestConfigStore testConfigStore = new TestConfigStore(); + testConfigStore.enablePrivateSpaceInPhotoPicker(); + holders.add(new MessageHolder(mView.getContext(), new Space(mView.getContext()), + testConfigStore) { + @Override + public void bind(Cursor cursor, String modelId) { + + } + }); + + mView.setHolders(holders); + + mAccessibilityDelegate.getItemDelegate().onInitializeAccessibilityNodeInfo(item, info); + assertFalse(info.isClickable()); + } + + public void testNullItemDetails_NoActionClick_PrivateSpaceDisabled() throws Exception { + View item = Views.createTestView(true); + AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(); + + List<RecyclerView.ViewHolder> holders = new ArrayList<>(); + TestConfigStore testConfigStore = new TestConfigStore(); + testConfigStore.disablePrivateSpaceInPhotoPicker(); + holders.add(new MessageHolder(mView.getContext(), new Space(mView.getContext()), + testConfigStore) { @Override public void bind(Cursor cursor, String modelId) { diff --git a/tests/unit/com/android/documentsui/dirlist/AppsRowManagerTest.java b/tests/unit/com/android/documentsui/dirlist/AppsRowManagerTest.java index 6482440da..bbe2a0030 100644 --- a/tests/unit/com/android/documentsui/dirlist/AppsRowManagerTest.java +++ b/tests/unit/com/android/documentsui/dirlist/AppsRowManagerTest.java @@ -35,7 +35,9 @@ import androidx.test.InstrumentationRegistry; import com.android.documentsui.ActionHandler; import com.android.documentsui.BaseActivity; import com.android.documentsui.R; +import com.android.documentsui.TestConfigStore; import com.android.documentsui.TestUserIdManager; +import com.android.documentsui.TestUserManagerState; import com.android.documentsui.base.State; import com.android.documentsui.base.UserId; import com.android.documentsui.sidebar.AppItem; @@ -45,15 +47,21 @@ import com.android.documentsui.testing.TestActionHandler; import com.android.documentsui.testing.TestProvidersAccess; import com.android.documentsui.testing.TestResolveInfo; import com.android.documentsui.util.VersionUtils; +import com.android.modules.utils.build.SdkLevel; import com.google.common.collect.Lists; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; import java.util.ArrayList; import java.util.List; +@RunWith(Parameterized.class) public class AppsRowManagerTest { private AppsRowManager mAppsRowManager; @@ -62,17 +70,31 @@ public class AppsRowManagerTest { private boolean mMaybeShowBadge; private BaseActivity mActivity; private TestUserIdManager mTestUserIdManager; + private TestUserManagerState mTestUserManagerState; private State mState; private View mAppsRow; private LinearLayout mAppsGroup; + private final TestConfigStore mTestConfigStore = new TestConfigStore(); + + @Parameter(0) + public boolean isPrivateSpaceEnabled; + + /** + * Parametrize values for {@code isPrivateSpaceEnabled} to run all the tests twice once with + * private space flag enabled and once with it disabled. + */ + @Parameters(name = "privateSpaceEnabled={0}") + public static Iterable<?> data() { + return com.google.android.collect.Lists.newArrayList(true, false); + } @Before public void setUp() { mActionHandler = new TestActionHandler(); mTestUserIdManager = new TestUserIdManager(); - mAppsRowManager = new AppsRowManager(mActionHandler, mMaybeShowBadge, mTestUserIdManager); + mAppsRowManager = getAppsRowManager(); Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); LayoutInflater layoutInflater = LayoutInflater.from(context); @@ -81,18 +103,39 @@ public class AppsRowManagerTest { mAppsRow = layoutInflater.inflate(R.layout.apps_row, null); mAppsGroup = mAppsRow.findViewById(R.id.apps_row); + mState.configStore = mTestConfigStore; + when(mActivity.getLayoutInflater()).thenReturn(layoutInflater); when(mActivity.getDisplayState()).thenReturn(mState); when(mActivity.findViewById(R.id.apps_row)).thenReturn(mAppsRow); when(mActivity.findViewById(R.id.apps_group)).thenReturn(mAppsGroup); when(mActivity.getSelectedUser()).thenReturn(TestProvidersAccess.USER_ID); + isPrivateSpaceEnabled &= SdkLevel.isAtLeastS(); + if (isPrivateSpaceEnabled) { + mTestConfigStore.enablePrivateSpaceInPhotoPicker(); + } + } + + private AppsRowManager getAppsRowManager() { + if (isPrivateSpaceEnabled && SdkLevel.isAtLeastS()) { + mTestUserManagerState = new TestUserManagerState(); + mTestUserManagerState.userIds = + Lists.newArrayList(UserId.DEFAULT_USER, TestProvidersAccess.OtherUser.USER_ID, + TestProvidersAccess.AnotherUser.USER_ID); + return new AppsRowManager(mActionHandler, mMaybeShowBadge, mTestUserManagerState, + mTestConfigStore); + } + mTestUserIdManager = new TestUserIdManager(); mTestUserIdManager.userIds = Lists.newArrayList(UserId.DEFAULT_USER, TestProvidersAccess.OtherUser.USER_ID); + return new AppsRowManager(mActionHandler, mMaybeShowBadge, mTestUserIdManager, + mTestConfigStore); } @Test public void testUpdateList_byRootItem() { + mActivity.setConfigStore(mTestConfigStore); final List<Item> rootList = new ArrayList<>(); rootList.add(new RootItem(TestProvidersAccess.INSPECTOR, mActionHandler, mMaybeShowBadge)); rootList.add(new RootItem(TestProvidersAccess.PICKLES, mActionHandler, mMaybeShowBadge)); @@ -105,15 +148,16 @@ public class AppsRowManagerTest { assertEquals(chipDataList.size(), rootList.size()); assertEquals(TestProvidersAccess.INSPECTOR.title, chipDataList.get(0).getTitle()); - assertEquals(null, chipDataList.get(0).getSummary()); + assertNull(chipDataList.get(0).getSummary()); assertEquals(TestProvidersAccess.PICKLES.title, chipDataList.get(1).getTitle()); - assertEquals(null, chipDataList.get(1).getSummary()); + assertNull(chipDataList.get(1).getSummary()); assertEquals(TestProvidersAccess.PICKLES.summary, chipDataList.get(2).getSummary()); assertEquals(TestProvidersAccess.PICKLES.summary, chipDataList.get(3).getSummary()); } @Test public void testUpdateList_byHybridItem() { + mActivity.setConfigStore(mTestConfigStore); final String testPackageName = "com.test1"; final ResolveInfo info = TestResolveInfo.create(); info.activityInfo.packageName = testPackageName; @@ -136,6 +180,7 @@ public class AppsRowManagerTest { @Test public void testUpdateView_matchedState_showRow() { + mActivity.setConfigStore(mTestConfigStore); mState.action = State.ACTION_BROWSE; mState.stack.changeRoot(TestProvidersAccess.RECENTS); final List<Item> rootList = new ArrayList<>(); @@ -150,6 +195,7 @@ public class AppsRowManagerTest { @Test public void testUpdateView_showSelectedUserItems() { + mActivity.setConfigStore(mTestConfigStore); mState.action = State.ACTION_GET_CONTENT; mState.stack.changeRoot(TestProvidersAccess.RECENTS); final List<Item> rootList = new ArrayList<>(); @@ -173,6 +219,7 @@ public class AppsRowManagerTest { if (!VersionUtils.isAtLeastR()) { return; } + mActivity.setConfigStore(mTestConfigStore); mState.action = State.ACTION_GET_CONTENT; when(mActivity.getSelectedUser()).thenReturn(TestProvidersAccess.OtherUser.USER_ID); mState.stack.changeRoot(TestProvidersAccess.RECENTS); @@ -194,6 +241,7 @@ public class AppsRowManagerTest { @Test public void testUpdateView_notInRecent_hideRow() { + mActivity.setConfigStore(mTestConfigStore); mState.action = State.ACTION_BROWSE; final List<Item> rootList = new ArrayList<>(); rootList.add(new RootItem(TestProvidersAccess.INSPECTOR, mActionHandler, mMaybeShowBadge)); @@ -208,6 +256,7 @@ public class AppsRowManagerTest { @Test public void testUpdateView_notHandledAction_hideRow() { + mActivity.setConfigStore(mTestConfigStore); mState.action = State.ACTION_OPEN_TREE; mState.stack.changeRoot(TestProvidersAccess.RECENTS); @@ -222,6 +271,7 @@ public class AppsRowManagerTest { @Test public void testUpdateView_noItems_hideRow() { + mActivity.setConfigStore(mTestConfigStore); mState.action = State.ACTION_BROWSE; mState.stack.changeRoot(TestProvidersAccess.RECENTS); @@ -235,6 +285,7 @@ public class AppsRowManagerTest { @Test public void testUpdateView_crossProfileSearch_hideRow() { + mActivity.setConfigStore(mTestConfigStore); mState.supportsCrossProfile = true; when(mActivity.isSearchExpanded()).thenReturn(true); @@ -256,6 +307,7 @@ public class AppsRowManagerTest { @Test public void testUpdateView_notCrossProfileSearch_showRow() { + mActivity.setConfigStore(mTestConfigStore); mState.supportsCrossProfile = true; when(mActivity.isSearchExpanded()).thenReturn(false); @@ -277,6 +329,7 @@ public class AppsRowManagerTest { @Test public void testUpdateView_noItemsOnSelectedUser_hideRow() { + mActivity.setConfigStore(mTestConfigStore); mState.supportsCrossProfile = true; mState.stack.changeRoot(TestProvidersAccess.RECENTS); when(mActivity.getSelectedUser()).thenReturn(TestProvidersAccess.OtherUser.USER_ID); diff --git a/tests/unit/com/android/documentsui/dirlist/DocumentHolderTest.java b/tests/unit/com/android/documentsui/dirlist/DocumentHolderTest.java index 2574f73bd..bd76f5745 100644 --- a/tests/unit/com/android/documentsui/dirlist/DocumentHolderTest.java +++ b/tests/unit/com/android/documentsui/dirlist/DocumentHolderTest.java @@ -27,24 +27,26 @@ import android.view.MotionEvent; import android.view.MotionEvent.PointerCoords; import android.view.MotionEvent.PointerProperties; -import androidx.test.filters.SmallTest; import androidx.test.filters.Suppress; import com.android.documentsui.R; +import com.android.documentsui.TestConfigStore; -@SmallTest public class DocumentHolderTest extends AndroidTestCase { DocumentHolder mHolder; TestListener mListener; + TestConfigStore mTestConfigStore = new TestConfigStore(); @Override public void setUp() throws Exception { Context context = getContext(); LayoutInflater inflater = LayoutInflater.from(context); - mHolder = new DocumentHolder(getContext(), inflater.inflate(R.layout.item_doc_list, null)) { + mHolder = new DocumentHolder(getContext(), inflater.inflate(R.layout.item_doc_list, null), + mTestConfigStore) { @Override - public void bind(Cursor cursor, String modelId) {} + public void bind(Cursor cursor, String modelId) { + } }; mListener = new TestListener(); @@ -67,12 +69,12 @@ public class DocumentHolderTest extends AndroidTestCase { public MotionEvent createEvent(int tooltype) { long time = SystemClock.uptimeMillis(); - PointerProperties properties[] = new PointerProperties[] { + PointerProperties[] properties = new PointerProperties[]{ new PointerProperties() }; properties[0].toolType = tooltype; - PointerCoords coords[] = new PointerCoords[] { + PointerCoords[] coords = new PointerCoords[]{ new PointerCoords() }; @@ -96,7 +98,7 @@ public class DocumentHolderTest extends AndroidTestCase { 0, // edgeflags 0, // source 0 // flags - ); + ); } private class TestListener extends KeyboardEventListener<DocumentItemDetails> { diff --git a/tests/unit/com/android/documentsui/dirlist/IconHelperTest.java b/tests/unit/com/android/documentsui/dirlist/IconHelperTest.java index d2419e8cf..6a6dd3d9b 100644 --- a/tests/unit/com/android/documentsui/dirlist/IconHelperTest.java +++ b/tests/unit/com/android/documentsui/dirlist/IconHelperTest.java @@ -24,51 +24,124 @@ import android.os.UserHandle; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.documentsui.TestConfigStore; +import com.android.documentsui.TestUserManagerState; import com.android.documentsui.ThumbnailCache; import com.android.documentsui.base.State; import com.android.documentsui.base.UserId; +import com.android.modules.utils.build.SdkLevel; + +import com.google.common.collect.Lists; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; @SmallTest +@RunWith(Parameterized.class) public final class IconHelperTest { - + private final UserId mSystemUser = UserId.of(UserHandle.SYSTEM); + private final UserId mManagedUser = UserId.of(100); + private final UserId mPrivateUser = UserId.of(101); private Context mContext; private IconHelper mIconHelper; private ThumbnailCache mThumbnailCache = new ThumbnailCache(1000); + private TestUserManagerState mTestUserManagerState; + private final TestConfigStore mTestConfigStore = new TestConfigStore(); + + @Parameter(0) + public boolean isPrivateSpaceEnabled; - private UserId systemUser = UserId.of(UserHandle.SYSTEM); - private UserId managedUser = UserId.of(100); + /** + * Parametrize values for {@code isPrivateSpaceEnabled} to run all the tests twice once with + * private space flag enabled and once with it disabled. + */ + @Parameters(name = "privateSpaceEnabled={0}") + public static Iterable<?> data() { + return Lists.newArrayList(true, false); + } @Before public void setUp() { mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); - mIconHelper = new IconHelper(mContext, State.MODE_LIST, /* maybeShowBadge= */ true, - mThumbnailCache, managedUser); + + isPrivateSpaceEnabled = SdkLevel.isAtLeastS() && isPrivateSpaceEnabled; + if (SdkLevel.isAtLeastS()) { + mTestUserManagerState = new TestUserManagerState(); + mTestUserManagerState.userIds = SdkLevel.isAtLeastV() + ? Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser) + : Lists.newArrayList(mSystemUser, mManagedUser); + } + mIconHelper = isPrivateSpaceEnabled + ? new IconHelper(mContext, State.MODE_LIST, /* maybeShowBadge= */ true, + mThumbnailCache, null, mTestUserManagerState, mTestConfigStore) + : new IconHelper(mContext, State.MODE_LIST, /* maybeShowBadge= */ true, + mThumbnailCache, mManagedUser, null, mTestConfigStore); + if (isPrivateSpaceEnabled) { + mTestConfigStore.enablePrivateSpaceInPhotoPicker(); + } } @Test public void testShouldShowBadge_returnFalse_onSystemUser() { - assertThat(mIconHelper.shouldShowBadge(systemUser.getIdentifier())).isFalse(); + assertThat(mIconHelper.shouldShowBadge(mSystemUser.getIdentifier())).isFalse(); } @Test public void testShouldShowBadge_returnTrue_onManagedUser() { - assertThat(mIconHelper.shouldShowBadge(managedUser.getIdentifier())).isTrue(); + assertThat(mIconHelper.shouldShowBadge(mManagedUser.getIdentifier())).isTrue(); + } + + @Test + public void testShouldShowBadge_returnTrue_onPrivateUser() { + if (!SdkLevel.isAtLeastV() || !isPrivateSpaceEnabled) return; + assertThat(mIconHelper.shouldShowBadge(mPrivateUser.getIdentifier())).isTrue(); } @Test public void testShouldShowBadge_returnFalse_onManagedUser_doNotShowBadge() { + if (isPrivateSpaceEnabled) return; mIconHelper = new IconHelper(mContext, State.MODE_LIST, /* maybeShowBadge= */ false, - mThumbnailCache, managedUser); - assertThat(mIconHelper.shouldShowBadge(managedUser.getIdentifier())).isFalse(); + mThumbnailCache, mManagedUser, null, mTestConfigStore); + assertThat(mIconHelper.shouldShowBadge(mManagedUser.getIdentifier())).isFalse(); + } + + @Test + public void testShouldShowBadge_returnFalseOnPrivateUser_doNotShowBadge() { + if (!isPrivateSpaceEnabled) return; + mIconHelper = new IconHelper(mContext, State.MODE_LIST, /* maybeShowBadge= */ false, + mThumbnailCache, null, mTestUserManagerState, mTestConfigStore); + assertThat(mIconHelper.shouldShowBadge(mPrivateUser.getIdentifier())).isFalse(); + } + + @Test + public void testShouldShowBadge_returnFalseOnManagedUser_withoutManagedUser() { + if (isPrivateSpaceEnabled) return; + mIconHelper = new IconHelper(mContext, State.MODE_LIST, /* maybeShowBadge= */ true, + mThumbnailCache, /* mManagedUser= */ null, null, mTestConfigStore); + assertThat(mIconHelper.shouldShowBadge(mManagedUser.getIdentifier())).isFalse(); + } + + @Test + public void testShouldShowBadge_returnFalseOnManagedUser_withoutMultipleUsers() { + if (!isPrivateSpaceEnabled) return; + if (SdkLevel.isAtLeastS()) { + mTestUserManagerState.userIds = Lists.newArrayList(mManagedUser); + } + mIconHelper = new IconHelper(mContext, State.MODE_LIST, /* maybeShowBadge= */ true, + mThumbnailCache, /* mManagedUser= */ null, mTestUserManagerState, mTestConfigStore); + assertThat(mIconHelper.shouldShowBadge(mManagedUser.getIdentifier())).isFalse(); } @Test - public void testShouldShowBadge_returnFalse_onManagedUser_withoutManagedUser() { + public void testShouldShowBadge_returnFalseOnPrivateUser_withoutMultipleUsers() { + if (!SdkLevel.isAtLeastV() || !isPrivateSpaceEnabled) return; + mTestUserManagerState.userIds = Lists.newArrayList(mPrivateUser); mIconHelper = new IconHelper(mContext, State.MODE_LIST, /* maybeShowBadge= */ true, - mThumbnailCache, /* managedUser= */ null); - assertThat(mIconHelper.shouldShowBadge(managedUser.getIdentifier())).isFalse(); + mThumbnailCache, /* mManagedUser= */ null, mTestUserManagerState, mTestConfigStore); + assertThat(mIconHelper.shouldShowBadge(mPrivateUser.getIdentifier())).isFalse(); } } diff --git a/tests/unit/com/android/documentsui/dirlist/InflateMessageDocumentHolderTest.java b/tests/unit/com/android/documentsui/dirlist/InflateMessageDocumentHolderTest.java index 436e4fbca..507e9bf4a 100644 --- a/tests/unit/com/android/documentsui/dirlist/InflateMessageDocumentHolderTest.java +++ b/tests/unit/com/android/documentsui/dirlist/InflateMessageDocumentHolderTest.java @@ -18,7 +18,11 @@ package com.android.documentsui.dirlist; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.when; + import android.content.Context; +import android.content.pm.UserProperties; +import android.os.UserManager; import android.view.View; import android.widget.Button; @@ -28,15 +32,29 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.documentsui.CrossProfileQuietModeException; import com.android.documentsui.Model; import com.android.documentsui.R; +import com.android.documentsui.TestConfigStore; import com.android.documentsui.base.State; +import com.android.documentsui.base.UserId; import com.android.documentsui.testing.TestActionHandler; import com.android.documentsui.testing.TestEnv; import com.android.documentsui.testing.TestProvidersAccess; +import com.android.documentsui.testing.UserManagers; +import com.android.modules.utils.build.SdkLevel; + +import com.google.common.collect.Lists; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +import java.util.HashMap; +import java.util.Map; @SmallTest +@RunWith(Parameterized.class) public final class InflateMessageDocumentHolderTest { private Context mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); @@ -45,23 +63,70 @@ public final class InflateMessageDocumentHolderTest { private Message mInflateMessage; private TestActionHandler mTestActionHandler = new TestActionHandler(); private InflateMessageDocumentHolder mHolder; + private TestConfigStore mTestConfigStore = new TestConfigStore(); + + @Parameter(0) + public boolean isPrivateSpaceEnabled; + + /** + * Parametrize values for {@code isPrivateSpaceEnabled} to run all the tests twice once with + * private space flag enabled and once with it disabled. + */ + @Parameters(name = "privateSpaceEnabled={0}") + public static Iterable<?> data() { + return Lists.newArrayList(true, false); + } @Before public void setUp() { DocumentsAdapter.Environment env = new TestEnvironment(mContext, TestEnv.create(), mTestActionHandler); env.getDisplayState().action = State.ACTION_GET_CONTENT; - env.getDisplayState().canShareAcrossProfile = true; env.getDisplayState().supportsCrossProfile = true; - mInflateMessage = new Message.InflateMessage(env, mDefaultCallback); + mContext.setTheme(R.style.DocumentsTheme); mContext.getTheme().applyStyle(R.style.DocumentsDefaultTheme, /* force= */false); - mHolder = new InflateMessageDocumentHolder(mContext, /* parent= */null); + isPrivateSpaceEnabled = SdkLevel.isAtLeastS() && isPrivateSpaceEnabled; + if (isPrivateSpaceEnabled) { + mTestConfigStore.enablePrivateSpaceInPhotoPicker(); + Map<UserId, String> userIdToLabelMap = new HashMap<>(); + userIdToLabelMap.put(TestProvidersAccess.USER_ID, "Personal"); + userIdToLabelMap.put(TestProvidersAccess.OtherUser.USER_ID, "Work"); + env.getDisplayState().canForwardToProfileIdMap.put(TestProvidersAccess.USER_ID, true); + env.getDisplayState().canForwardToProfileIdMap.put( + TestProvidersAccess.OtherUser.USER_ID, true); + UserManager userManager = UserManagers.create(); + if (SdkLevel.isAtLeastV()) { + userIdToLabelMap.put(TestProvidersAccess.AnotherUser.USER_ID, "Private"); + env.getDisplayState().canForwardToProfileIdMap.put( + TestProvidersAccess.AnotherUser.USER_ID, true); + UserProperties otherUserProperties = new UserProperties.Builder() + .setShowInQuietMode(UserProperties.SHOW_IN_QUIET_MODE_PAUSED) + .build(); + UserProperties anotherUserProperties = new UserProperties.Builder() + .setShowInQuietMode(UserProperties.SHOW_IN_QUIET_MODE_PAUSED) + .build(); + when(userManager.getUserProperties(TestProvidersAccess.OtherUser.USER_HANDLE)) + .thenReturn(otherUserProperties); + when(userManager.getUserProperties(TestProvidersAccess.AnotherUser.USER_HANDLE)) + .thenReturn(anotherUserProperties); + } + + mInflateMessage = new Message.InflateMessage(env, mDefaultCallback, + TestProvidersAccess.USER_ID, + TestProvidersAccess.OtherUser.USER_ID, userIdToLabelMap, userManager, + mTestConfigStore); + } else { + mInflateMessage = new Message.InflateMessage(env, mDefaultCallback, mTestConfigStore); + env.getDisplayState().canShareAcrossProfile = true; + } + mHolder = new InflateMessageDocumentHolder(mContext, /* parent= */null, mTestConfigStore); } @Test public void testClickingButtonShouldShowProgressBar() { + if (SdkLevel.isAtLeastV()) return; Model.Update error = new Model.Update( new CrossProfileQuietModeException(TestProvidersAccess.OtherUser.USER_ID), /* remoteActionsEnabled= */ true); diff --git a/tests/unit/com/android/documentsui/dirlist/MessageTest.java b/tests/unit/com/android/documentsui/dirlist/MessageTest.java index 0816684d7..17ca61eeb 100644 --- a/tests/unit/com/android/documentsui/dirlist/MessageTest.java +++ b/tests/unit/com/android/documentsui/dirlist/MessageTest.java @@ -16,12 +16,15 @@ package com.android.documentsui.dirlist; +import static com.android.documentsui.DevicePolicyResources.Drawables.Style.OUTLINE; +import static com.android.documentsui.DevicePolicyResources.Drawables.WORK_PROFILE_OFF_ICON; import static com.android.documentsui.DevicePolicyResources.Strings.CANT_SELECT_WORK_FILES_MESSAGE; import static com.android.documentsui.DevicePolicyResources.Strings.CANT_SELECT_WORK_FILES_TITLE; import static com.android.documentsui.DevicePolicyResources.Strings.WORK_PROFILE_OFF_ENABLE_BUTTON; import static com.android.documentsui.DevicePolicyResources.Strings.WORK_PROFILE_OFF_ERROR_TITLE; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.TruthJUnit.assume; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -31,7 +34,11 @@ import static org.mockito.Mockito.when; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyResourcesManager; import android.content.Context; +import android.content.pm.UserProperties; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; import android.os.UserManager; +import android.util.Log; import androidx.core.util.Preconditions; import androidx.test.filters.SmallTest; @@ -41,17 +48,30 @@ import com.android.documentsui.CrossProfileNoPermissionException; import com.android.documentsui.CrossProfileQuietModeException; import com.android.documentsui.Model; import com.android.documentsui.R; +import com.android.documentsui.TestConfigStore; import com.android.documentsui.base.State; import com.android.documentsui.base.UserId; import com.android.documentsui.testing.TestActionHandler; import com.android.documentsui.testing.TestEnv; +import com.android.documentsui.testing.TestProvidersAccess; import com.android.documentsui.testing.UserManagers; import com.android.modules.utils.build.SdkLevel; +import com.google.common.collect.Lists; + import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; @SmallTest +@RunWith(Parameterized.class) public final class MessageTest { private UserId mUserId = UserId.of(100); @@ -62,6 +82,19 @@ public final class MessageTest { private UserManager mUserManager; private DevicePolicyManager mDevicePolicyManager; private TestActionHandler mTestActionHandler; + private final TestConfigStore mTestConfigStore = new TestConfigStore(); + + @Parameter(0) + public boolean isPrivateSpaceEnabled; + + /** + * Parametrize values for {@code isPrivateSpaceEnabled} to run all the tests twice once with + * private space flag enabled and once with it disabled. + */ + @Parameters(name = "privateSpaceEnabled={0}") + public static Iterable<?> data() { + return Lists.newArrayList(true, false); + } @Before public void setUp() { @@ -69,7 +102,8 @@ public final class MessageTest { mUserManager = UserManagers.create(); mTestActionHandler = new TestActionHandler(); mDevicePolicyManager = mock(DevicePolicyManager.class); - when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); + when(mContext.getSystemServiceName(UserManager.class)).thenReturn("mUserManager"); + when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager); when(mContext.getSystemServiceName(DevicePolicyManager.class)) .thenReturn(Context.DEVICE_POLICY_SERVICE); when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)) @@ -79,12 +113,34 @@ public final class MessageTest { DocumentsAdapter.Environment env = new TestEnvironment(mContext, TestEnv.create(), mTestActionHandler); env.getDisplayState().action = State.ACTION_GET_CONTENT; - mInflateMessage = new Message.InflateMessage(env, mDefaultCallback); + + isPrivateSpaceEnabled = SdkLevel.isAtLeastS() && isPrivateSpaceEnabled; + if (SdkLevel.isAtLeastV()) { + UserProperties userProperties = new UserProperties.Builder() + .setShowInQuietMode(UserProperties.SHOW_IN_QUIET_MODE_PAUSED) + .build(); + UserHandle userHandle = UserHandle.of(mUserId.getIdentifier()); + when(mUserManager.getUserProperties(userHandle)).thenReturn(userProperties); + } + if (isPrivateSpaceEnabled) { + mTestConfigStore.enablePrivateSpaceInPhotoPicker(); + String personalLabel = mContext.getString(R.string.personal_tab); + String workLabel = mContext.getString(R.string.work_tab); + Map<UserId, String> userIdToLabelMap = new HashMap<>(); + userIdToLabelMap.put(TestProvidersAccess.USER_ID, personalLabel); + userIdToLabelMap.put(mUserId, workLabel); + mInflateMessage = new Message.InflateMessage(env, mDefaultCallback, + TestProvidersAccess.USER_ID, mUserId, userIdToLabelMap, mUserManager, + mTestConfigStore); + } else { + mInflateMessage = new Message.InflateMessage(env, mDefaultCallback, mTestConfigStore); + } } @Test public void testInflateMessage_updateToCrossProfileNoPermission() { // Make sure this test is running on system user. + assume().that(UserId.CURRENT_USER.isSystem()).isTrue(); Preconditions.checkArgument(UserId.CURRENT_USER.isSystem()); Model.Update error = new Model.Update( new CrossProfileNoPermissionException(), @@ -105,16 +161,32 @@ public final class MessageTest { assertThat(mInflateMessage.getLayout()) .isEqualTo(InflateMessageDocumentHolder.LAYOUT_CROSS_PROFILE_ERROR); - assertThat(mInflateMessage.getTitleString()) - .isEqualTo(mContext.getString(R.string.cant_select_work_files_error_title)); - assertThat(mInflateMessage.getMessageString()) - .isEqualTo(mContext.getString(R.string.cant_select_work_files_error_message)); + Log.d("DocsUiAdi", "title string in test = " + mInflateMessage.getTitleString()); + if (isPrivateSpaceEnabled) { + String workLabel = mContext.getString(R.string.work_tab); + String personalLabel = mContext.getString(R.string.personal_tab); + assertThat(mInflateMessage.getTitleString()) + .isEqualTo( + mContext.getString(R.string.cant_select_cross_profile_files_error_title, + workLabel.toLowerCase(Locale.getDefault()))); + assertThat(mInflateMessage.getMessageString()) + .isEqualTo(mContext.getString( + R.string.cant_select_cross_profile_files_error_message, + workLabel.toLowerCase(Locale.getDefault()), + personalLabel.toLowerCase(Locale.getDefault()))); + } else { + assertThat(mInflateMessage.getTitleString()) + .isEqualTo(mContext.getString(R.string.cant_select_work_files_error_title)); + assertThat(mInflateMessage.getMessageString()) + .isEqualTo(mContext.getString(R.string.cant_select_work_files_error_message)); + } // No button for this error assertThat(mInflateMessage.getButtonString()).isNull(); } @Test public void testInflateMessage_updateToCrossProfileQuietMode() { + if (SdkLevel.isAtLeastV()) return; Model.Update error = new Model.Update( new CrossProfileQuietModeException(mUserId), /* isRemoteActionsEnabled= */ true); @@ -143,4 +215,47 @@ public final class MessageTest { assertThat(mTestActionHandler.mRequestDisablingQuietModeHappened).isTrue(); } + + @Test + public void testInflateMessage_updateToCrossProfileQuietMode_PostV() { + if (!SdkLevel.isAtLeastV()) return; + Model.Update error = new Model.Update( + new CrossProfileQuietModeException(mUserId), + /* isRemoteActionsEnabled= */ true); + + DevicePolicyResourcesManager devicePolicyResourcesManager = mock( + DevicePolicyResourcesManager.class); + when(mDevicePolicyManager.getResources()).thenReturn(devicePolicyResourcesManager); + + if (isPrivateSpaceEnabled) { + Drawable icon = mContext.getDrawable(R.drawable.work_off); + when(devicePolicyResourcesManager.getDrawable(eq(WORK_PROFILE_OFF_ICON), eq(OUTLINE), + any())) + .thenReturn(icon); + } else { + String title = mContext.getString(R.string.quiet_mode_error_title); + String text = mContext.getString(R.string.quiet_mode_button); + when(devicePolicyResourcesManager.getString(eq(WORK_PROFILE_OFF_ERROR_TITLE), any())) + .thenReturn(title); + when(devicePolicyResourcesManager.getString(eq(WORK_PROFILE_OFF_ENABLE_BUTTON), any())) + .thenReturn(text); + } + mInflateMessage.update(error); + + assertThat(mInflateMessage.getLayout()) + .isEqualTo(InflateMessageDocumentHolder.LAYOUT_CROSS_PROFILE_ERROR); + + if (!isPrivateSpaceEnabled) { + assert mInflateMessage.getTitleString() != null; + assertThat(mInflateMessage.getTitleString()) + .isEqualTo(mContext.getString(R.string.quiet_mode_error_title)); + assert mInflateMessage.getButtonString() != null; + assertThat(mInflateMessage.getButtonString().toString()).isEqualTo( + mContext.getString(R.string.quiet_mode_button)); + } + assertThat(mInflateMessage.mCallback).isNotNull(); + mInflateMessage.mCallback.run(); + + assertThat(mTestActionHandler.mRequestDisablingQuietModeHappened).isTrue(); + } } diff --git a/tests/unit/com/android/documentsui/files/ActionHandlerTest.java b/tests/unit/com/android/documentsui/files/ActionHandlerTest.java index 62fea24f0..2554ea52b 100644 --- a/tests/unit/com/android/documentsui/files/ActionHandlerTest.java +++ b/tests/unit/com/android/documentsui/files/ActionHandlerTest.java @@ -39,6 +39,10 @@ import android.content.ClipData; import android.content.Intent; import android.net.Uri; import android.os.Parcelable; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Path; import android.util.Pair; @@ -47,18 +51,19 @@ import android.view.DragEvent; import androidx.core.util.Preconditions; import androidx.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; import com.android.documentsui.AbstractActionHandler; import com.android.documentsui.ModelId; import com.android.documentsui.R; import com.android.documentsui.TestActionModeAddons; +import com.android.documentsui.TestConfigStore; import com.android.documentsui.archives.ArchivesProvider; import com.android.documentsui.base.DebugFlags; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.RootInfo; import com.android.documentsui.base.Shared; +import com.android.documentsui.flags.Flags; import com.android.documentsui.inspector.InspectorActivity; import com.android.documentsui.testing.ClipDatas; import com.android.documentsui.testing.DocumentStackAsserts; @@ -72,16 +77,24 @@ import com.android.documentsui.testing.TestProvidersAccess; import com.android.documentsui.testing.UserManagers; import com.android.documentsui.ui.TestDialogController; import com.android.documentsui.util.VersionUtils; +import com.android.modules.utils.build.SdkLevel; + +import com.google.common.collect.Lists; import org.junit.Before; +import org.junit.Ignore; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) @MediumTest public class ActionHandlerTest { @@ -93,8 +106,24 @@ public class ActionHandlerTest { private TestDocumentClipper mClipper; private TestDragAndDropManager mDragAndDropManager; private TestFeatures mFeatures; + private TestConfigStore mTestConfigStore; private boolean refreshAnswer = false; + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + + @Parameter(0) + public boolean isPrivateSpaceEnabled; + + /** + * Parametrize values for {@code isPrivateSpaceEnabled} to run all the tests twice once with + * private space flag enabled and once with it disabled. + */ + @Parameters(name = "privateSpaceEnabled={0}") + public static Iterable<?> data() { + return Lists.newArrayList(true, false); + } + @Before public void setUp() { mFeatures = new TestFeatures(); @@ -105,6 +134,14 @@ public class ActionHandlerTest { mDialogs = new TestDialogController(); mClipper = new TestDocumentClipper(); mDragAndDropManager = new TestDragAndDropManager(); + mTestConfigStore = new TestConfigStore(); + mEnv.state.configStore = mTestConfigStore; + + isPrivateSpaceEnabled &= SdkLevel.isAtLeastS(); + if (isPrivateSpaceEnabled) { + mTestConfigStore.enablePrivateSpaceInPhotoPicker(); + mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.USER_ID, true); + } mEnv.providers.configurePm(mActivity.packageMgr); ((TestActivityConfig) mEnv.injector.config).nextDocumentEnabled = true; @@ -129,6 +166,33 @@ public class ActionHandlerTest { } @Test + @RequiresFlagsDisabled({Flags.FLAG_DESKTOP_FILE_HANDLING}) + public void testOpenFileFlags() { + mHandler.onDocumentOpened(TestEnv.FILE_GIF, + com.android.documentsui.files.ActionHandler.VIEW_TYPE_PREVIEW, + com.android.documentsui.files.ActionHandler.VIEW_TYPE_REGULAR, false); + + int expectedFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_ACTIVITY_SINGLE_TOP + | Intent.FLAG_GRANT_WRITE_URI_PERMISSION; + Intent actual = mActivity.startActivity.getLastValue(); + assertEquals(expectedFlags, actual.getFlags()); + } + + @Test + @RequiresFlagsEnabled({Flags.FLAG_DESKTOP_FILE_HANDLING}) + public void testOpenFileFlagsDesktop() { + mHandler.onDocumentOpened(TestEnv.FILE_GIF, + com.android.documentsui.files.ActionHandler.VIEW_TYPE_PREVIEW, + com.android.documentsui.files.ActionHandler.VIEW_TYPE_REGULAR, false); + + int expectedFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_ACTIVITY_SINGLE_TOP + | Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_ACTIVITY_NEW_DOCUMENT + | Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_TASK; + Intent actual = mActivity.startActivity.getLastValue(); + assertEquals(expectedFlags, actual.getFlags()); + } + + @Test public void testSpringOpenDirectory() { mHandler.springOpenDirectory(TestEnv.FOLDER_0); assertTrue(mActionModeAddons.finishActionModeCalled); @@ -396,7 +460,26 @@ public class ActionHandlerTest { assertEquals(false, result); } + // Require desktop file handling flag because when it's disabled proguard strips the + // openDocumentViewOnly function because it's not used anywhere reachable by production code. + @Test + @RequiresFlagsEnabled({Flags.FLAG_DESKTOP_FILE_HANDLING}) + public void testDocumentContextMenuOpen() throws Exception { + mActivity.resources.setQuickViewerPackage("corptropolis.viewer"); + mActivity.currentRoot = TestProvidersAccess.HOME; + + // Test normal picking (i.e. double click) behaviour will quick view + mHandler.openDocument(TestEnv.FILE_GIF, ActionHandler.VIEW_TYPE_PREVIEW, + ActionHandler.VIEW_TYPE_REGULAR); + mActivity.assertActivityStarted(Intent.ACTION_QUICK_VIEW); + + // And verify open via context menu will view instead + mHandler.openDocumentViewOnly(TestEnv.FILE_GIF); + mActivity.assertActivityStarted(Intent.ACTION_VIEW); + } + @Test + @RequiresFlagsDisabled({Flags.FLAG_DESKTOP_FILE_HANDLING}) public void testShowChooser() throws Exception { mActivity.currentRoot = TestProvidersAccess.DOWNLOADS; @@ -405,6 +488,18 @@ public class ActionHandlerTest { } @Test + @RequiresFlagsEnabled({Flags.FLAG_DESKTOP_FILE_HANDLING}) + public void testShowChooserDesktop() throws Exception { + mActivity.currentRoot = TestProvidersAccess.DOWNLOADS; + + mHandler.showChooserForDoc(TestEnv.FILE_PDF); + Intent actual = mActivity.startActivity.getLastValue(); + assertEquals(Intent.ACTION_VIEW, actual.getAction()); + assertEquals("ComponentInfo{android/com.android.internal.app.ResolverActivity}", + actual.getComponent().toString()); + } + + @Test public void testInitLocation_LaunchToStackLocation() { DocumentStack path = new DocumentStack(Roots.create("123"), mEnv.model.getDocument("1")); @@ -510,23 +605,35 @@ public class ActionHandlerTest { assertRootPicked(TestProvidersAccess.DOWNLOADS.getUri()); } + // Ignoring the test because it uses hidden api DragEvent#obtain() and changes to the api is + // causing failure on older base builds + // TODO: b/343206763 remove dependence on hidden api + @Ignore @Test public void testDragAndDrop_OnReadOnlyRoot() throws Exception { assumeTrue(VersionUtils.isAtLeastS()); RootInfo root = new RootInfo(); // root by default has no SUPPORT_CREATE flag - DragEvent event = DragEvent.obtain(DragEvent.ACTION_DROP, 1, 1, 0, 0, null, null, null, - null, null, true); + DragEvent event = DragEvent.obtain(DragEvent.ACTION_DROP, 1, 1, 0, 0, 0, 0, null, null, + null, null, null, true); assertFalse(mHandler.dropOn(event, root)); } + // Ignoring the test because it uses hidden api DragEvent#obtain() and changes to the api is + // causing failure on older base builds + // TODO: b/343206763 remove dependence on hidden api + @Ignore @Test public void testDragAndDrop_OnLibraryRoot() throws Exception { assumeTrue(VersionUtils.isAtLeastS()); - DragEvent event = DragEvent.obtain(DragEvent.ACTION_DROP, 1, 1, 0, 0, null, null, null, - null, null, true); + DragEvent event = DragEvent.obtain(DragEvent.ACTION_DROP, 1, 1, 0, 0, 0, 0, null, null, + null, null, null, true); assertFalse(mHandler.dropOn(event, TestProvidersAccess.RECENTS)); } + // Ignoring the test because it uses hidden api DragEvent#obtain() and changes to the api is + // causing failure on older base builds + // TODO: b/343206763 remove dependence on hidden api + @Ignore @Test public void testDragAndDrop_DropsOnWritableRoot() throws Exception { assumeTrue(VersionUtils.isAtLeastS()); @@ -535,8 +642,8 @@ public class ActionHandlerTest { // our Clipper is getting the original CipData passed in. Object localState = new Object(); ClipData clipData = ClipDatas.createTestClipData(); - DragEvent event = DragEvent.obtain(DragEvent.ACTION_DROP, 1, 1, 0, 0, localState, null, - clipData, null, null, true); + DragEvent event = DragEvent.obtain(DragEvent.ACTION_DROP, 1, 1, 0, 0, 0, 0, localState, + null, clipData, null, null, true); mHandler.dropOn(event, TestProvidersAccess.DOWNLOADS); event.recycle(); @@ -617,8 +724,17 @@ public class ActionHandlerTest { } @Test + @RequiresFlagsEnabled({Flags.FLAG_USE_MATERIAL3, Flags.FLAG_USE_PEEK_PREVIEW}) + public void testShowPeek() throws Exception { + mHandler.showPreview(TestEnv.FILE_GIF); + // The inspector activity is not called. + mActivity.startActivity.assertNotCalled(); + } + + @Test + @RequiresFlagsDisabled({Flags.FLAG_USE_PEEK_PREVIEW}) public void testShowInspector() throws Exception { - mHandler.showInspector(TestEnv.FILE_GIF); + mHandler.showPreview(TestEnv.FILE_GIF); mActivity.startActivity.assertCalled(); Intent intent = mActivity.startActivity.getLastValue(); @@ -630,10 +746,11 @@ public class ActionHandlerTest { } @Test + @RequiresFlagsDisabled({Flags.FLAG_USE_PEEK_PREVIEW}) public void testShowInspector_DebugDisabled() throws Exception { mFeatures.debugSupport = false; - mHandler.showInspector(TestEnv.FILE_GIF); + mHandler.showPreview(TestEnv.FILE_GIF); Intent intent = mActivity.startActivity.getLastValue(); assertHasExtra(intent, Shared.EXTRA_SHOW_DEBUG); @@ -641,11 +758,12 @@ public class ActionHandlerTest { } @Test + @RequiresFlagsDisabled({Flags.FLAG_USE_PEEK_PREVIEW}) public void testShowInspector_DebugEnabled() throws Exception { mFeatures.debugSupport = true; DebugFlags.setDocumentDetailsEnabled(true); - mHandler.showInspector(TestEnv.FILE_GIF); + mHandler.showPreview(TestEnv.FILE_GIF); Intent intent = mActivity.startActivity.getLastValue(); assertHasExtra(intent, Shared.EXTRA_SHOW_DEBUG); @@ -654,6 +772,7 @@ public class ActionHandlerTest { } @Test + @RequiresFlagsDisabled({Flags.FLAG_USE_PEEK_PREVIEW}) public void testShowInspector_OverridesRootDocumentName() throws Exception { mActivity.currentRoot = TestProvidersAccess.PICKLES; mEnv.populateStack(); @@ -665,7 +784,7 @@ public class ActionHandlerTest { DocumentInfo rootDoc = mEnv.state.stack.peek(); rootDoc.displayName = "poodles"; - mHandler.showInspector(rootDoc); + mHandler.showPreview(rootDoc); Intent intent = mActivity.startActivity.getLastValue(); assertEquals( TestProvidersAccess.PICKLES.title, @@ -673,6 +792,7 @@ public class ActionHandlerTest { } @Test + @RequiresFlagsDisabled({Flags.FLAG_USE_PEEK_PREVIEW}) public void testShowInspector_OverridesRootDocumentNameX() throws Exception { mActivity.currentRoot = TestProvidersAccess.PICKLES; mEnv.populateStack(); @@ -685,7 +805,7 @@ public class ActionHandlerTest { DocumentInfo rootDoc = mEnv.state.stack.peek(); rootDoc.displayName = "poodles"; - mHandler.showInspector(rootDoc); + mHandler.showPreview(rootDoc); Intent intent = mActivity.startActivity.getLastValue(); assertFalse(intent.getExtras().containsKey(Intent.EXTRA_TITLE)); } diff --git a/tests/unit/com/android/documentsui/files/MenuManagerTest.java b/tests/unit/com/android/documentsui/files/MenuManagerTest.java index fe1d02209..f3b7078e8 100644 --- a/tests/unit/com/android/documentsui/files/MenuManagerTest.java +++ b/tests/unit/com/android/documentsui/files/MenuManagerTest.java @@ -21,6 +21,10 @@ import static junit.framework.Assert.assertEquals; import static org.junit.Assert.assertTrue; import android.net.Uri; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; @@ -35,6 +39,7 @@ import com.android.documentsui.base.RootInfo; import com.android.documentsui.base.State; import com.android.documentsui.base.UserId; import com.android.documentsui.dirlist.TestData; +import com.android.documentsui.flags.Flags; import com.android.documentsui.testing.TestDirectoryDetails; import com.android.documentsui.testing.TestEnv; import com.android.documentsui.testing.TestFeatures; @@ -45,6 +50,7 @@ import com.android.documentsui.testing.TestSearchViewManager; import com.android.documentsui.testing.TestSelectionDetails; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -60,6 +66,7 @@ public final class MenuManagerTest { private TestMenuItem dirOpenWith; private TestMenuItem dirCutToClipboard; private TestMenuItem dirCopyToClipboard; + private TestMenuItem mDirCompress; private TestMenuItem dirPasteFromClipboard; private TestMenuItem dirCreateDir; private TestMenuItem dirSelectAll; @@ -104,6 +111,7 @@ public final class MenuManagerTest { private TestMenuItem optionSort; private TestMenuItem mOptionLauncher; private TestMenuItem mOptionShowHiddenFiles; + private TestMenuItem mOptionExtractAll; /* Sub Option Menu items */ private TestMenuItem subOptionGrid; @@ -122,6 +130,9 @@ public final class MenuManagerTest { private int mFilesCount; + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @Before public void setUp() { testMenu = TestMenu.create(); @@ -132,6 +143,7 @@ public final class MenuManagerTest { dirOpenWith = testMenu.findItem(R.id.dir_menu_open_with); dirCutToClipboard = testMenu.findItem(R.id.dir_menu_cut_to_clipboard); dirCopyToClipboard = testMenu.findItem(R.id.dir_menu_copy_to_clipboard); + mDirCompress = testMenu.findItem(R.id.dir_menu_compress); dirPasteFromClipboard = testMenu.findItem(R.id.dir_menu_paste_from_clipboard); dirCreateDir = testMenu.findItem(R.id.dir_menu_create_dir); dirSelectAll = testMenu.findItem(R.id.dir_menu_select_all); @@ -174,6 +186,7 @@ public final class MenuManagerTest { optionSort = testMenu.findItem(R.id.option_menu_sort); mOptionLauncher = testMenu.findItem(R.id.option_menu_launcher); mOptionShowHiddenFiles = testMenu.findItem(R.id.option_menu_show_hidden_files); + mOptionExtractAll = testMenu.findItem(R.id.option_menu_extract_all); // Menu actions on root title row. subOptionGrid = testMenu.findItem(R.id.sub_menu_grid); @@ -242,6 +255,7 @@ public final class MenuManagerTest { actionModeSort.assertEnabledAndVisible(); actionModeSelectAll.assertEnabledAndVisible(); mActionModeDeselectAll.assertDisabledAndInvisible(); + mOptionExtractAll.assertDisabledAndInvisible(); } @Test @@ -257,6 +271,7 @@ public final class MenuManagerTest { actionModeExtractTo.assertDisabledAndInvisible(); actionModeMoveTo.assertDisabledAndInvisible(); actionModeViewInOwner.assertDisabledAndInvisible(); + mOptionExtractAll.assertDisabledAndInvisible(); } @Test @@ -386,7 +401,7 @@ public final class MenuManagerTest { @Test public void testActionMenu_CanOpenWith() { - selectionDetails.canOpenWith = true; + selectionDetails.canOpen = true; mgr.updateActionMenu(testMenu, selectionDetails); actionModeOpenWith.assertEnabledAndVisible(); @@ -394,7 +409,7 @@ public final class MenuManagerTest { @Test public void testActionMenu_NoOpenWith() { - selectionDetails.canOpenWith = false; + selectionDetails.canOpen = false; mgr.updateActionMenu(testMenu, selectionDetails); actionModeOpenWith.assertDisabledAndInvisible(); @@ -581,22 +596,35 @@ public final class MenuManagerTest { dirOpen.assertDisabledAndInvisible(); dirCutToClipboard.assertDisabledAndInvisible(); dirCopyToClipboard.assertEnabledAndVisible(); + mDirCompress.assertDisabledAndInvisible(); dirRename.assertDisabledAndInvisible(); dirCreateDir.assertEnabledAndVisible(); dirDelete.assertDisabledAndInvisible(); } @Test - public void testContextMenu_OnFile_CanOpenWith() { - selectionDetails.canOpenWith = true; + @RequiresFlagsDisabled({Flags.FLAG_DESKTOP_FILE_HANDLING}) + public void testContextMenu_OnFile_CanOpen() { + selectionDetails.canOpen = true; + mgr.updateContextMenuForFiles(testMenu, selectionDetails); + dirOpen.assertDisabledAndInvisible(); + dirOpenWith.assertEnabledAndVisible(); + } + + @Test + @RequiresFlagsEnabled({Flags.FLAG_DESKTOP_FILE_HANDLING}) + public void testContextMenu_OnFile_CanOpenDesktop() { + selectionDetails.canOpen = true; mgr.updateContextMenuForFiles(testMenu, selectionDetails); + dirOpen.assertEnabledAndVisible(); dirOpenWith.assertEnabledAndVisible(); } @Test - public void testContextMenu_OnFile_NoOpenWith() { - selectionDetails.canOpenWith = false; + public void testContextMenu_OnFile_NoOpen() { + selectionDetails.canOpen = false; mgr.updateContextMenuForFiles(testMenu, selectionDetails); + dirOpen.assertDisabledAndInvisible(); dirOpenWith.assertDisabledAndInvisible(); } @@ -605,6 +633,7 @@ public final class MenuManagerTest { selectionDetails.size = 3; mgr.updateContextMenuForFiles(testMenu, selectionDetails); dirOpen.assertDisabledAndInvisible(); + mDirCompress.assertDisabledAndInvisible(); } @Test @@ -616,6 +645,7 @@ public final class MenuManagerTest { dirOpenInNewWindow.assertEnabledAndVisible(); dirCutToClipboard.assertDisabledAndInvisible(); dirCopyToClipboard.assertEnabledAndVisible(); + mDirCompress.assertDisabledAndInvisible(); dirPasteIntoFolder.assertEnabledAndVisible(); dirRename.assertDisabledAndInvisible(); dirDelete.assertDisabledAndInvisible(); @@ -629,6 +659,7 @@ public final class MenuManagerTest { dirOpenInNewWindow.assertEnabledAndVisible(); dirCutToClipboard.assertDisabledAndInvisible(); dirCopyToClipboard.assertEnabledAndVisible(); + mDirCompress.assertDisabledAndInvisible(); dirPasteIntoFolder.assertDisabledAndInvisible(); dirRename.assertDisabledAndInvisible(); dirDelete.assertDisabledAndInvisible(); @@ -656,6 +687,7 @@ public final class MenuManagerTest { selectionDetails.size = 3; mgr.updateContextMenuForDirs(testMenu, selectionDetails); dirOpenInNewWindow.assertDisabledAndInvisible(); + mDirCompress.assertDisabledAndInvisible(); } @Test @@ -667,6 +699,7 @@ public final class MenuManagerTest { mgr.updateContextMenu(testMenu, selectionDetails); dirCutToClipboard.assertEnabledAndVisible(); dirCopyToClipboard.assertEnabledAndVisible(); + mDirCompress.assertDisabledAndInvisible(); dirDelete.assertEnabledAndVisible(); } @@ -680,6 +713,7 @@ public final class MenuManagerTest { mgr.updateContextMenu(testMenu, selectionDetails); dirCutToClipboard.assertDisabledAndInvisible(); dirCopyToClipboard.assertDisabledAndInvisible(); + mDirCompress.assertDisabledAndInvisible(); dirDelete.assertEnabledAndVisible(); } @@ -692,6 +726,7 @@ public final class MenuManagerTest { mgr.updateContextMenu(testMenu, selectionDetails); dirCutToClipboard.assertDisabledAndInvisible(); dirCopyToClipboard.assertEnabledAndVisible(); + mDirCompress.assertDisabledAndInvisible(); dirDelete.assertDisabledAndInvisible(); } diff --git a/tests/unit/com/android/documentsui/files/QuickViewIntentBuilderTest.java b/tests/unit/com/android/documentsui/files/QuickViewIntentBuilderTest.java index 14c86e69f..5adaa4d65 100644 --- a/tests/unit/com/android/documentsui/files/QuickViewIntentBuilderTest.java +++ b/tests/unit/com/android/documentsui/files/QuickViewIntentBuilderTest.java @@ -142,7 +142,7 @@ public class QuickViewIntentBuilderTest { public void testBuild_twoProfiles_containsOnlyPreviewDocument() { mEnv.model.reset(); mEnv.model.createDocumentForUser("a.txt", "text/plain", 0, - TestProvidersAccess.OtherUser.USER_ID); + System.currentTimeMillis(), TestProvidersAccess.OtherUser.USER_ID); DocumentInfo previewDoc = mEnv.model.createFile("b.png", 0); mEnv.model.createFile("c.png", 0); mEnv.model.update(); diff --git a/tests/unit/com/android/documentsui/inspector/GpsCoordinatesTextClassifierTest.java b/tests/unit/com/android/documentsui/inspector/GpsCoordinatesTextClassifierTest.java index e25d227e7..f4e04221d 100644 --- a/tests/unit/com/android/documentsui/inspector/GpsCoordinatesTextClassifierTest.java +++ b/tests/unit/com/android/documentsui/inspector/GpsCoordinatesTextClassifierTest.java @@ -20,12 +20,12 @@ import static junit.framework.Assert.assertEquals; import android.content.Context; import android.content.pm.PackageManager; import android.os.LocaleList; -import android.test.suitebuilder.annotation.SmallTest; import android.view.textclassifier.TextClassification; import android.view.textclassifier.TextClassificationManager; import android.view.textclassifier.TextClassifier; import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.documentsui.testing.TestPackageManager; diff --git a/tests/unit/com/android/documentsui/inspector/HeaderTextSelectorTest.java b/tests/unit/com/android/documentsui/inspector/HeaderTextSelectorTest.java index 30178cedc..28bc667ab 100644 --- a/tests/unit/com/android/documentsui/inspector/HeaderTextSelectorTest.java +++ b/tests/unit/com/android/documentsui/inspector/HeaderTextSelectorTest.java @@ -19,12 +19,12 @@ import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; import android.content.Context; -import android.test.suitebuilder.annotation.SmallTest; import android.text.Spannable; import android.text.SpannableString; import android.widget.TextView; import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.documentsui.inspector.HeaderTextSelector.Selector; diff --git a/tests/unit/com/android/documentsui/inspector/InspectorControllerTest.java b/tests/unit/com/android/documentsui/inspector/InspectorControllerTest.java index 9a7bad574..f3d5b591c 100644 --- a/tests/unit/com/android/documentsui/inspector/InspectorControllerTest.java +++ b/tests/unit/com/android/documentsui/inspector/InspectorControllerTest.java @@ -29,10 +29,10 @@ import android.os.Looper; import android.os.UserHandle; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; -import android.test.suitebuilder.annotation.SmallTest; import android.view.View.OnClickListener; import androidx.annotation.Nullable; +import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.documentsui.InspectorProvider; diff --git a/tests/unit/com/android/documentsui/inspector/MediaViewTest.java b/tests/unit/com/android/documentsui/inspector/MediaViewTest.java index 80c3c4729..db87e42bd 100644 --- a/tests/unit/com/android/documentsui/inspector/MediaViewTest.java +++ b/tests/unit/com/android/documentsui/inspector/MediaViewTest.java @@ -19,8 +19,8 @@ import android.media.ExifInterface; import android.media.MediaMetadata; import android.os.Bundle; import android.provider.DocumentsContract; -import android.test.suitebuilder.annotation.SmallTest; +import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.documentsui.R; diff --git a/tests/unit/com/android/documentsui/loaders/BaseLoaderTest.kt b/tests/unit/com/android/documentsui/loaders/BaseLoaderTest.kt new file mode 100644 index 000000000..62434b71f --- /dev/null +++ b/tests/unit/com/android/documentsui/loaders/BaseLoaderTest.kt @@ -0,0 +1,98 @@ +/* + * 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.documentsui.loaders + +import android.os.Parcel +import android.provider.DocumentsContract +import com.android.documentsui.DirectoryResult +import com.android.documentsui.TestActivity +import com.android.documentsui.TestConfigStore +import com.android.documentsui.base.DocumentInfo +import com.android.documentsui.base.UserId +import com.android.documentsui.sorting.SortModel +import com.android.documentsui.testing.ActivityManagers +import com.android.documentsui.testing.TestEnv +import com.android.documentsui.testing.TestModel +import com.android.documentsui.testing.UserManagers +import java.time.Duration +import java.util.Locale +import kotlin.time.Duration.Companion.hours +import org.junit.Before + +/** + * Returns the number of matched files, or -1. + */ +fun getFileCount(result: DirectoryResult?) = result?.cursor?.count ?: -1 + +/** + * A data class that holds parameters that can be varied for the loader test. The last + * value, expectedCount, can be used for simple tests that check that the number of + * returned files matches the expectations. + */ +data class LoaderTestParams( + // A query, matched against file names. May be empty. + val query: String, + // The delta from now that indicates maximum age of matched files. + val lastModifiedDelta: Duration?, + // The number of files that are expected, for the above parameters, to be found by a loader. + val expectedCount: Int +) + +/** + * Common base class for search and folder loaders. + */ +open class BaseLoaderTest { + lateinit var mEnv: TestEnv + lateinit var mActivity: TestActivity + lateinit var mTestConfigStore: TestConfigStore + + @Before + open fun setUp() { + mEnv = TestEnv.create() + mTestConfigStore = TestConfigStore() + mEnv.state.configStore = mTestConfigStore + mEnv.state.showHiddenFiles = false + val parcel = Parcel.obtain() + mEnv.state.sortModel = SortModel.CREATOR.createFromParcel(parcel) + + mActivity = TestActivity.create(mEnv) + mActivity.activityManager = ActivityManagers.create(false) + mActivity.userManager = UserManagers.create() + } + + /** + * Creates a text, PNG, MP4 and MPG files named sample-000x, for x in 0 .. count - 1. + * Each file gets a matching extension. The 0th file is modified 1h, 1st 2 hours, .. etc., ago. + */ + fun createDocuments(count: Int): Array<DocumentInfo> { + val extensionList = arrayOf("txt", "png", "mp4", "mpg") + val now = System.currentTimeMillis() + val flags = (DocumentsContract.Document.FLAG_SUPPORTS_WRITE + or DocumentsContract.Document.FLAG_SUPPORTS_DELETE + or DocumentsContract.Document.FLAG_SUPPORTS_RENAME) + return Array<DocumentInfo>(count) { i -> + val id = String.format(Locale.US, "%05d", i) + val name = "sample-$id.${extensionList[i % extensionList.size]}" + mEnv.model.createDocumentForUser( + name, + TestModel.guessMimeType(name), + flags, + now - 1.hours.inWholeMilliseconds * i, + UserId.DEFAULT_USER + ) + } + } +} diff --git a/tests/unit/com/android/documentsui/loaders/FolderLoaderTest.kt b/tests/unit/com/android/documentsui/loaders/FolderLoaderTest.kt new file mode 100644 index 000000000..cb0735b17 --- /dev/null +++ b/tests/unit/com/android/documentsui/loaders/FolderLoaderTest.kt @@ -0,0 +1,81 @@ +/* + * 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.documentsui.loaders + +import androidx.test.filters.SmallTest +import com.android.documentsui.ContentLock +import com.android.documentsui.base.DocumentInfo +import com.android.documentsui.testing.TestFileTypeLookup +import com.android.documentsui.testing.TestProvidersAccess +import java.time.Duration +import junit.framework.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized +import org.junit.runners.Parameterized.Parameters + +private const val TOTAL_FILE_COUNT = 10 + +@RunWith(Parameterized::class) +@SmallTest +class FolderLoaderTest(private val testParams: LoaderTestParams) : BaseLoaderTest() { + companion object { + @JvmStatic + @Parameters(name = "with parameters {0}") + fun data() = listOf( + LoaderTestParams("", null, TOTAL_FILE_COUNT), + // The first file is at NOW, the second at NOW - 1h, etc. + LoaderTestParams("", Duration.ofMinutes(1L), 1), + LoaderTestParams("", Duration.ofMinutes(60L + 1), 2), + LoaderTestParams("", Duration.ofMinutes(TOTAL_FILE_COUNT * 60L + 1), TOTAL_FILE_COUNT), + ) + } + + @Test + fun testLoadInBackground() { + val mockProvider = mEnv.mockProviders[TestProvidersAccess.DOWNLOADS.authority] + val docs = createDocuments(TOTAL_FILE_COUNT) + mockProvider!!.setNextChildDocumentsReturns(*docs) + val userIds = listOf(TestProvidersAccess.DOWNLOADS.userId) + val queryOptions = + QueryOptions( + TOTAL_FILE_COUNT, + testParams.lastModifiedDelta, + null, + true, + arrayOf<String>("*/*") + ) + val contentLock = ContentLock() + // TODO(majewski): Is there a better way to create Downloads root folder DocumentInfo? + val rootFolderInfo = DocumentInfo() + rootFolderInfo.authority = TestProvidersAccess.DOWNLOADS.authority + rootFolderInfo.userId = userIds[0] + + val loader = + FolderLoader( + mActivity, + userIds, + TestFileTypeLookup(), + contentLock, + TestProvidersAccess.DOWNLOADS, + rootFolderInfo, + queryOptions, + mEnv.state.sortModel + ) + val directoryResult = loader.loadInBackground() + assertEquals(testParams.expectedCount, getFileCount(directoryResult)) + } +} diff --git a/tests/unit/com/android/documentsui/loaders/SearchLoaderTest.kt b/tests/unit/com/android/documentsui/loaders/SearchLoaderTest.kt new file mode 100644 index 000000000..9addf1a7f --- /dev/null +++ b/tests/unit/com/android/documentsui/loaders/SearchLoaderTest.kt @@ -0,0 +1,99 @@ +/* + * 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.documentsui.loaders + +import androidx.test.filters.SmallTest +import com.android.documentsui.ContentLock +import com.android.documentsui.LockingContentObserver +import com.android.documentsui.base.DocumentInfo +import com.android.documentsui.testing.TestFileTypeLookup +import com.android.documentsui.testing.TestProvidersAccess +import java.time.Duration +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import junit.framework.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized +import org.junit.runners.Parameterized.Parameters + +private const val TOTAL_FILE_COUNT = 8 + +@RunWith(Parameterized::class) +@SmallTest +class SearchLoaderTest(private val testParams: LoaderTestParams) : BaseLoaderTest() { + private lateinit var mExecutor: ExecutorService + + companion object { + @JvmStatic + @Parameters(name = "with parameters {0}") + fun data() = listOf( + LoaderTestParams("sample", null, TOTAL_FILE_COUNT), + LoaderTestParams("txt", null, 2), + LoaderTestParams("foozig", null, 0), + // The first file is at NOW, the second at NOW - 1h; expect 2. + LoaderTestParams("sample", Duration.ofMinutes(60 + 1), 2), + // TODO(b:378590632): Add test for recents. + ) + } + + @Before + override fun setUp() { + super.setUp() + mExecutor = Executors.newSingleThreadExecutor() + } + + @Test + fun testLoadInBackground() { + val mockProvider = mEnv.mockProviders[TestProvidersAccess.DOWNLOADS.authority] + val docs = createDocuments(TOTAL_FILE_COUNT) + mockProvider!!.setNextChildDocumentsReturns(*docs) + val userIds = listOf(TestProvidersAccess.DOWNLOADS.userId) + val queryOptions = + QueryOptions( + TOTAL_FILE_COUNT + 1, + testParams.lastModifiedDelta, + null, + true, + arrayOf("*/*") + ) + val contentLock = ContentLock() + val rootIds = listOf(TestProvidersAccess.DOWNLOADS) + val observer = LockingContentObserver(contentLock) { + } + + // TODO(majewski): Is there a better way to create Downloads root folder DocumentInfo? + val rootFolderInfo = DocumentInfo() + rootFolderInfo.authority = TestProvidersAccess.DOWNLOADS.authority + rootFolderInfo.userId = userIds[0] + + val loader = + SearchLoader( + mActivity, + userIds, + TestFileTypeLookup(), + observer, + rootIds, + testParams.query, + queryOptions, + mEnv.state.sortModel, + mExecutor, + ) + val directoryResult = loader.loadInBackground() + assertEquals(testParams.expectedCount, getFileCount(directoryResult)) + } +} diff --git a/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java b/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java index 61094ba94..d3e6e90d0 100644 --- a/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java +++ b/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java @@ -36,13 +36,11 @@ import android.provider.DocumentsContract.Path; import androidx.fragment.app.FragmentActivity; import androidx.test.filters.MediumTest; import androidx.test.filters.SdkSuppress; -import androidx.test.runner.AndroidJUnit4; import com.android.documentsui.DocumentsAccess; import com.android.documentsui.Injector; import com.android.documentsui.R; -import com.android.documentsui.TestUserIdManager; -import com.android.documentsui.UserIdManager; +import com.android.documentsui.TestConfigStore; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.Lookup; @@ -59,28 +57,47 @@ import com.android.documentsui.testing.TestLastAccessedStorage; import com.android.documentsui.testing.TestProvidersAccess; import com.android.documentsui.testing.TestResolveInfo; import com.android.documentsui.util.VersionUtils; +import com.android.modules.utils.build.SdkLevel; + +import com.google.common.collect.Lists; import org.junit.AfterClass; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; import java.util.Arrays; import java.util.concurrent.Executor; -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) @MediumTest public class ActionHandlerTest { private static final String EXTRA_INTENT = "EXTRA_INTENT"; private static final String EXTRA_USER = "EXTRA_USER"; + private final TestConfigStore mTestConfigStore = new TestConfigStore(); + private TestEnv mEnv; private TestActivity mActivity; private TestableActionHandler<TestActivity> mHandler; private TestLastAccessedStorage mLastAccessed; private PickCountRecordStorage mPickCountRecord; - private TestUserIdManager mTestUserIdManager; + + @Parameter(0) + public boolean isPrivateSpaceEnabled; + + /** + * Parametrize values for {@code isPrivateSpaceEnabled} to run all the tests twice once with + * private space flag enabled and once with it disabled. + */ + @Parameters(name = "privateSpaceEnabled={0}") + public static Iterable<?> data() { + return Lists.newArrayList(true, false); + } @Before public void setUp() { @@ -89,8 +106,14 @@ public class ActionHandlerTest { mEnv.providers.configurePm(mActivity.packageMgr); mEnv.injector.pickResult = new PickResult(); mLastAccessed = new TestLastAccessedStorage(); - mTestUserIdManager = new TestUserIdManager(); mPickCountRecord = mock(PickCountRecordStorage.class); + mEnv.state.configStore = mTestConfigStore; + + isPrivateSpaceEnabled = SdkLevel.isAtLeastS() && isPrivateSpaceEnabled; + if (isPrivateSpaceEnabled) { + mTestConfigStore.enablePrivateSpaceInPhotoPicker(); + mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.USER_ID, true); + } mHandler = new TestableActionHandler<>( mActivity, @@ -101,17 +124,17 @@ public class ActionHandlerTest { mEnv::lookupExecutor, mEnv.injector, mLastAccessed, - mPickCountRecord, - mTestUserIdManager + mPickCountRecord ); + mEnv.selectionMgr.select("1"); AsyncTask.setDefaultExecutor(mEnv.mExecutor); } private static class TestableActionHandler<T extends FragmentActivity & Addons> - extends ActionHandler { + extends ActionHandler { private UpdatePickResultTask mTask; @@ -124,10 +147,8 @@ public class ActionHandlerTest { Lookup<String, Executor> executors, Injector injector, LastAccessedStorage lastAccessed, - PickCountRecordStorage pickCountRecordStorage, - UserIdManager userIdManager) { - super(activity, state, providers, docs, searchMgr, executors, injector, lastAccessed, - userIdManager); + PickCountRecordStorage pickCountRecordStorage) { + super(activity, state, providers, docs, searchMgr, executors, injector, lastAccessed); mTask = new UpdatePickResultTask( mActivity, mInjector.pickResult, pickCountRecordStorage); } @@ -202,6 +223,7 @@ public class ActionHandlerTest { @Test public void testInitLocation_RestoresLastAccessedStack() throws Exception { + if (!SdkLevel.isAtLeastS()) return; final DocumentStack stack = new DocumentStack(TestProvidersAccess.HAMMY, TestEnv.FOLDER_0, TestEnv.FOLDER_1); mLastAccessed.setLastAccessed(mActivity, stack); @@ -284,7 +306,7 @@ public class ActionHandlerTest { mEnv.beforeAsserts(); verify(mPickCountRecord).increasePickCountRecord( - mActivity.getApplicationContext(), TestEnv.FILE_JPG.derivedUri); + mActivity.getApplicationContext(), TestEnv.FILE_JPG.derivedUri); mActivity.finishedHandler.assertCalled(); } @@ -355,7 +377,8 @@ public class ActionHandlerTest { final String mimeType = "audio/aac"; final String displayName = "foobar.m4a"; - mHandler.saveDocument(mimeType, displayName, (boolean inProgress) -> {}); + mHandler.saveDocument(mimeType, displayName, (boolean inProgress) -> { + }); mEnv.beforeAsserts(); @@ -431,7 +454,7 @@ public class ActionHandlerTest { mEnv.state.action = State.ACTION_GET_CONTENT; mEnv.state.stack.changeRoot(TestProvidersAccess.HOME); mEnv.state.stack.push(TestEnv.FOLDER_1); - mEnv.state.acceptMimes = new String[] { "image/*" }; + mEnv.state.acceptMimes = new String[]{"image/*"}; mActivity.finishedHandler.assertNotCalled(); @@ -483,7 +506,7 @@ public class ActionHandlerTest { mEnv.state.action = State.ACTION_OPEN; mEnv.state.stack.changeRoot(TestProvidersAccess.HOME); mEnv.state.stack.push(TestEnv.FOLDER_1); - mEnv.state.acceptMimes = new String[] { "image/*" }; + mEnv.state.acceptMimes = new String[]{"image/*"}; mActivity.finishedHandler.assertNotCalled(); @@ -539,13 +562,17 @@ public class ActionHandlerTest { @Test public void testOpenAppRoot_otherUser() throws Exception { ResolveInfo info = TestResolveInfo.create(); - mEnv.state.canShareAcrossProfile = true; + if (isPrivateSpaceEnabled) { + mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.OtherUser.USER_ID, true); + } else { + mEnv.state.canShareAcrossProfile = true; + } mHandler.openRoot(info, TestProvidersAccess.OtherUser.USER_ID); assertThat(mActivity.startActivityAsUser.getLastValue().first.getComponent()).isEqualTo( new ComponentName(info.activityInfo.applicationInfo.packageName, - info.activityInfo.name)); + info.activityInfo.name)); assertThat(mActivity.startActivityAsUser.getLastValue().second) - .isEqualTo(TestProvidersAccess.OtherUser.USER_HANDLE); + .isEqualTo(TestProvidersAccess.OtherUser.USER_HANDLE); int flags = mActivity.startActivityAsUser.getLastValue().first.getFlags(); assertEquals(0, flags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); @@ -569,7 +596,7 @@ public class ActionHandlerTest { mHandler.openRoot(info, TestProvidersAccess.USER_ID); assertThat(mActivity.startActivity.getLastValue().getComponent()).isEqualTo( new ComponentName(info.activityInfo.applicationInfo.packageName, - info.activityInfo.name)); + info.activityInfo.name)); int flags = mActivity.startActivity.getLastValue().getFlags(); assertEquals(0, flags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); @@ -589,7 +616,7 @@ public class ActionHandlerTest { mHandler.openRoot(TestResolveInfo.create(), TestProvidersAccess.USER_ID); assertEquals(queryContent, mActivity.startActivity.getLastValue().getStringExtra( - Intent.EXTRA_CONTENT_QUERY)); + Intent.EXTRA_CONTENT_QUERY)); } @Test @@ -618,7 +645,8 @@ public class ActionHandlerTest { mActivity.currentRoot = TestProvidersAccess.OtherUser.DOWNLOADS; mEnv.model.reset(); DocumentInfo otherUserDoc = mEnv.model.createDocumentForUser("a.png", - "image/png", /* flags= */ 0, TestProvidersAccess.OtherUser.USER_ID); + "image/png", /* flags= */ 0, System.currentTimeMillis(), + TestProvidersAccess.OtherUser.USER_ID); mEnv.model.update(); mHandler.onDocumentOpened(otherUserDoc, ActionHandler.VIEW_TYPE_PREVIEW, @@ -712,4 +740,4 @@ public class ActionHandlerTest { } } } -} +}
\ No newline at end of file diff --git a/tests/unit/com/android/documentsui/picker/MenuManagerTest.java b/tests/unit/com/android/documentsui/picker/MenuManagerTest.java index cf9699a3b..7ebf1e6a3 100644 --- a/tests/unit/com/android/documentsui/picker/MenuManagerTest.java +++ b/tests/unit/com/android/documentsui/picker/MenuManagerTest.java @@ -61,6 +61,7 @@ public final class MenuManagerTest { private TestMenuItem dirCutToClipboard; private TestMenuItem dirCopyToClipboard; private TestMenuItem dirPasteFromClipboard; + private TestMenuItem mDirCompress; private TestMenuItem dirCreateDir; private TestMenuItem dirSelectAll; private TestMenuItem mDirDeselectAll; @@ -102,6 +103,7 @@ public final class MenuManagerTest { private TestMenuItem optionSort; private TestMenuItem mOptionLauncher; private TestMenuItem mOptionShowHiddenFiles; + private TestMenuItem mOptionExtractAll; private TestMenuItem subOptionGrid; private TestMenuItem subOptionList; @@ -124,6 +126,7 @@ public final class MenuManagerTest { dirOpenWith = testMenu.findItem(R.id.dir_menu_open_with); dirCutToClipboard = testMenu.findItem(R.id.dir_menu_cut_to_clipboard); dirCopyToClipboard = testMenu.findItem(R.id.dir_menu_copy_to_clipboard); + mDirCompress = testMenu.findItem(R.id.dir_menu_compress); dirPasteFromClipboard = testMenu.findItem(R.id.dir_menu_paste_from_clipboard); dirCreateDir = testMenu.findItem(R.id.dir_menu_create_dir); dirSelectAll = testMenu.findItem(R.id.dir_menu_select_all); @@ -162,6 +165,7 @@ public final class MenuManagerTest { optionSort = testMenu.findItem(R.id.option_menu_sort); mOptionLauncher = testMenu.findItem(R.id.option_menu_launcher); mOptionShowHiddenFiles = testMenu.findItem(R.id.option_menu_show_hidden_files); + mOptionExtractAll = testMenu.findItem(R.id.option_menu_extract_all); // Menu actions on root title row. subOptionGrid = testMenu.findItem(R.id.sub_menu_grid); @@ -195,6 +199,7 @@ public final class MenuManagerTest { mActionModeDeselectAll.assertDisabledAndInvisible(); actionModeViewInOwner.assertDisabledAndInvisible(); actionModeSort.assertEnabledAndVisible(); + mOptionExtractAll.assertDisabledAndInvisible(); } @Test @@ -268,6 +273,7 @@ public final class MenuManagerTest { optionSort.assertEnabledAndVisible(); mOptionLauncher.assertDisabledAndInvisible(); mOptionShowHiddenFiles.assertEnabledAndVisible(); + mOptionExtractAll.assertDisabledAndInvisible(); assertTrue(testSearchManager.showMenuCalled()); } @@ -281,6 +287,7 @@ public final class MenuManagerTest { optionCreateDir.assertDisabledAndInvisible(); subOptionGrid.assertEnabledAndVisible(); subOptionList.assertDisabledAndInvisible(); + mOptionExtractAll.assertDisabledAndInvisible(); assertFalse(testSearchManager.showMenuCalled()); } @@ -300,6 +307,7 @@ public final class MenuManagerTest { subOptionGrid.assertDisabledAndInvisible(); subOptionList.assertDisabledAndInvisible(); + mOptionExtractAll.assertDisabledAndInvisible(); } @@ -402,6 +410,7 @@ public final class MenuManagerTest { dirOpenWith.assertDisabledAndInvisible(); dirCutToClipboard.assertDisabledAndInvisible(); dirCopyToClipboard.assertEnabledAndVisible(); + mDirCompress.assertDisabledAndInvisible(); dirRename.assertDisabledAndInvisible(); dirDelete.assertDisabledAndInvisible(); } @@ -414,6 +423,7 @@ public final class MenuManagerTest { dirOpenInNewWindow.assertDisabledAndInvisible(); dirCutToClipboard.assertDisabledAndInvisible(); dirCopyToClipboard.assertEnabledAndVisible(); + mDirCompress.assertDisabledAndInvisible(); // Doesn't matter if directory is selected, we don't want pasteInto for PickerActivity dirPasteIntoFolder.assertDisabledAndInvisible(); dirRename.assertDisabledAndInvisible(); @@ -429,6 +439,7 @@ public final class MenuManagerTest { mgr.updateContextMenu(testMenu, selectionDetails); dirCutToClipboard.assertEnabledAndVisible(); dirCopyToClipboard.assertEnabledAndVisible(); + mDirCompress.assertDisabledAndInvisible(); dirDelete.assertEnabledAndVisible(); } @@ -442,6 +453,7 @@ public final class MenuManagerTest { mgr.updateContextMenu(testMenu, selectionDetails); dirCutToClipboard.assertDisabledAndInvisible(); dirCopyToClipboard.assertDisabledAndInvisible(); + mDirCompress.assertDisabledAndInvisible(); dirDelete.assertEnabledAndVisible(); } @@ -454,6 +466,7 @@ public final class MenuManagerTest { mgr.updateContextMenu(testMenu, selectionDetails); dirCutToClipboard.assertDisabledAndInvisible(); dirCopyToClipboard.assertEnabledAndVisible(); + mDirCompress.assertDisabledAndInvisible(); dirDelete.assertDisabledAndInvisible(); } diff --git a/tests/unit/com/android/documentsui/roots/ProvidersAccessTest.java b/tests/unit/com/android/documentsui/roots/ProvidersAccessTest.java index cab664150..255c1cb10 100644 --- a/tests/unit/com/android/documentsui/roots/ProvidersAccessTest.java +++ b/tests/unit/com/android/documentsui/roots/ProvidersAccessTest.java @@ -21,9 +21,9 @@ import static com.google.common.truth.Truth.assertThat; import android.provider.DocumentsContract; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; import androidx.annotation.Nullable; +import androidx.test.filters.SmallTest; import com.android.documentsui.base.Providers; import com.android.documentsui.base.RootInfo; diff --git a/tests/unit/com/android/documentsui/sidebar/RootsFragmentTest.java b/tests/unit/com/android/documentsui/sidebar/RootsFragmentTest.java index ea88cfb31..2f91a0f0f 100644 --- a/tests/unit/com/android/documentsui/sidebar/RootsFragmentTest.java +++ b/tests/unit/com/android/documentsui/sidebar/RootsFragmentTest.java @@ -24,38 +24,56 @@ import static org.mockito.Mockito.when; import android.app.admin.DevicePolicyManager; import android.content.Context; +import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import androidx.test.filters.MediumTest; import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; +import com.android.documentsui.TestConfigStore; +import com.android.documentsui.TestUserManagerState; import com.android.documentsui.base.RootInfo; -import com.android.documentsui.base.State; import com.android.documentsui.base.UserId; +import com.android.documentsui.flags.Flags; +import com.android.documentsui.testing.TestEnv; import com.android.documentsui.testing.TestProvidersAccess; import com.android.documentsui.testing.TestResolveInfo; +import com.android.modules.utils.build.SdkLevel; + +import com.google.android.collect.Lists; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** - * An unit test for RootsFragment. + * A unit test for RootsFragment. */ -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) @MediumTest public class RootsFragmentTest { private Context mContext; + private PackageManager mPackageManager; private DevicePolicyManager mDevicePolicyManager; private RootsFragment mRootsFragment; + private TestEnv mEnv; + private final TestConfigStore mTestConfigStore = new TestConfigStore(); + private TestUserManagerState mTestUserManagerState; - private static final String[] EXPECTED_SORTED_RESULT = { + private static final String[] EXPECTED_SORTED_RESULT_FOR_NON_DESKTOP = { TestProvidersAccess.RECENTS.title, TestProvidersAccess.IMAGE.title, TestProvidersAccess.VIDEO.title, @@ -69,29 +87,98 @@ public class RootsFragmentTest { TestProvidersAccess.INSPECTOR.title, TestProvidersAccess.PICKLES.title}; + private static final String[] EXPECTED_SORTED_RESULT_FOR_DESKTOP = { + TestProvidersAccess.RECENTS.title, + TestProvidersAccess.DOWNLOADS.title, + "" /* SpacerItem */, + TestProvidersAccess.EXTERNALSTORAGE.title, + TestProvidersAccess.HAMMY.title, + "" /* SpacerItem */, + TestProvidersAccess.INSPECTOR.title, + TestProvidersAccess.PICKLES.title}; + + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + + @Parameter(0) + public boolean isPrivateSpaceEnabled; + + /** + * Parametrize values for {@code isPrivateSpaceEnabled} to run all the tests twice once with + * private space flag enabled and once with it disabled. + */ + @Parameters(name = "privateSpaceEnabled={0}") + public static Iterable<?> data() { + return Lists.newArrayList(true, false); + } + @Before public void setUp() { + mEnv = TestEnv.create(); + mEnv.state.configStore = mTestConfigStore; + mContext = mock(Context.class); mDevicePolicyManager = mock(DevicePolicyManager.class); + mPackageManager = mock(PackageManager.class); when(mContext.getResources()).thenReturn( InstrumentationRegistry.getInstrumentation().getTargetContext().getResources()); when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)) .thenReturn(mDevicePolicyManager); - + when(mContext.getApplicationContext()).thenReturn( + InstrumentationRegistry.getInstrumentation().getTargetContext()); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + + if (SdkLevel.isAtLeastS() && isPrivateSpaceEnabled) { + mTestConfigStore.enablePrivateSpaceInPhotoPicker(); + mTestUserManagerState = new TestUserManagerState(); + mTestUserManagerState.canFrowardToProfileIdMap.put(UserId.DEFAULT_USER, true); + } + isPrivateSpaceEnabled = SdkLevel.isAtLeastS() && isPrivateSpaceEnabled; mRootsFragment = new RootsFragment(); } @Test - public void testSortLoadResult_WithCorrectOrder() { + @RequiresFlagsDisabled({Flags.FLAG_HIDE_ROOTS_ON_DESKTOP}) + public void testSortLoadResult_WithCorrectOrder_hideRootsOnDesktopFlagDisable() { + List<Item> items = mRootsFragment.sortLoadResult( + mContext, + mEnv.state, + createFakeRootInfoList(), + null /* excludePackage */, null /* handlerAppIntent */, new TestProvidersAccess(), + UserId.DEFAULT_USER, + Collections.singletonList(UserId.DEFAULT_USER), + /* maybeShowBadge */ false, mTestUserManagerState); + assertTrue(assertSortedResult(items, EXPECTED_SORTED_RESULT_FOR_NON_DESKTOP)); + } + + @Test + @RequiresFlagsEnabled({Flags.FLAG_HIDE_ROOTS_ON_DESKTOP}) + public void testSortLoadResult_WithCorrectOrder_onNonDesktop() { + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_PC)).thenReturn(false); + List<Item> items = mRootsFragment.sortLoadResult( + mContext, + mEnv.state, + createFakeRootInfoList(), + null /* excludePackage */, null /* handlerAppIntent */, new TestProvidersAccess(), + UserId.DEFAULT_USER, + Collections.singletonList(UserId.DEFAULT_USER), + /* maybeShowBadge */ false, mTestUserManagerState); + assertTrue(assertSortedResult(items, EXPECTED_SORTED_RESULT_FOR_NON_DESKTOP)); + } + + @Test + @RequiresFlagsEnabled({Flags.FLAG_HIDE_ROOTS_ON_DESKTOP}) + public void testSortLoadResult_WithCorrectOrder_onDesktop() { + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_PC)).thenReturn(true); List<Item> items = mRootsFragment.sortLoadResult( mContext, - new State(), + mEnv.state, createFakeRootInfoList(), null /* excludePackage */, null /* handlerAppIntent */, new TestProvidersAccess(), UserId.DEFAULT_USER, Collections.singletonList(UserId.DEFAULT_USER), - /* maybeShowBadge */ false); - assertTrue(assertSortedResult(items)); + /* maybeShowBadge */ false, mTestUserManagerState); + assertTrue(assertSortedResult(items, EXPECTED_SORTED_RESULT_FOR_DESKTOP)); } @Test @@ -136,13 +223,13 @@ public class RootsFragmentTest { assertEquals(rootList.get(2).title, TestProvidersAccess.PICKLES.title); } - private boolean assertSortedResult(List<Item> items) { + private boolean assertSortedResult(List<Item> items, String[] expectedSortedResult) { for (int i = 0; i < items.size(); i++) { Item item = items.get(i); if (item instanceof RootItem) { - assertEquals(EXPECTED_SORTED_RESULT[i], ((RootItem) item).root.title); + assertEquals(expectedSortedResult[i], ((RootItem) item).root.title); } else if (item instanceof SpacerItem) { - assertTrue(EXPECTED_SORTED_RESULT[i].isEmpty()); + assertTrue(expectedSortedResult[i].isEmpty()); } else { return false; } diff --git a/tests/unit/com/android/documentsui/sidebar/UserItemsCombinerTest.java b/tests/unit/com/android/documentsui/sidebar/UserItemsCombinerTest.java index 2a8086791..fc9d1f301 100644 --- a/tests/unit/com/android/documentsui/sidebar/UserItemsCombinerTest.java +++ b/tests/unit/com/android/documentsui/sidebar/UserItemsCombinerTest.java @@ -27,9 +27,11 @@ import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import com.android.documentsui.R; +import com.android.documentsui.TestConfigStore; import com.android.documentsui.base.State; import com.android.documentsui.base.UserId; import com.android.documentsui.testing.TestProvidersAccess; +import com.android.modules.utils.build.SdkLevel; import com.google.common.collect.Lists; import com.google.common.truth.Correspondence; @@ -38,8 +40,11 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; /** @@ -50,6 +55,7 @@ import java.util.Objects; public class UserItemsCombinerTest { private static final UserId PERSONAL_USER = TestProvidersAccess.USER_ID; private static final UserId WORK_USER = TestProvidersAccess.OtherUser.USER_ID; + private static final UserId PRIVATE_USER = TestProvidersAccess.AnotherUser.USER_ID; private static final List<Item> PERSONAL_ITEMS = Lists.newArrayList( personalItem("personal 1"), @@ -61,10 +67,14 @@ public class UserItemsCombinerTest { workItem("work 1") ); + private static final List<Item> PRIVATE_ITEMS = Lists.newArrayList( + privateItem("private1") + ); + private static final Correspondence<Item, Item> ITEM_CORRESPONDENCE = Correspondence.from((Item actual, Item expected) -> { - return Objects.equals(actual.title, expected.title) - && Objects.equals(actual.userId, expected.userId); + return Objects.equals(actual.title, expected.title) + && Objects.equals(actual.userId, expected.userId); }, "has same title and userId as in"); private final State mState = new State(); @@ -73,12 +83,29 @@ public class UserItemsCombinerTest { private final DevicePolicyManager mDpm = InstrumentationRegistry.getInstrumentation().getTargetContext().getSystemService( DevicePolicyManager.class); + private final List<UserId> mUserIds = new ArrayList<>(); + private final Map<UserId, String> mUserIdToLabelMap = new HashMap<>(); + private final TestConfigStore mTestConfigStore = new TestConfigStore(); private UserItemsCombiner mCombiner; @Before public void setUp() { mState.canShareAcrossProfile = true; mState.supportsCrossProfile = true; + mUserIds.add(PERSONAL_USER); + mUserIds.add(WORK_USER); + mUserIdToLabelMap.put(PERSONAL_USER, "Personal"); + mUserIdToLabelMap.put(WORK_USER, "Work"); + mState.canForwardToProfileIdMap.put(PERSONAL_USER, true); + mState.canForwardToProfileIdMap.put(WORK_USER, true); + mState.configStore = mTestConfigStore; + + if (SdkLevel.isAtLeastV()) { + mUserIds.add(PRIVATE_USER); + mUserIdToLabelMap.put(PRIVATE_USER, "Private"); + mState.canForwardToProfileIdMap.put(PRIVATE_USER, true); + mTestConfigStore.enablePrivateSpaceInPhotoPicker(); + } } @Test @@ -90,6 +117,20 @@ public class UserItemsCombinerTest { } @Test + public void testCreatePresentableListForAllUsers_empty() { + final List<List<Item>> rootListAllUsers = new ArrayList<>(); + rootListAllUsers.add(Collections.emptyList()); + rootListAllUsers.add(Collections.emptyList()); + if (SdkLevel.isAtLeastV()) { + rootListAllUsers.add(Collections.emptyList()); + } + mCombiner = new UserItemsCombiner(mResources, mDpm, mState) + .setRootListForAllUsers(rootListAllUsers); + assertThat( + mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap)).isEmpty(); + } + + @Test public void testCreatePresentableList_currentIsPersonal_personalItemsOnly() { mCombiner = new UserItemsCombiner(mResources, mDpm, mState) .setRootListForCurrentUser(PERSONAL_ITEMS) @@ -113,6 +154,55 @@ public class UserItemsCombinerTest { } @Test + public void testCreatePresentableListForAllUsers_currentIsPersonal_personalItemsOnly() { + final List<List<Item>> rootListAllUsers = new ArrayList<>(); + rootListAllUsers.add(Lists.newArrayList(PERSONAL_ITEMS)); + rootListAllUsers.add(Collections.emptyList()); + if (SdkLevel.isAtLeastV()) { + rootListAllUsers.add(Collections.emptyList()); + } + mCombiner = new UserItemsCombiner(mResources, mDpm, mState) + .setRootListForAllUsers(rootListAllUsers); + assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap)) + .comparingElementsUsing(ITEM_CORRESPONDENCE) + .containsExactlyElementsIn(PERSONAL_ITEMS) + .inOrder(); + } + + @Test + public void testCreatePresentableListForAllUsers_currentIsWork_personalItemsOnly() { + final List<List<Item>> rootListAllUsers = new ArrayList<>(); + rootListAllUsers.add(Lists.newArrayList(PERSONAL_ITEMS)); + rootListAllUsers.add(Collections.emptyList()); + if (SdkLevel.isAtLeastV()) { + rootListAllUsers.add(Collections.emptyList()); + } + mCombiner = new UserItemsCombiner(mResources, mDpm, mState) + .overrideCurrentUserForTest(WORK_USER) + .setRootListForAllUsers(rootListAllUsers); + assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap)) + .comparingElementsUsing(ITEM_CORRESPONDENCE) + .containsExactlyElementsIn(PERSONAL_ITEMS) + .inOrder(); + } + + @Test + public void testCreatePresentableListForAllUsers_currentIsPrivate_personalItemsOnly() { + if (!SdkLevel.isAtLeastV()) return; + final List<List<Item>> rootListAllUsers = new ArrayList<>(); + rootListAllUsers.add(Lists.newArrayList(PERSONAL_ITEMS)); + rootListAllUsers.add(Collections.emptyList()); + rootListAllUsers.add(Collections.emptyList()); + mCombiner = new UserItemsCombiner(mResources, mDpm, mState) + .overrideCurrentUserForTest(PRIVATE_USER) + .setRootListForAllUsers(rootListAllUsers); + assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap)) + .comparingElementsUsing(ITEM_CORRESPONDENCE) + .containsExactlyElementsIn(PERSONAL_ITEMS) + .inOrder(); + } + + @Test public void testCreatePresentableList_currentIsPersonal_workItemsOnly() { mCombiner = new UserItemsCombiner(mResources, mDpm, mState) .setRootListForCurrentUser(Collections.emptyList()) @@ -136,6 +226,56 @@ public class UserItemsCombinerTest { } @Test + public void testCreatePresentableListForAllUsers_currentIsPersonal_workItemsOnly() { + final List<List<Item>> rootListAllUsers = new ArrayList<>(); + rootListAllUsers.add(Collections.emptyList()); + rootListAllUsers.add(Lists.newArrayList(WORK_ITEMS)); + if (SdkLevel.isAtLeastV()) { + rootListAllUsers.add(Collections.emptyList()); + } + mCombiner = new UserItemsCombiner(mResources, mDpm, mState) + .overrideCurrentUserForTest(PERSONAL_USER) + .setRootListForAllUsers(rootListAllUsers); + assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap)) + .comparingElementsUsing(ITEM_CORRESPONDENCE) + .containsExactlyElementsIn(WORK_ITEMS) + .inOrder(); + } + + @Test + public void testCreatePresentableListForAllUsers_currentIsWork_workItemsOnly() { + final List<List<Item>> rootListAllUsers = new ArrayList<>(); + rootListAllUsers.add(Collections.emptyList()); + rootListAllUsers.add(Lists.newArrayList(WORK_ITEMS)); + if (SdkLevel.isAtLeastV()) { + rootListAllUsers.add(Collections.emptyList()); + } + mCombiner = new UserItemsCombiner(mResources, mDpm, mState) + .overrideCurrentUserForTest(WORK_USER) + .setRootListForAllUsers(rootListAllUsers); + assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap)) + .comparingElementsUsing(ITEM_CORRESPONDENCE) + .containsExactlyElementsIn(WORK_ITEMS) + .inOrder(); + } + + @Test + public void testCreatePresentableListForAllUsers_currentIsPrivate_workItemsOnly() { + if (!SdkLevel.isAtLeastV()) return; + final List<List<Item>> rootListAllUsers = new ArrayList<>(); + rootListAllUsers.add(Collections.emptyList()); + rootListAllUsers.add(Lists.newArrayList(WORK_ITEMS)); + rootListAllUsers.add(Collections.emptyList()); + mCombiner = new UserItemsCombiner(mResources, mDpm, mState) + .overrideCurrentUserForTest(PRIVATE_USER) + .setRootListForAllUsers(rootListAllUsers); + assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap)) + .comparingElementsUsing(ITEM_CORRESPONDENCE) + .containsExactlyElementsIn(WORK_ITEMS) + .inOrder(); + } + + @Test public void testCreatePresentableList_currentIsPersonal_personalAndWorkItems() { mCombiner = new UserItemsCombiner(mResources, mDpm, mState) .setRootListForCurrentUser(PERSONAL_ITEMS) @@ -173,6 +313,89 @@ public class UserItemsCombinerTest { } @Test + public void testCreatePresentableListForAllUsers_currentIsPersonal_allUsersItems() { + final List<List<Item>> rootListAllUsers = new ArrayList<>(); + rootListAllUsers.add(PERSONAL_ITEMS); + rootListAllUsers.add(Lists.newArrayList(WORK_ITEMS)); + if (SdkLevel.isAtLeastV()) { + rootListAllUsers.add(PRIVATE_ITEMS); + } + mCombiner = new UserItemsCombiner(mResources, mDpm, mState) + .setRootListForAllUsers(rootListAllUsers); + + List<Item> expected = Lists.newArrayList(); + expected.add(new HeaderItem("Personal")); + expected.addAll(PERSONAL_ITEMS); + expected.add(new HeaderItem("Work")); + expected.addAll(WORK_ITEMS); + if (SdkLevel.isAtLeastV()) { + expected.add(new HeaderItem("Private")); + expected.addAll(PRIVATE_ITEMS); + } + + assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap)) + .comparingElementsUsing(ITEM_CORRESPONDENCE) + .containsExactlyElementsIn(expected) + .inOrder(); + } + + @Test + public void testCreatePresentableListForAllUsers_currentIsWork_allUsersItems() { + final List<List<Item>> rootListAllUsers = new ArrayList<>(); + rootListAllUsers.add(PERSONAL_ITEMS); + rootListAllUsers.add(Lists.newArrayList(WORK_ITEMS)); + if (SdkLevel.isAtLeastV()) { + rootListAllUsers.add(PRIVATE_ITEMS); + } + mCombiner = new UserItemsCombiner(mResources, mDpm, mState) + .overrideCurrentUserForTest(WORK_USER) + .setRootListForAllUsers(rootListAllUsers); + + List<Item> expected = Lists.newArrayList(); + expected.add(new HeaderItem("Personal")); + expected.addAll(PERSONAL_ITEMS); + expected.add(new HeaderItem("Work")); + expected.addAll(WORK_ITEMS); + if (SdkLevel.isAtLeastV()) { + expected.add(new HeaderItem("Private")); + expected.addAll(PRIVATE_ITEMS); + } + + assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap)) + .comparingElementsUsing(ITEM_CORRESPONDENCE) + .containsExactlyElementsIn(expected) + .inOrder(); + } + + @Test + public void testCreatePresentableListForAllUsers_currentIsPrivate_allUsersItems() { + final List<List<Item>> rootListAllUsers = new ArrayList<>(); + rootListAllUsers.add(PERSONAL_ITEMS); + rootListAllUsers.add(Lists.newArrayList(WORK_ITEMS)); + if (SdkLevel.isAtLeastV()) { + rootListAllUsers.add(PRIVATE_ITEMS); + } + mCombiner = new UserItemsCombiner(mResources, mDpm, mState) + .overrideCurrentUserForTest(PRIVATE_USER) + .setRootListForAllUsers(rootListAllUsers); + + List<Item> expected = Lists.newArrayList(); + expected.add(new HeaderItem("Personal")); + expected.addAll(PERSONAL_ITEMS); + expected.add(new HeaderItem("Work")); + expected.addAll(WORK_ITEMS); + if (SdkLevel.isAtLeastV()) { + expected.add(new HeaderItem("Private")); + expected.addAll(PRIVATE_ITEMS); + } + + assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap)) + .comparingElementsUsing(ITEM_CORRESPONDENCE) + .containsExactlyElementsIn(expected) + .inOrder(); + } + + @Test public void testCreatePresentableList_currentIsPersonal_personalAndWorkItems_cannotShare() { mState.canShareAcrossProfile = false; mCombiner = new UserItemsCombiner(mResources, mDpm, mState) @@ -196,6 +419,57 @@ public class UserItemsCombinerTest { assertThat(mCombiner.createPresentableList()).isEmpty(); } + @Test + public void testCreatePresentableListForAllUsers_currentIsPersonal_cannotShareToWork() { + if (!SdkLevel.isAtLeastV()) return; + mState.canForwardToProfileIdMap.put(WORK_USER, false); + final List<List<Item>> rootListAllUsers = new ArrayList<>(); + rootListAllUsers.add(PERSONAL_ITEMS); + rootListAllUsers.add(Lists.newArrayList(WORK_ITEMS)); + if (SdkLevel.isAtLeastV()) { + rootListAllUsers.add(PRIVATE_ITEMS); + } + mCombiner = new UserItemsCombiner(mResources, mDpm, mState) + .setRootListForAllUsers(rootListAllUsers); + + List<Item> expected = Lists.newArrayList(); + expected.add(new HeaderItem("Personal")); + expected.addAll(PERSONAL_ITEMS); + if (SdkLevel.isAtLeastV()) { + expected.add(new HeaderItem("Private")); + expected.addAll(PRIVATE_ITEMS); + } + + assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap)) + .comparingElementsUsing(ITEM_CORRESPONDENCE) + .containsExactlyElementsIn(expected) + .inOrder(); + } + + @Test + public void testCreatePresentableListForAllUsers_currentIsWork_AllItems_cannotSharePersonal() { + if (!SdkLevel.isAtLeastV()) return; + mState.canForwardToProfileIdMap.put(PERSONAL_USER, false); + // In the current implementation of cross profile content sharing strategy work profile will + // be able to share to all the child profiles of the parent/personal profile only if it is + // able to share with parent/personal profile + mState.canForwardToProfileIdMap.put(PRIVATE_USER, false); + final List<List<Item>> rootListAllUsers = new ArrayList<>(); + rootListAllUsers.add(PERSONAL_ITEMS); + rootListAllUsers.add(Lists.newArrayList(WORK_ITEMS)); + if (SdkLevel.isAtLeastV()) { + rootListAllUsers.add(PRIVATE_ITEMS); + } + mCombiner = new UserItemsCombiner(mResources, mDpm, mState) + .overrideCurrentUserForTest(WORK_USER) + .setRootListForAllUsers(rootListAllUsers); + + assertThat(mCombiner.createPresentableListForAllUsers(mUserIds, mUserIdToLabelMap)) + .comparingElementsUsing(ITEM_CORRESPONDENCE) + .containsExactlyElementsIn(WORK_ITEMS) + .inOrder(); + } + private static TestItem personalItem(String title) { return new TestItem(title, PERSONAL_USER); } @@ -204,6 +478,10 @@ public class UserItemsCombinerTest { return new TestItem(title, WORK_USER); } + private static TestItem privateItem(String title) { + return new TestItem(title, PRIVATE_USER); + } + private static class TestItem extends Item { TestItem(String title, UserId userId) { diff --git a/tests/unit/com/android/documentsui/sorting/SortingCursorWrapperTest.java b/tests/unit/com/android/documentsui/sorting/SortingCursorWrapperTest.java index e323dc8e8..72ad1b774 100644 --- a/tests/unit/com/android/documentsui/sorting/SortingCursorWrapperTest.java +++ b/tests/unit/com/android/documentsui/sorting/SortingCursorWrapperTest.java @@ -34,7 +34,6 @@ import androidx.test.runner.AndroidJUnit4; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.Shared; import com.android.documentsui.roots.RootCursorWrapper; -import com.android.documentsui.sorting.SortModel.SortDimensionId; import com.android.documentsui.testing.SortModels; import com.android.documentsui.testing.TestFileTypeLookup; @@ -497,7 +496,7 @@ public class SortingCursorWrapperTest { } private Cursor createSortingCursorWrapper(Cursor c) { - final @SortDimensionId int id = sortModel.getSortedDimensionId(); + final int id = sortModel.getSortedDimensionId(); return new SortingCursorWrapper(c, sortModel.getDimensionById(id), fileTypeLookup); } } diff --git a/trace.sh b/trace.sh new file mode 100755 index 000000000..573d92362 --- /dev/null +++ b/trace.sh @@ -0,0 +1,3 @@ +$ANDROID_BUILD_TOP/external/perfetto/tools/record_android_trace \ + -c $ANDROID_BUILD_TOP/packages/apps/DocumentsUI/perfetto_config.pbtx \ + -o /tmp/perfetto-traces/docsui-$(date +"%d-%m-%Y_%H-%M-%S").perfetto-trace |