diff options
185 files changed, 3274 insertions, 1420 deletions
diff --git a/flags.aconfig b/flags.aconfig index 21fc9567c..1e31323a5 100644 --- a/flags.aconfig +++ b/flags.aconfig @@ -10,10 +10,11 @@ flag { } flag { - name: "use_search_v2_rw" + name: "use_search_v2_read_only" namespace: "documentsui" - description: "Read/write flag that enables the next generation search functionality." + description: "Enables the next generation search functionality." bug: "383412640" + is_fixed_read_only: true } flag { diff --git a/proguard.flags b/proguard.flags index 76449d4e9..34071fa6d 100644 --- a/proguard.flags +++ b/proguard.flags @@ -106,6 +106,7 @@ int dir_menu_view_in_owner; int drawer_layout; int inspector_details_view; + int job_progress_panel_title; int option_menu_create_dir; int option_menu_debug; int option_menu_extract_all; 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/breadcrumb_item_ripple_color.xml index e4e1edc48..1ca24551e 100644 --- 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/breadcrumb_item_ripple_color.xml @@ -1,5 +1,6 @@ -<?xml version="1.0" encoding="utf-8"?><!-- - Copyright 2018 The Android Open Source Project +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2025 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,6 +16,5 @@ --> <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" /> + <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/fragment_pick_button_background_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/fragment_pick_button_background_color.xml deleted file mode 100644 index cf6d480ea..000000000 --- a/res/flag(com.android.documentsui.flags.use_material3)/color/fragment_pick_button_background_color.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?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/horizontal_breadcrumb_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/horizontal_breadcrumb_color.xml index ab511326d..f615b257c 100644 --- 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 @@ -15,7 +15,7 @@ --> <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" /> + <item android:state_enabled="false" + android:color="?attr/colorOnSurface" /> + <item android:color="?attr/colorOnSurfaceVariant" /> </selector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/list_item_ripple_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/list_item_ripple_color.xml index 6c2d0714e..85e5b46ce 100644 --- a/res/flag(com.android.documentsui.flags.use_material3)/color/list_item_ripple_color.xml +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/list_item_ripple_color.xml @@ -17,6 +17,10 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="false" android:color="@android:color/transparent" /> + <!-- By default <ripple> introduces a gray-ish layer for the focused state which we don't + want, hence explicitly setting focused ripple color to transparent to get rid of that. + --> + <item android:state_focused="true" android:color="@android:color/transparent" /> <item android:state_selected="true" android:alpha="@dimen/ripple_overlay_alpha" android:color="?attr/colorOnPrimaryContainer" /> <item android:alpha="@dimen/ripple_overlay_alpha" 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 index 8e6282199..3ca0191cd 100644 --- 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 @@ -17,25 +17,37 @@ <ripple xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" - android:color="?attr/colorControlHighlight"> + android:color="@color/breadcrumb_item_ripple_color"> <item android:id="@android:id/mask" - android:drawable="@android:color/white"/> + android:drawable="@drawable/breadcrumb_item_mask"/> <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 android:state_pressed="true"> + <shape android:tint="?attr/colorOnSurfaceVariant"> + <corners android:radius="@dimen/breadcrumb_item_height" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + <item android:state_focused="true"> + <shape> + <corners android:radius="@dimen/breadcrumb_item_height" /> + <stroke + android:width="@dimen/focus_ring_width" + android:color="?attr/colorSecondary" /> + </shape> + </item> + <item android:state_hovered="true"> + <shape android:tint="?attr/colorOnSurfaceVariant"> + <corners android:radius="@dimen/breadcrumb_item_height" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + + <!-- Default: use the container background. --> + <item> + <color android:color="@android:color/transparent"/> </item> </selector> </item> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/breadcrumb_item_mask.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/breadcrumb_item_mask.xml new file mode 100644 index 000000000..c64be0765 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/breadcrumb_item_mask.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <corners android:radius="@dimen/breadcrumb_item_height" /> + <!-- 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/drag_file_counter_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/drag_file_counter_background.xml new file mode 100644 index 000000000..e7e02ee7d --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/drag_file_counter_background.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="@color/drag_file_counter_background" /> + <corners android:radius="@dimen/drag_file_counter_height" /> +</shape> 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 index eed005eca..0052f4609 100644 --- 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 @@ -17,9 +17,5 @@ <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"/> + <corners android:radius="@dimen/drag_content_radius" /> </shape> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/drop_badge_container_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/drop_badge_container_background.xml new file mode 100644 index 000000000..7dff0ada8 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/drop_badge_container_background.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:bottom="@dimen/drop_icon_offset" + android:left="0dp" + android:right="@dimen/drop_icon_offset" + android:top="0dp"> + <shape android:shape="rectangle"> + <corners android:radius="@dimen/drop_mime_icon_wrapper_radius" /> + <solid android:color="@color/drag_mime_icon_wrapper_background" /> + </shape> + </item> +</layer-list>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/grid_nameplate_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/grid_nameplate_background.xml index 4a25b9a02..502efaede 100644 --- a/res/flag(com.android.documentsui.flags.use_material3)/drawable/grid_nameplate_background.xml +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/grid_nameplate_background.xml @@ -16,10 +16,125 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <!-- selected --> + <item + android:state_focused="true" + android:state_hovered="true" + android:state_selected="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/grid_item_nameplate_inner_radius" /> + <solid android:color="?attr/colorPrimaryContainer" /> + </shape> + </item> + <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 android:tint="?attr/colorOnPrimaryContainer"> + <corners android:radius="@dimen/grid_item_nameplate_inner_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + <item> + <shape> + <corners android:radius="@dimen/grid_item_nameplate_radius" /> + <stroke + android:width="@dimen/focus_ring_width" + android:color="?attr/colorSecondary" /> + </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/grid_item_nameplate_inner_radius" /> + <solid android:color="?attr/colorPrimaryContainer" /> + </shape> + </item> + <item> + <shape> + <corners android:radius="@dimen/grid_item_nameplate_radius" /> + <stroke + android:width="@dimen/focus_ring_width" + android:color="?attr/colorSecondary" /> + </shape> + </item> + </layer-list> + </item> + <item + android:state_hovered="true" + android:state_selected="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/grid_item_nameplate_radius" /> + <solid android:color="?attr/colorPrimaryContainer" /> + </shape> + </item> + <item> + <shape android:tint="?attr/colorOnPrimaryContainer"> + <corners android:radius="@dimen/grid_item_nameplate_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + </layer-list> + </item> <item android:state_selected="true"> <shape> <corners android:radius="@dimen/grid_item_nameplate_radius" /> <solid android:color="?attr/colorPrimaryContainer" /> </shape> </item> + + <!-- unselected --> + <item + android:state_focused="true" + android:state_hovered="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 android:tint="?attr/colorOnSurface"> + <corners android:radius="@dimen/grid_item_nameplate_inner_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + <item> + <shape> + <corners android:radius="@dimen/grid_item_nameplate_radius" /> + <stroke + android:width="@dimen/focus_ring_width" + android:color="?attr/colorSecondary" /> + </shape> + </item> + </layer-list> + </item> + <item android:state_focused="true"> + <shape> + <corners android:radius="@dimen/grid_item_nameplate_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/grid_item_nameplate_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> </selector>
\ 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 index 5305b4ae3..8a4aea8ac 100644 --- 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 @@ -15,12 +15,12 @@ --> <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"> + android:width="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960" + android:autoMirrored="true"> <path - android:fillColor="?android:attr/colorControlNormal" - android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6 -6,-6z"/> + android:fillColor="?attr/colorSecondary" + android:pathData="M504,480L320,296L376,240L616,480L376,720L320,664L504,480Z"/> </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 index 370c4fe70..c929806fe 100644 --- 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 @@ -14,24 +14,19 @@ Copyright (C) 2024 The Android Open Source Project 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"> + android:width="14dp" + android:height="14dp" + android:viewportWidth="14" + android:viewportHeight="14"> <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" /> + android:pathData="M7,0L7,0A7,7 0,0 1,14 7L14,7A7,7 0,0 1,7 14L7,14A7,7 0,0 1,0 7L0,7A7,7 0,0 1,7 0z" + android:fillColor="@color/drop_icon_copy_container_background"/> + <group> + <clip-path + android:pathData="M1,1h12v12h-12z"/> + <path + android:pathData="M6.387,11.438V7.613H2.563V6.387H6.387V2.563H7.613V6.387H11.438V7.613H7.613V11.438H6.387Z" + android:fillColor="@color/drop_icon_symbol_color"/> </group> </vector> + 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 index 06db34617..ea2c3950c 100644 --- 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 @@ -15,24 +15,18 @@ Copyright (C) 2024 The Android Open Source Project --> <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"> + android:width="14dp" + android:height="14dp" + android:viewportWidth="14" + android:viewportHeight="14"> + <path + android:pathData="M7,0L7,0A7,7 0,0 1,14 7L14,7A7,7 0,0 1,7 14L7,14A7,7 0,0 1,0 7L0,7A7,7 0,0 1,7 0z" + android:fillColor="@color/drop_icon_reject_container_background"/> + <group> + <clip-path + android:pathData="M1,1h12v12h-12z"/> <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" /> + android:pathData="M7,12.038C6.308,12.038 5.654,11.908 5.037,11.65C4.429,11.383 3.896,11.021 3.438,10.563C2.979,10.096 2.617,9.558 2.35,8.95C2.092,8.333 1.962,7.679 1.962,6.988C1.962,6.287 2.092,5.637 2.35,5.037C2.617,4.429 2.979,3.896 3.438,3.438C3.896,2.979 4.429,2.621 5.037,2.362C5.654,2.096 6.308,1.962 7,1.962C7.7,1.962 8.354,2.096 8.962,2.362C9.571,2.621 10.104,2.979 10.563,3.438C11.021,3.896 11.379,4.429 11.637,5.037C11.904,5.637 12.038,6.287 12.038,6.988C12.038,7.679 11.904,8.333 11.637,8.95C11.379,9.558 11.021,10.096 10.563,10.563C10.104,11.021 9.571,11.383 8.962,11.65C8.354,11.908 7.7,12.038 7,12.038ZM7,10.813C7.417,10.813 7.817,10.75 8.2,10.625C8.583,10.5 8.925,10.317 9.225,10.075L3.912,4.762C3.679,5.079 3.5,5.425 3.375,5.8C3.25,6.175 3.188,6.571 3.188,6.988C3.188,8.046 3.558,8.95 4.3,9.7C5.042,10.442 5.942,10.813 7,10.813ZM10.087,9.212C10.321,8.896 10.5,8.55 10.625,8.175C10.75,7.8 10.813,7.404 10.813,6.988C10.813,5.929 10.442,5.033 9.7,4.3C8.958,3.558 8.058,3.188 7,3.188C6.583,3.188 6.188,3.25 5.813,3.375C5.446,3.492 5.104,3.662 4.787,3.888L10.087,9.212Z" + android:fillColor="@color/drop_icon_symbol_color"/> </group> </vector> 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 index c986d6579..9affe2bb9 100644 --- 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 @@ -16,9 +16,10 @@ <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:viewportWidth="960" + android:viewportHeight="960"> <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"/> + android:fillColor="?attr/colorOnSurface" + android:pathData="M480,640Q555,640 607.5,587.5Q660,535 660,460Q660,385 607.5,332.5Q555,280 480,280Q405,280 352.5,332.5Q300,385 300,460Q300,535 352.5,587.5Q405,640 480,640ZM480,568Q435,568 403.5,536.5Q372,505 372,460Q372,415 403.5,383.5Q435,352 480,352Q525,352 556.5,383.5Q588,415 588,460Q588,505 556.5,536.5Q525,568 480,568ZM480,760Q334,760 214,678.5Q94,597 40,460Q94,323 214,241.5Q334,160 480,160Q626,160 746,241.5Q866,323 920,460Q866,597 746,678.5Q626,760 480,760ZM480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460ZM480,680Q593,680 687.5,620.5Q782,561 832,460Q782,359 687.5,299.5Q593,240 480,240Q367,240 272.5,299.5Q178,359 128,460Q178,561 272.5,620.5Q367,680 480,680Z" /> </vector> + 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 index 31bbec1f2..79c2eb1b7 100644 --- 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 @@ -26,6 +26,41 @@ <item> <selector> <!-- Selected --> + <item + android:state_selected="true" + android:state_focused="true" + android:state_hovered="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 + 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 android:tint="?attr/colorOnPrimaryContainer"> + <corners android:radius="@dimen/list_item_height" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </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_drag_hovered="true"> <layer-list> <item> @@ -104,6 +139,28 @@ </item> <!-- Unselected --> + <item android:state_focused="true" android:state_hovered="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 android:tint="?attr/colorOnSurface"> + <corners android:radius="@dimen/list_item_height" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </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_drag_hovered="true"> <shape android:tint="?attr/colorOnSurface"> <corners android:radius="@dimen/list_item_height" /> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout-w600dp/fragment_save_cancel_button.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout-w600dp/fragment_save_cancel_button.xml new file mode 100644 index 000000000..93245946c --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout-w600dp/fragment_save_cancel_button.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<com.google.android.material.button.MaterialButton + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@android:id/button2" + style="@style/MaterialTonalButton" + app:cornerRadius="@dimen/button_corner_radius" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/picker_saver_button_gap" + android:layout_marginEnd="@dimen/picker_saver_button_gap" + android:text="@android:string/cancel"/> 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 index c692b4124..dcd3283b4 100644 --- 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 @@ -27,111 +27,103 @@ android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="@dimen/doc_header_height" - android:paddingHorizontal="@dimen/list_container_padding" + android:baselineAligned="false" + android:gravity="center_vertical" + android:paddingStart="@dimen/table_header_padding_start" + android:paddingEnd="@dimen/table_header_padding_end" android:visibility="gone"> - + <!-- Placeholder for MIME/thumbnail icon --> + <View + android:layout_width="@dimen/list_item_icon_size" + android:layout_height="@dimen/list_item_icon_size" + android:layout_gravity="center_vertical" + android:layout_marginEnd="@dimen/list_item_icon_margin_end" + android:layout_marginStart="0dp"/> + + <!-- Column headers --> <LinearLayout - android:layout_width="match_parent" + android:layout_width="0dp" 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:layout_weight="1" android:orientation="horizontal"> - <!-- Placeholder for MIME/thumbnail icon --> - <View - android:layout_width="@dimen/list_item_icon_size" - android:layout_height="@dimen/list_item_icon_size" - android:layout_gravity="center_vertical" - android:layout_marginEnd="@dimen/list_item_icon_margin_end" - android:layout_marginStart="0dp"/> - - <!-- Column headers --> - <LinearLayout + + <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="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: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: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: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> - - <!-- Placeholder for preview icon in picker mode --> - <View - android:id="@+id/preview_icon_placeholder" - 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:layout_weight="0.2" + 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: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: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> + + <!-- Placeholder for preview icon in picker mode --> + <View + android:id="@+id/preview_icon_placeholder" + 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" /> </LinearLayout>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/additional_drag_shadow.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/additional_drag_shadow.xml new file mode 100644 index 000000000..e829baefd --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/additional_drag_shadow.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- Transparent container so shadow layer can be drawn --> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="@dimen/drag_shadow_width" + android:layout_height="@dimen/drag_shadow_height" + android:background="@color/item_drag_shadow_container_background"> + + <View + android:layout_width="@dimen/drag_content_width" + android:layout_height="@dimen/drag_content_height" + android:layout_marginTop="@dimen/drag_additional_layer_margin_top" + android:layout_marginStart="@dimen/drag_shadow_radius" + android:background="@drawable/drag_shadow_background" /> +</FrameLayout>
\ 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 index fde349b88..18a8dc8f7 100644 --- 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 @@ -15,6 +15,39 @@ 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 /> +<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:baselineAligned="false" + android:gravity="center_vertical" + android:paddingStart="@dimen/table_header_padding_start" + android:paddingEnd="@dimen/table_header_padding_end" + android:background="?attr/colorSurfaceBright" + android:visibility="gone"> + + <!-- Placeholder for MIME/thumbnail icon --> + <View + android:layout_width="@dimen/list_item_icon_size" + android:layout_height="@dimen/list_item_icon_size" + android:layout_gravity="center_vertical" + android:layout_marginEnd="@dimen/list_item_icon_margin_end" + android:layout_marginStart="0dp"/> + + <!-- Column headers: Name only for compact/medium size screen --> + <com.android.documentsui.sorting.HeaderCell + android:id="@android:id/title" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + 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>
\ No newline at end of file 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 index 54a6a7cb2..94e4b953d 100644 --- 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 @@ -23,29 +23,40 @@ android:layout_height="wrap_content" android:touchscreenBlocksFocus="false"> + <!-- Technically we don't need this CollapsingToolbarLayout wrapper when use_material3 flag + is ON, because we don't want to hide anything in the app header area when scrolling, but + some files (e.g. NavigationViewManager and others) uses the existence of this element to + do some specific logic, hence leaving it here with "noScroll" behavior. + --> <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"> + app:layout_scrollFlags="noScroll"> - <androidx.core.widget.NestedScrollView + <LinearLayout android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + android:orientation="vertical" + android:background="?attr/colorSurfaceBright"> <include layout="@layout/directory_header" /> - <!-- column headers are empty on small screens, in portrait or in grid mode. --> + <com.google.android.material.divider.MaterialDivider + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:dividerColor="?attr/colorSurfaceContainer" + app:dividerThickness="@dimen/main_container_section_gap" /> + <include layout="@layout/column_headers"/> - </androidx.core.widget.NestedScrollView> + </LinearLayout> <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 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 index c3de2399c..8181cd403 100644 --- 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 @@ -15,34 +15,53 @@ --> <!-- Transparent container so shadow layer can be drawn --> -<LinearLayout +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:padding="8dp" + android:layout_width="@dimen/drag_shadow_width" + android:layout_height="@dimen/drag_shadow_height" 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:layout_width="@dimen/drag_content_width" + android:layout_height="@dimen/drag_content_height" + android:layout_marginTop="@dimen/drag_file_counter_offset" + android:layout_marginStart="@dimen/drag_content_margin_start" + android:paddingHorizontal="@dimen/space_extra_small_4" android:orientation="horizontal" android:gravity="center_vertical" android:background="@drawable/drag_shadow_background"> - <include layout="@layout/drop_badge"/> + <LinearLayout + android:layout_width="@dimen/drop_badge_container_size" + android:layout_height="@dimen/drop_badge_container_size" + android:orientation="horizontal" + android:gravity="center_horizontal" + android:background="@drawable/drop_badge_container_background"> + + <include layout="@layout/drop_badge"/> + + </LinearLayout> + <TextView android:id="@android:id/title" - android:layout_width="match_parent" + android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_marginStart="@dimen/space_extra_small_4" android:maxLines="1" android:ellipsize="end" android:textAlignment="viewStart" - android:textAppearance="@style/Subhead" - android:paddingStart="6dp" - android:paddingBottom="1dp"/> + android:textAppearance="@style/DragBadgeText" /> </LinearLayout> -</LinearLayout> + + <TextView + android:id="@+id/drag_file_counter" + android:layout_width="wrap_content" + android:layout_height="@dimen/drag_file_counter_height" + android:paddingHorizontal="@dimen/space_extra_small_4" + android:layout_gravity="top|end" + android:background="@drawable/drag_file_counter_background" + android:textAppearance="@style/DragCounterText" + android:visibility="gone" /> +</FrameLayout> 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 index c13f68132..0fe74fe64 100644 --- 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 @@ -40,7 +40,6 @@ <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingBottom="@dimen/file_area_padding_bottom" app:layout_behavior="@string/scrolling_behavior"> <FrameLayout @@ -66,21 +65,34 @@ </FrameLayout> <!-- Footer of right hand side: Breadcrumbs and Picker footer. --> - <com.android.documentsui.HorizontalBreadcrumb - android:id="@+id/horizontal_breadcrumb" + <LinearLayout + android:id="@+id/bottom_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_gravity="bottom" - android:background="?attr/colorSurfaceBright" - /> + android:orientation="vertical" + android:layout_gravity="bottom"> - <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" - /> + <com.google.android.material.divider.MaterialDivider + android:id="@+id/breadcrumb_top_divider" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:dividerColor="?attr/colorSurfaceContainer" + app:dividerThickness="@dimen/main_container_section_gap" /> + + <com.android.documentsui.HorizontalBreadcrumb + android:id="@+id/horizontal_breadcrumb" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?attr/colorSurfaceBright" + android:paddingHorizontal="@dimen/breadcrumb_padding_horizontal" /> + + <androidx.coordinatorlayout.widget.CoordinatorLayout + android:id="@+id/container_save" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?attr/colorSurfaceContainer" /> + + </LinearLayout> <!-- Top section: toolbar, search chips, profile tab --> <include layout="@layout/directory_app_bar"/> 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 index e2f0d35cd..a4210d07c 100644 --- 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 @@ -17,8 +17,8 @@ <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:layout_width="match_parent" + android:layout_height="match_parent" 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 index d3b66494f..4445dd1a6 100644 --- 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 @@ -32,7 +32,6 @@ 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" @@ -116,7 +115,8 @@ <com.android.documentsui.HorizontalBreadcrumb android:id="@+id/horizontal_breadcrumb" android:layout_width="match_parent" - android:layout_height="wrap_content" /> + android:layout_height="wrap_content" + android:paddingHorizontal="@dimen/breadcrumb_padding_horizontal" /> </LinearLayout> @@ -124,7 +124,7 @@ android:id="@+id/container_save" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="?android:attr/colorBackgroundFloating" + android:background="?attr/colorSurfaceContainer" android:elevation="8dp" /> </LinearLayout> 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 index 742861a3e..5923bf9eb 100644 --- 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 @@ -13,48 +13,58 @@ limitations under the License. --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +<androidx.constraintlayout.widget.ConstraintLayout + 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" /> + android:paddingTop="@dimen/picker_saver_container_padding_top" + android:paddingBottom="@dimen/picker_saver_container_padding_bottom"> - <FrameLayout + <LinearLayout android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="wrap_content" + android:orientation="horizontal" + android:baselineAligned="false" + android:background="?attr/colorSurfaceContainer" + android:gravity="center_vertical|end" + android:paddingStart="@dimen/bottom_bar_padding" + android:paddingEnd="@dimen/bottom_bar_padding" + android:paddingTop="@dimen/picker_saver_padding_top" + android:paddingBottom="@dimen/picker_saver_padding_bottom"> + + <com.google.android.material.button.MaterialButton + android:id="@android:id/button2" + style="@style/MaterialTonalButton" + app:cornerRadius="@dimen/button_corner_radius" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/picker_saver_button_gap" + android:layout_marginEnd="@dimen/picker_saver_button_gap" + android:text="@android:string/cancel" /> <com.google.android.material.button.MaterialButton android:id="@android:id/button1" - style="?attr/materialButtonStyle" + style="@style/MaterialButton" 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" /> + android:layout_marginStart="@dimen/picker_saver_button_gap" + android:layout_marginEnd="@dimen/picker_saver_button_gap" /> - <!-- 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" /> + </LinearLayout> - </FrameLayout> + <!-- Handles touch events when button1 is disabled. --> + <View + android:id="@+id/pick_button_overlay" + android:layout_width="0dp" + android:layout_height="0dp" + android:background="@android:color/transparent" + android:visibility="gone" + android:importantForAccessibility="no" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent"/> -</LinearLayout> +</androidx.constraintlayout.widget.ConstraintLayout> 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 index 401eaec88..3270b183c 100644 --- 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 @@ -18,50 +18,49 @@ 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"> + android:paddingTop="@dimen/picker_saver_container_padding_top" + android:paddingBottom="@dimen/picker_saver_container_padding_bottom"> - <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" + <LinearLayout + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_weight="1" - android:singleLine="true" - android:selectAllOnFocus="true" /> + android:paddingTop="@dimen/picker_saver_padding_top" + android:paddingBottom="@dimen/picker_saver_padding_bottom" + android:paddingEnd="@dimen/bottom_bar_padding" + android:orientation="horizontal" + android:baselineAligned="false" + android:gravity="center_vertical|end" + android:paddingStart="@dimen/list_item_padding"> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/title_wrapper" + style="?attr/textInputFilledStyle" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_marginEnd="@dimen/picker_saver_button_gap" + android:hint="@string/file_name_hint"> + <com.google.android.material.textfield.TextInputEditText + android:id="@android:id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:singleLine="true" + android:selectAllOnFocus="true" /> + </com.google.android.material.textfield.TextInputLayout> - <FrameLayout - android:layout_width="wrap_content" - android:layout_height="match_parent"> + <include layout="@layout/fragment_save_cancel_button" /> <com.google.android.material.button.MaterialButton android:id="@android:id/button1" - style="@style/Widget.Material3.Button.UnelevatedButton" + style="@style/MaterialButton" 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:layout_marginStart="@dimen/picker_saver_button_gap" + android:layout_marginEnd="@dimen/picker_saver_button_gap" android:text="@string/menu_save"/> - <ProgressBar + <com.google.android.material.progressindicator.CircularProgressIndicator android:id="@android:id/progress" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -69,8 +68,8 @@ android:visibility="gone" android:indeterminate="true" android:padding="8dp" - style="?android:attr/progressBarStyle" /> + app:trackColor="?attr/colorSecondaryContainer" /> - </FrameLayout> + </LinearLayout> </LinearLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_save_cancel_button.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_save_cancel_button.xml new file mode 100644 index 000000000..5179630c9 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_save_cancel_button.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<!-- The "Cancel" button is default invisible. On form factors with FEATURE_PC set, it is + updated to be shown always. --> +<com.google.android.material.button.MaterialButton + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@android:id/button2" + style="@style/Widget.Material3.Button.TonalButton" + 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:visibility="gone" + android:text="@android:string/cancel"/>
\ 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 index 574978c74..7d40f794b 100644 --- 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 @@ -14,171 +14,162 @@ limitations under the License. --> -<com.google.android.material.card.MaterialCardView - xmlns:android="http://schemas.android.com/apk/res/android" +<RelativeLayout 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="@dimen/grid_item_width" - android:layout_height="@dimen/grid_item_height" - android:layout_margin="@dimen/grid_item_layout_margin" + android:layout_width="@dimen/grid_width" + android:layout_height="@dimen/grid_height" + android:layout_margin="@dimen/grid_item_margin" android:clickable="true" + android:defaultFocusHighlightEnabled="false" android:focusable="true" - app:cardBackgroundColor="@android:color/transparent" - app:cardElevation="0dp" - app:strokeWidth="0dp"> - - <RelativeLayout - android:id="@+id/grid_item_layout" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginStart="@dimen/grid_item_layout_marginStart" - android:layout_marginEnd="@dimen/grid_item_layout_marginEnd" - android:layout_marginTop="@dimen/grid_item_layout_marginTop"> - - <!-- 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="@dimen/grid_item_thumbnail_width" - android:layout_height="@dimen/grid_item_thumbnail_height" - android:layout_centerHorizontal="true" - android:background="@drawable/grid_thumbnail_background"> - - <!-- stroke width will be controlled dynamically in the code. --> - <com.google.android.material.card.MaterialCardView - android:id="@+id/icon_wrapper" - android:layout_width="@dimen/grid_item_icon_width" - android:layout_height="@dimen/grid_item_icon_height" + android:paddingEnd="@dimen/grid_item_padding_end" + android:paddingStart="@dimen/grid_item_padding_start" + android:paddingTop="@dimen/grid_item_padding_top"> + +<!-- 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="@dimen/grid_item_thumbnail_width" + android:layout_height="@dimen/grid_item_thumbnail_height" + android:layout_centerHorizontal="true" + android:background="@drawable/grid_thumbnail_background"> + + <!-- stroke width will be controlled dynamically in the code. --> + <com.google.android.material.card.MaterialCardView + android:id="@+id/icon_wrapper" + android:layout_width="@dimen/grid_item_icon_width" + android:layout_height="@dimen/grid_item_icon_height" + android:layout_gravity="center" + app:cardBackgroundColor="?attr/colorSurfaceContainerLowest" + app:cardElevation="0dp" + app:strokeColor="?attr/colorSecondaryContainer" + app:strokeWidth="0dp"> + + <com.android.documentsui.GridItemThumbnail + android:id="@+id/icon_thumb" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:contentDescription="@null" + android:scaleType="centerCrop" + 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" - app:cardBackgroundColor="?attr/colorSurfaceContainerLowest" - app:cardElevation="0dp" - app:strokeColor="?attr/colorSecondaryContainer" - app:strokeWidth="0dp"> - - <com.android.documentsui.GridItemThumbnail - android:id="@+id/icon_thumb" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:contentDescription="@null" - android:scaleType="centerCrop" - 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:contentDescription="@null" - android:scaleType="fitCenter" /> - - </com.google.android.material.card.MaterialCardView> - - </FrameLayout> - - <FrameLayout - android:id="@+id/preview_icon" - android:layout_width="@dimen/button_touch_size" - android:layout_height="@dimen/button_touch_size" - android:layout_alignParentEnd="true" - android:layout_alignParentTop="true" - android:clickable="true" - android:focusable="true" - android:pointerIcon="hand"> + android:contentDescription="@null" + android:scaleType="fitCenter" /> + + </com.google.android.material.card.MaterialCardView> + + </FrameLayout> + + <FrameLayout + android:id="@+id/preview_icon" + android:layout_width="@dimen/button_touch_size" + android:layout_height="@dimen/button_touch_size" + android:layout_alignParentEnd="true" + android:layout_alignParentTop="true" + android:clickable="true" + android:focusable="true" + android:pointerIcon="hand"> + + <ImageView + android:layout_width="@dimen/zoom_icon_size" + android:layout_height="@dimen/zoom_icon_size" + android:layout_gravity="center" + android:background="@drawable/circle_button_background" + android:padding="2dp" + android:scaleType="fitCenter" + android:src="@drawable/ic_zoom_out" /> + + </FrameLayout> + + <!-- Item nameplate. Has some text fields (title, size, mod-time, etc). --> + + <LinearLayout + android:id="@+id/nameplate" + android:layout_width="@dimen/grid_item_nameplate_width" + android:layout_height="@dimen/grid_item_nameplate_height" + android:layout_below="@id/thumbnail" + android:layout_marginTop="@dimen/grid_item_nameplate_marginTop" + android:background="@drawable/grid_nameplate_background" + android:orientation="vertical" + android:duplicateParentState="true" + android:padding="@dimen/grid_item_nameplate_padding"> + + <!-- Top row. --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:orientation="horizontal"> <ImageView - android:layout_width="@dimen/zoom_icon_size" - android:layout_height="@dimen/zoom_icon_size" - android:layout_gravity="center" - android:background="@drawable/circle_button_background" - android:padding="2dp" - android:scaleType="fitCenter" - android:src="@drawable/ic_zoom_out" /> - - </FrameLayout> + android:id="@+id/icon_profile_badge" + android:layout_width="@dimen/briefcase_icon_size" + android:layout_height="@dimen/briefcase_icon_size" + android:layout_marginEnd="@dimen/briefcase_icon_margin" + android:contentDescription="@string/a11y_work" + android:gravity="center_vertical" + android:src="@drawable/ic_briefcase" + android:tint="?android:attr/colorAccent" /> + + <TextView + android:id="@android:id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ellipsize="end" + android:singleLine="true" + android:textAlignment="center" + android:textAppearance="@style/FileItemLabelText" /> - <!-- Item nameplate. Has some text fields (title, size, mod-time, etc). --> + </LinearLayout> + <!-- Bottom row. --> <LinearLayout - android:id="@+id/nameplate" - android:layout_width="@dimen/grid_item_nameplate_width" - android:layout_height="@dimen/grid_item_nameplate_height" - android:layout_below="@id/thumbnail" - android:layout_marginTop="@dimen/grid_item_nameplate_marginTop" - android:background="@drawable/grid_nameplate_background" - android:orientation="vertical" - android:padding="@dimen/grid_item_nameplate_padding"> - - <!-- Top row. --> - <LinearLayout - android:layout_width="match_parent" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:orientation="horizontal"> + + <TextView + android:id="@+id/details" + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:gravity="center" - android:orientation="horizontal"> - - <ImageView - android:id="@+id/icon_profile_badge" - android:layout_width="@dimen/briefcase_icon_size" - android:layout_height="@dimen/briefcase_icon_size" - android:layout_marginEnd="@dimen/briefcase_icon_margin" - android:contentDescription="@string/a11y_work" - android:gravity="center_vertical" - android:src="@drawable/ic_briefcase" - android:tint="?android:attr/colorAccent" /> - - <TextView - android:id="@android:id/title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:ellipsize="end" - android:singleLine="true" - android:textAlignment="center" - android:textAppearance="@style/FileItemLabelText" /> - - </LinearLayout> - - <!-- Bottom row. --> - <LinearLayout - android:layout_width="match_parent" + android:layout_marginEnd="4dp" + android:ellipsize="end" + android:singleLine="true" + android:textAlignment="viewStart" + android:textAppearance="@style/ItemCaptionText" /> + + <TextView + android:id="@+id/bullet" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="4dp" + android:singleLine="true" + android:text="@string/bullet" + android:textAlignment="viewStart" + android:textAppearance="@style/ItemCaptionText" /> + + <TextView + android:id="@+id/date" + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:gravity="center" - android:orientation="horizontal"> - - <TextView - android:id="@+id/details" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginEnd="4dp" - android:ellipsize="end" - android:singleLine="true" - android:textAlignment="viewStart" - android:textAppearance="@style/ItemCaptionText" /> - - <TextView - android:id="@+id/bullet" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginEnd="4dp" - android:singleLine="true" - android:text="@string/bullet" - android:textAlignment="viewStart" - android:textAppearance="@style/ItemCaptionText" /> - - <TextView - android:id="@+id/date" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:ellipsize="end" - android:singleLine="true" - android:textAlignment="viewStart" - android:textAppearance="@style/ItemCaptionText" /> - - </LinearLayout> + android:ellipsize="end" + android:singleLine="true" + android:textAlignment="viewStart" + android:textAppearance="@style/ItemCaptionText" /> </LinearLayout> - </RelativeLayout> + </LinearLayout> -</com.google.android.material.card.MaterialCardView> +</RelativeLayout>
\ No newline at end of file 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 index 26f5a8ee7..9cf92940c 100644 --- 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 @@ -19,7 +19,7 @@ android:id="@android:id/empty" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="?android:attr/colorBackground" + android:background="?attr/colorSurfaceBright" android:focusable="true"> <include android:id="@+id/content" layout="@layout/item_doc_inflated_message_content"/> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/job_progress_panel.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/job_progress_panel.xml new file mode 100644 index 000000000..17f6aa6fc --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/job_progress_panel.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <com.google.android.material.card.MaterialCardView + style="@style/JobProgressPanelStyle" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <LinearLayout + 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:id="@+id/job_progress_panel_title" + android:text="@string/job_progress_panel_title" + android:textAppearance="@style/JobProgressPanelHeaderText" + android:layout_margin="@dimen/job_progress_panel_header_margin" /> + <androidx.recyclerview.widget.RecyclerView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:id="@+id/job_progress_list" /> + </LinearLayout> + </com.google.android.material.card.MaterialCardView> +</FrameLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/job_progress_toolbar_item.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/job_progress_toolbar_item.xml new file mode 100644 index 000000000..222c8d43e --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/job_progress_toolbar_item.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<com.google.android.material.progressindicator.CircularProgressIndicator + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + style="@style/JobProgressToolbarIndicatorStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:clickable="true" + android:focusable="true" /> 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 index 9c382c193..091444155 100644 --- 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 @@ -35,8 +35,8 @@ 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:paddingBottom="@dimen/layout_padding_bottom" android:background="?attr/colorSurfaceContainer"> <!-- Navigation rail: left hand side. --> @@ -144,17 +144,18 @@ 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" /> + <com.android.documentsui.HorizontalBreadcrumb + android:id="@+id/horizontal_breadcrumb" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingHorizontal="@dimen/breadcrumb_padding_horizontal" /> </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:background="?attr/colorSurfaceContainer" android:elevation="8dp" /> </LinearLayout> 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 index 672343795..ba99ac35d 100644 --- 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 @@ -15,29 +15,20 @@ 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"> + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minHeight="@dimen/breadcrumb_height" + android:gravity="center_vertical" + android:orientation="horizontal"> <TextView android:id="@+id/breadcrumb_text" android:layout_width="wrap_content" - android:layout_height="match_parent" + android:layout_height="@dimen/breadcrumb_item_height" + android:focusable="true" + android:clickable="true" android:maxWidth="275dp" android:gravity="center_vertical" android:maxLines="1" @@ -47,8 +38,8 @@ <ImageView android:id="@+id/breadcrumb_arrow" - android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_width="@dimen/breadcrumb_item_arrow_size" + android:layout_height="@dimen/breadcrumb_item_arrow_size" 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/search_chip_row.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/search_chip_row.xml index 559ae3188..62a36f3e8 100644 --- 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 @@ -20,10 +20,21 @@ android:layout_height="wrap_content" android:scrollbars="none"> - <com.google.android.material.chip.ChipGroup - android:id="@+id/search_chip_group" + <!-- This additional FrameLayout layer is essential to make HorizontalScrollView work with the + marginHorizontal on the ChipGroup below, without this the scroll behavior is weird. + Alternatively we could use paddingHorizontal on the ChipGroup below to make it work with + HorizontalScrollView, but that cause a weird padding issue in RTL. + --> + <FrameLayout 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" /> + android:layout_height="wrap_content"> + + <com.google.android.material.chip.ChipGroup + android:id="@+id/search_chip_group" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/main_container_padding_start" + android:paddingVertical="@dimen/search_chip_group_padding_vertical" /> + + </FrameLayout> </HorizontalScrollView> 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/shared_cell_content.xml index f269afdbe..f269afdbe 100644 --- 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/shared_cell_content.xml 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 index 0e636a18c..809a1386a 100644 --- a/res/flag(com.android.documentsui.flags.use_material3)/menu/activity.xml +++ b/res/flag(com.android.documentsui.flags.use_material3)/menu/activity.xml @@ -34,6 +34,12 @@ app:showAsAction="always|collapseActionView" app:actionViewClass="androidx.appcompat.widget.SearchView"/> <item + android:id="@+id/option_menu_job_progress" + android:enabled="false" + android:visible="false" + app:actionLayout="@layout/job_progress_toolbar_item" + app:showAsAction="always" /> + <item android:id="@+id/sub_menu_grid" android:title="@string/menu_grid" android:icon="@drawable/ic_menu_view_grid" 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 index 2105936ab..b75afa868 100644 --- 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 @@ -37,4 +37,24 @@ </color> <!-- neutral variant 100 --> <color name="fragment_pick_active_text_color">@android:color/black</color> + + <!-- All drag drop badge colors, we can only use system color tokens because there's no theme + context inside the view. + --> + <!-- ?attr/colorTertiary --> + <color name="drag_file_counter_background">@android:color/system_accent3_200</color> + <!-- ?attr/colorOnTertiary --> + <color name="drag_file_counter_text_color">@android:color/system_accent3_800</color> + <!-- ?attr/colorSurfaceDim --> + <color name="item_drag_shadow_background">@color/m3_ref_palette_dynamic_neutral_variant6</color> + <!-- ?attr/colorSurfaceContainerLowest --> + <color name="drag_mime_icon_wrapper_background"> + @color/m3_ref_palette_dynamic_neutral_variant4 + </color> + <!-- ?attr/colorOnSurface --> + <color name="drag_content_text_color">@android:color/system_neutral1_100</color> + <!-- ?attr/colorOnError --> + <color name="drop_icon_symbol_color">@color/m3_ref_palette_error20</color> + <!-- ?attr/colorError --> + <color name="drop_icon_reject_container_background">@color/m3_ref_palette_error80</color> </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 index 3096f8a3e..b7e11e885 100644 --- 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 @@ -37,4 +37,22 @@ </color> <!-- accent 600 --> <color name="fragment_pick_active_text_color">@android:color/white</color> + + <!-- All drag drop badge colors, we can only use system color tokens because there's no theme + context inside the view. + --> + <!-- ?attr/colorTertiary --> + <color name="drag_file_counter_background">@android:color/system_accent3_600</color> + <!-- ?attr/colorOnTertiary --> + <color name="drag_file_counter_text_color">@android:color/system_accent3_0</color> + <!-- ?attr/colorSurfaceDim --> + <color name="item_drag_shadow_background">@color/m3_ref_palette_dynamic_neutral_variant87</color> + <!-- ?attr/colorSurfaceContainerLowest --> + <color name="drag_mime_icon_wrapper_background">@android:color/system_neutral2_0</color> + <!-- ?attr/colorOnSurface --> + <color name="drag_content_text_color">@android:color/system_neutral1_900</color> + <!-- ?attr/colorOnError --> + <color name="drop_icon_symbol_color">@android:color/white</color> + <!-- ?attr/colorError --> + <color name="drop_icon_reject_container_background">@color/m3_ref_palette_error40</color> </resources> 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 index 4707991f6..00c9a662a 100644 --- 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 @@ -26,5 +26,12 @@ <dimen name="toolbar_padding_start">@dimen/main_container_padding_start</dimen> <dimen name="list_container_padding">@dimen/space_extra_small_6</dimen> + + <!-- list_container_padding + list_item_padding_start --> + <dimen name="table_header_padding_start">28dp</dimen> + <!-- list_container_padding + list_item_padding_end --> + <dimen name="table_header_padding_end">20dp</dimen> + + <dimen name="picker_saver_container_padding_bottom">0dp</dimen> </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 index d37f3af68..24ff2b17b 100644 --- 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 @@ -36,4 +36,9 @@ <dimen name="toolbar_padding_end">@dimen/space_small_3</dimen> <dimen name="drawer_padding_top">@dimen/space_small_1</dimen> + + <!-- list_container_padding + list_item_padding_start --> + <dimen name="table_header_padding_start">32dp</dimen> + <!-- list_container_padding + list_item_padding_end --> + <dimen name="table_header_padding_end">12dp</dimen> </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 index 05cbb6c81..5696288e6 100644 --- a/res/flag(com.android.documentsui.flags.use_material3)/values/colors.xml +++ b/res/flag(com.android.documentsui.flags.use_material3)/values/colors.xml @@ -29,11 +29,26 @@ <!-- TODO(b/379776735): remove this after use_material3 flag is launched. --> <color name="chip_background_disable_color">#fff1f3f4</color> <color name="menu_search_background">@android:color/transparent</color> + <!-- TODO(b/379776735): remove this after use_material3 flag is launched. --> <color name="item_breadcrumb_background_hovered">#1affffff</color> - <color name="item_drag_shadow_background">@android:color/white</color> + + <!-- All the colors used inside the drag drop badge don't support Material color attributes + because the drag view and shadow are isolated views rendered without theme context, so + we need to use static colors for SDK <= 30, and use system color tokens for SDK >= 31. + Check the variables with the same name defined in the v31 version of colors.xml. + --> + <color name="item_drag_shadow_background">#E3D7DD</color> <color name="item_drag_shadow_container_background"> @android:color/transparent </color> + <color name="drag_file_counter_background">#825344</color> + <color name="drag_file_counter_text_color">@android:color/white</color> + <color name="drag_mime_icon_wrapper_background">@android:color/white</color> + <color name="drag_content_text_color">#201A1E</color> + <color name="drop_icon_symbol_color">@android:color/white</color> + <color name="drop_icon_copy_container_background">#1EA446</color> + <color name="drop_icon_reject_container_background">#BA1A1A</color> + <color name="tool_bar_gradient_max">#7f000000</color> <color name="band_select_background">?attr/colorPrimaryInverse</color> 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 index 65740f15c..fa9e436ab 100644 --- a/res/flag(com.android.documentsui.flags.use_material3)/values/dimens.xml +++ b/res/flag(com.android.documentsui.flags.use_material3)/values/dimens.xml @@ -14,7 +14,7 @@ limitations under the License. --> -<!-- Dimensions/sizes for size Compact (<=600dp). --> +<!-- Dimensions/sizes for size Compact (<600dp). --> <resources> <!-- Material design rounded radius --> <dimen name="material_round_radius">2dp</dimen> @@ -23,13 +23,11 @@ <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> - <!-- For compact screen, file area occupies the whole screen height, when use_material3 flag is - ON we show breadcrumb at the bottom, so we need to add padding (breadcrumb height) at the - bottom to make sure breadcrumb won't over-shadow the file area. --> - <dimen name="file_area_padding_bottom">48dp</dimen> <dimen name="icon_size">40dp</dimen> <dimen name="button_touch_size">48dp</dimen> <dimen name="root_icon_size">24dp</dimen> + <dimen name="thumbnail_clip_corner_radius">6dp</dimen> + <dimen name="thumbnail_border_width">1dp</dimen> <!-- TODO(b/379776735): remove this block after use_material3 flag is launched. --> <dimen name="root_icon_margin">0dp</dimen> <dimen name="root_spacer_padding">0dp</dimen> @@ -45,9 +43,10 @@ <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_width">150dp</dimen> + <dimen name="grid_height">132dp</dimen> <dimen name="grid_section_separator_height">0dp</dimen> - <dimen name="grid_item_margin">6dp</dimen> + <dimen name="grid_item_margin">@dimen/space_small_1</dimen> <dimen name="grid_padding_horiz">4dp</dimen> <dimen name="grid_padding_vert">4dp</dimen> <dimen name="list_item_height">56dp</dimen> @@ -62,26 +61,31 @@ <dimen name="list_item_icon_padding">16dp</dimen> <dimen name="list_divider_inset">72dp</dimen> <!-- block end --> + <dimen name="breadcrumb_padding_horizontal">@dimen/space_small_3</dimen> + <!-- TODO(b/379776735): remove this after use_material3 flag is launched. --> <dimen name="breadcrumb_item_padding">8dp</dimen> - <dimen name="breadcrumb_item_height">36dp</dimen> + <dimen name="breadcrumb_item_padding_horizontal">12dp</dimen> + <dimen name="breadcrumb_item_padding_vertical">6dp</dimen> + <dimen name="breadcrumb_item_arrow_padding">@dimen/space_extra_small_2</dimen> + <dimen name="breadcrumb_item_height">32dp</dimen> + <dimen name="breadcrumb_height">48dp</dimen> + <dimen name="breadcrumb_item_arrow_size">16dp</dimen> <dimen name="dir_elevation">8dp</dimen> <dimen name="drag_shadow_size">120dp</dimen> - <dimen name="grid_item_width">150dp</dimen> - <dimen name="grid_item_height">132dp</dimen> - <dimen name="grid_item_layout_marginStart">@dimen/space_extra_small_2</dimen> - <dimen name="grid_item_layout_marginEnd">@dimen/space_extra_small_2</dimen> - <dimen name="grid_item_layout_marginTop">@dimen/space_extra_small_2</dimen> + <dimen name="grid_item_padding_start">@dimen/space_extra_small_2</dimen> + <dimen name="grid_item_padding_end">@dimen/space_extra_small_2</dimen> + <dimen name="grid_item_padding_top">@dimen/space_extra_small_2</dimen> <dimen name="grid_item_thumbnail_width">80dp</dimen> <dimen name="grid_item_thumbnail_height">80dp</dimen> <dimen name="grid_item_thumbnail_radius">12dp</dimen> <dimen name="grid_item_icon_width">64dp</dimen> <dimen name="grid_item_icon_height">64dp</dimen> - <dimen name="grid_item_layout_margin">@dimen/space_small_1</dimen> <dimen name="grid_item_nameplate_width">142dp</dimen> <dimen name="grid_item_nameplate_height">44dp</dimen> <dimen name="grid_item_nameplate_padding">4dp</dimen> <dimen name="grid_item_nameplate_marginTop">@dimen/space_extra_small_2</dimen> <dimen name="grid_item_nameplate_radius">8dp</dimen> + <dimen name="grid_item_nameplate_inner_radius">4dp</dimen> <dimen name="grid_item_elevation">2dp</dimen> <dimen name="grid_item_radius">12dp</dimen> <dimen name="max_drawer_width">280dp</dimen> @@ -90,6 +94,11 @@ <dimen name="briefcase_icon_size_photo">24dp</dimen> <dimen name="button_corner_radius">2dp</dimen> + <!-- list_container_padding + list_item_padding_start --> + <dimen name="table_header_padding_start">24dp</dimen> + <!-- list_container_padding + list_item_padding_end --> + <dimen name="table_header_padding_end">16dp</dimen> + <dimen name="bottom_sheet_dialog_radius">28dp</dimen> <dimen name="drawer_edge_width">12dp</dimen> @@ -109,21 +118,44 @@ <dimen name="nav_rail_item_icon_bg_height">32dp</dimen> <dimen name="nav_rail_burger_icon_size">56dp</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_content_width">160dp</dimen> + <dimen name="drag_content_height">40dp</dimen> + <!-- drag_additional_layer_offset + drag_shadow_radius --> + <dimen name="drag_content_margin_start">7dp</dimen> + <dimen name="drag_content_radius">12dp</dimen> + <dimen name="drag_additional_layer_offset">4dp</dimen> + <!-- drag_additional_layer_offset + drag_file_counter_offset --> + <dimen name="drag_additional_layer_margin_top">12dp</dimen> + <dimen name="drag_file_counter_offset">8dp</dimen> + <dimen name="drag_file_counter_height">20dp</dimen> + <!-- drag shadow width/height need to cater all the elements drawing inside it, including + drag content, offset, shadow and drag file counter, so: + * width = drag_content_width + drag_file_counter_offset + drag_additional_layer_offset + drag_shadow_radius + * width = drag_content_height + drag_file_counter_offset + drag_additional_layer_offset + drag_shadow_radius + --> + <dimen name="drag_shadow_width">175dp</dimen> + <dimen name="drag_shadow_height">55dp</dimen> + <dimen name="drag_shadow_radius">3dp</dimen> + <dimen name="drag_shadow_2_radius">2dp</dimen> + <dimen name="drag_shadow_y_offset">1dp</dimen> + <!-- TODO(b/379776735): remove this after use_material3 flag is launched. --> <dimen name="drag_shadow_padding">8dp</dimen> + <dimen name="drop_mime_icon_wrapper_size">24dp</dimen> + <dimen name="drop_mime_icon_wrapper_radius">4dp</dimen> + <dimen name="drop_icon_height">14dp</dimen> + <dimen name="drop_icon_width">14dp</dimen> + <dimen name="drop_icon_offset">3dp</dimen> + <!-- drag_mime_icon_wrapper_size + drop_icon_offset --> + <dimen name="drop_badge_container_size">27dp</dimen> + <dimen name="doc_header_sort_icon_size">32dp</dimen> - <dimen name="doc_header_height">60dp</dimen> + <dimen name="doc_header_height">48dp</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> @@ -150,12 +182,18 @@ <dimen name="search_chip_radius">8dp</dimen> <dimen name="search_chip_group_padding_vertical">@dimen/space_extra_small_4</dimen> + <dimen name="search_chip_inactive_stroke_width">1dp</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="picker_saver_padding_top">@dimen/space_extra_small_1</dimen> + <dimen name="picker_saver_padding_bottom">@dimen/space_extra_small_1</dimen> + <dimen name="picker_saver_button_gap">@dimen/space_extra_small_2</dimen> + <dimen name="picker_saver_container_padding_top">@dimen/space_small_1</dimen> + <dimen name="picker_saver_container_padding_bottom">@dimen/space_small_1</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> @@ -188,6 +226,7 @@ <!-- 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> + <dimen name="job_progress_toolbar_indicator_size">24dp</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> @@ -209,4 +248,8 @@ <dimen name="focus_ring_gap">5dp</dimen> <dimen name="hover_overlay_alpha">0.08</dimen> <dimen name="ripple_overlay_alpha">0.10</dimen> + + <dimen name="job_progress_panel_width">360dp</dimen> + <dimen name="job_progress_panel_margin">@dimen/space_small_1</dimen> + <dimen name="job_progress_panel_header_margin">@dimen/space_small_1</dimen> </resources> 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 index 693679cf9..481cd0be8 100644 --- a/res/flag(com.android.documentsui.flags.use_material3)/values/styles.xml +++ b/res/flag(com.android.documentsui.flags.use_material3)/values/styles.xml @@ -34,6 +34,11 @@ <item name="android:maxHeight">@dimen/icon_size_headline_large</item> </style> + <style name="JobProgressToolbarIndicatorStyle" parent="@style/Widget.Material3.CircularProgressIndicator.ExtraSmall"> + <item name="indicatorSize">@dimen/job_progress_toolbar_indicator_size</item> + <item name="indicatorInset">@dimen/space_extra_small_6</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> @@ -90,6 +95,10 @@ <item name="android:textAppearance">@style/MaterialButtonTextAppearance</item> </style> + <style name="MaterialTonalButton" parent="@style/Widget.Material3.Button.TonalButton"> + <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> @@ -181,4 +190,11 @@ <item name="android:textColor">@color/nav_rail_item_text_color</item> <item name="android:textAppearance">@style/NavRailItemTextAppearance</item> </style> + + <style name="JobProgressPanelStyle" parent="@style/Widget.Material3.CardView.Elevated"> + <item name="android:layout_marginStart">@dimen/job_progress_panel_margin</item> + <item name="android:layout_marginBottom">@dimen/job_progress_panel_margin</item> + <item name="cardElevation">1dp</item> + <item name="cardBackgroundColor">?attr/colorSurfaceDim</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 index 82b498569..57dbb1212 100644 --- 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 @@ -96,9 +96,8 @@ <item name="fontFamily">@string/config_fontFamilyMedium</item> </style> - <style name="BreadcrumbText" parent="@style/TextAppearance.Widget.AppCompat.Toolbar.Subtitle"> + <style name="BreadcrumbText" parent="@style/TextAppearance.Material3.TitleSmall"> <item name="android:textColor">@color/horizontal_breadcrumb_color</item> - <item name="android:textSize">14sp</item> <item name="fontFamily">@string/config_fontFamilyMedium</item> </style> @@ -150,4 +149,18 @@ <item name="fontFamily">@string/config_fontFamily</item> </style> + <style name="DragBadgeText" parent="@style/TextAppearance.Material3.TitleSmall"> + <item name="android:textColor">@color/drag_content_text_color</item> + <item name="fontFamily">@string/config_fontFamily</item> + </style> + + <style name="DragCounterText" parent="@style/TextAppearance.Material3.LabelMedium"> + <item name="android:textColor">@color/drag_file_counter_text_color</item> + <item name="fontFamily">@string/config_fontFamily</item> + </style> + + <style name="JobProgressPanelHeaderText" parent="@style/TextAppearance.Material3.TitleMedium"> + <item name="fontFamily">@string/config_fontFamilyMedium</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 index 314022eea..114d14c88 100644 --- a/res/flag(com.android.documentsui.flags.use_material3)/values/themes.xml +++ b/res/flag(com.android.documentsui.flags.use_material3)/values/themes.xml @@ -79,5 +79,9 @@ <!-- Menu text appearance --> <item name="android:itemTextAppearance">@style/MenuItemTextAppearance</item> + + <!-- System bar colors. --> + <item name="android:statusBarColor">?attr/colorSurfaceContainer</item> + <item name="android:navigationBarColor">?attr/colorSurfaceContainer</item> </style> </resources> diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml index e935ed1a3..f3dc33788 100644 --- a/res/values-af/strings.xml +++ b/res/values-af/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Onttrek hier"</string> + <string name="menu_browse" msgid="6007716414766674967">"Blaai"</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> @@ -290,6 +292,6 @@ <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> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Lêernaam"</string> </resources> diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml index 23c0f4ab3..4267bd1de 100644 --- a/res/values-am/strings.xml +++ b/res/values-am/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"ወደዚህ አውጣ"</string> + <string name="menu_browse" msgid="6007716414766674967">"ያስሱ"</string> <string name="menu_rename" msgid="1883113442688817554">"ዳግም ሰይም"</string> <string name="menu_inspect" msgid="7279855349299446224">"መረጃ አግኝ"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"የተደበቁ ፋይሎችን አሳይ"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"ከሌላ መተግበሪያ ፋይሎችን መውሰድ አይችሉም።"</string> <string name="grid_mode_showing" msgid="2803166871485028508">"በፍርግርግ ሁነታ ላይ በማሳየት ላይ።"</string> <string name="list_mode_showing" msgid="1225413902295895166">"በዝርዝር ሁነታ ላይ በማሳየት ላይ።"</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"የፋይል ስም"</string> </resources> diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml index 32bb7f65b..6b193c223 100644 --- a/res/values-ar/strings.xml +++ b/res/values-ar/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"الاستخراج هنا"</string> + <string name="menu_browse" msgid="6007716414766674967">"تصفُّح"</string> <string name="menu_rename" msgid="1883113442688817554">"إعادة تسمية"</string> <string name="menu_inspect" msgid="7279855349299446224">"الحصول على المعلومات"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"إظهار الملفات المخفية"</string> @@ -378,6 +380,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"لا يمكنك نقل الملفات من تطبيق آخر."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"يتم العرض في وضع الشبكة."</string> <string name="list_mode_showing" msgid="1225413902295895166">"يتم العرض في وضع القائمة."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"اسم الملف"</string> </resources> diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml index accf7d508..1d830ebad 100644 --- a/res/values-as/strings.xml +++ b/res/values-as/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"ইয়াত আহৰণ কৰক"</string> + <string name="menu_browse" msgid="6007716414766674967">"ব্ৰাউজ কৰক"</string> <string name="menu_rename" msgid="1883113442688817554">"নতুন নাম দিয়ক"</string> <string name="menu_inspect" msgid="7279855349299446224">"তথ্য পাওক"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"লুকুৱাই থোৱা ফাইল দেখুৱাওক"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"আপুনি অন্য এটা এপৰ পৰা ফাইল স্থানান্তৰ কৰিব নোৱাৰে।"</string> <string name="grid_mode_showing" msgid="2803166871485028508">"গ্ৰিড ম’ডত দেখুৱাই থকা হৈছে।"</string> <string name="list_mode_showing" msgid="1225413902295895166">"সূচীযুক্ত ম’ডত দেখুৱাই থকা হৈছে।"</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"ফাইলৰ নাম"</string> </resources> diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml index 0ccc72860..789d477c1 100644 --- a/res/values-az/strings.xml +++ b/res/values-az/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Buraya çıxarın"</string> + <string name="menu_browse" msgid="6007716414766674967">"Axtarı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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Başqa tətbiqdən faylları köçürə bilməzsiniz."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Tor rejimində göstərilir."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Siyahı rejimində göstərilir."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Fayl adı"</string> </resources> diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml index 1984af705..af9c3d506 100644 --- a/res/values-b+sr+Latn/strings.xml +++ b/res/values-b+sr+Latn/strings.xml @@ -18,7 +18,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="missing_rename_error" msgid="9098952207447981103">"Morate da preimenujete ovo"</string> <string name="add_folder_name_error" msgid="6014615052491406810">"Morate da dodate naziv foldera"</string> - <string name="files_label" msgid="771781190045103748">"Datoteke"</string> + <string name="files_label" msgid="771781190045103748">"Fajlovi"</string> <string name="downloads_label" msgid="5462789470049501103">"Preuzimanja"</string> <!-- no translation found for app_label (8089292432455111409) --> <skip /> @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Izdvoj ovde"</string> + <string name="menu_browse" msgid="6007716414766674967">"Pregledaj"</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> @@ -272,7 +274,7 @@ <item quantity="other">Izabrano je <xliff:g id="COUNT_1">%1$d</xliff:g> stavki</item> </plurals> <string name="root_info_header_recent" msgid="5654901877295332262">"Nedavne datoteke"</string> - <string name="root_info_header_global_search" msgid="4904078222280496152">"Datoteke"</string> + <string name="root_info_header_global_search" msgid="4904078222280496152">"Fajlovi"</string> <string name="root_info_header_downloads" msgid="8848161246921154115">"Datoteke u Preuzimanjima"</string> <string name="root_info_header_storage" msgid="2989014130584927442">"Datoteke na uređaju <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="root_info_header_folder" msgid="5851172222368049864">"Datoteke u folderu <xliff:g id="FOLDER">%1$s</xliff:g>"</string> @@ -312,6 +314,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Ne možete da premeštate datoteke iz druge aplikacije."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Prikazuje se u režimu mreže."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Prikazuje se u režimu liste."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Naziv fajla"</string> </resources> diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml index 4f2418509..b20f4ec6b 100644 --- a/res/values-be/strings.xml +++ b/res/values-be/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Выняць сюды"</string> + <string name="menu_browse" msgid="6007716414766674967">"Прагледзець"</string> <string name="menu_rename" msgid="1883113442688817554">"Перайменаваць"</string> <string name="menu_inspect" msgid="7279855349299446224">"Атрымаць інфармацыю"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Паказваць схаваныя файлы"</string> @@ -334,6 +336,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Вы не можаце перамяшчаць файлы з іншай праграмы."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Паказ у рэжыме табліцы."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Паказ у рэжыме спіса."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Назва файла"</string> </resources> diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml index d73d376fa..eb6c137dc 100644 --- a/res/values-bg/strings.xml +++ b/res/values-bg/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Извличане тук"</string> + <string name="menu_browse" msgid="6007716414766674967">"Преглед"</string> <string name="menu_rename" msgid="1883113442688817554">"Преименуване"</string> <string name="menu_inspect" msgid="7279855349299446224">"Получаване на информация"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Показване на скрити файлове"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Не можете да местите файлове от друго приложение."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Показва се в табличен изглед."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Показва се в списъчен изглед."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Име на файла"</string> </resources> diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml index 59b3d297d..5815a476c 100644 --- a/res/values-bn/strings.xml +++ b/res/values-bn/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"এখানে এক্সট্র্যাক্ট করুন"</string> + <string name="menu_browse" msgid="6007716414766674967">"ব্রাউজ করুন"</string> <string name="menu_rename" msgid="1883113442688817554">"পুনঃনামকরণ"</string> <string name="menu_inspect" msgid="7279855349299446224">"তথ্য পান"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"লুকানো ফাইল দেখুন"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"অন্য অ্যাপ থেকে ফাইল সরাতে পারবেন না।"</string> <string name="grid_mode_showing" msgid="2803166871485028508">"গ্রিড মোডে দেখানো হচ্ছে।"</string> <string name="list_mode_showing" msgid="1225413902295895166">"তালিকা মোডে দেখানো হচ্ছে।"</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"ফাইলের নাম"</string> </resources> diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml index 96328a42c..73a4b502a 100644 --- a/res/values-bs/strings.xml +++ b/res/values-bs/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Izdvoji ovdje"</string> + <string name="menu_browse" msgid="6007716414766674967">"Pregledaj"</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> @@ -312,6 +314,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Ne možete premjestiti fajlove iz druge aplikacije."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Prikazivanje u vidu mreže."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Prikazivanje u vidu liste."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Naziv fajla"</string> </resources> diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index 6b4a256cd..f78ec3811 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Extreu aquí"</string> + <string name="menu_browse" msgid="6007716414766674967">"Navega"</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> @@ -312,6 +314,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"No pots moure fitxers des d\'una altra aplicació."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Es mostra en mode de quadrícula."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Es mostra en mode de llista."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Nom del fitxer"</string> </resources> diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index f0a4b6424..28b167244 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Extrahovat sem"</string> + <string name="menu_browse" msgid="6007716414766674967">"Procházet"</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> @@ -334,6 +336,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Není možné přesouvat soubory z jiné aplikace."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Zobrazuje se mřížka s položkami."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Zobrazuje se seznam položek."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Název souboru"</string> </resources> diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index 8248ffaca..bfc2386f2 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Udtræk herfra"</string> + <string name="menu_browse" msgid="6007716414766674967">"Gennemse"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Du kan ikke flytte filer fra en anden app."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Vises i gittervisning."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Vises i listevisning."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Filnavn"</string> </resources> diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 3c80bf742..ee5604973 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Hier extrahieren"</string> + <string name="menu_browse" msgid="6007716414766674967">"Durchsuchen"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Du kannst keine Dateien aus einer anderen App verschieben."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Wird im Rastermodus angezeigt."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Wird im Listenmodus angezeigt."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Dateiname"</string> </resources> diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml index e270d7d83..7b403cbe4 100644 --- a/res/values-el/strings.xml +++ b/res/values-el/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Εξαγωγή εδώ"</string> + <string name="menu_browse" msgid="6007716414766674967">"Περιήγηση"</string> <string name="menu_rename" msgid="1883113442688817554">"Μετονομασία"</string> <string name="menu_inspect" msgid="7279855349299446224">"Λήψη πληροφοριών"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Εμφάνιση κρυφών αρχείων"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Δεν είναι δυνατή η μεταφορά αρχείων από άλλη εφαρμογή."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Εμφάνιση σε λειτουργία πλέγματος."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Εμφάνιση σε λειτουργία λίστας."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Όνομα αρχείου"</string> </resources> diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml index 477944a51..f35f46c0c 100644 --- a/res/values-en-rAU/strings.xml +++ b/res/values-en-rAU/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Extract here"</string> + <string name="menu_browse" msgid="6007716414766674967">"Browse"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"You can’t move files from another app."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Showing in grid mode."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Showing in list mode."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"File name"</string> </resources> diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml index 6d10f06b8..adfdf6111 100644 --- a/res/values-en-rCA/strings.xml +++ b/res/values-en-rCA/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Extract here"</string> + <string name="menu_browse" msgid="6007716414766674967">"Browse"</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> @@ -291,4 +293,5 @@ <string name="grid_mode_showing" msgid="2803166871485028508">"Showing in grid mode."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Showing in list mode."</string> <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"File name"</string> </resources> diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml index 477944a51..f35f46c0c 100644 --- a/res/values-en-rGB/strings.xml +++ b/res/values-en-rGB/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Extract here"</string> + <string name="menu_browse" msgid="6007716414766674967">"Browse"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"You can’t move files from another app."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Showing in grid mode."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Showing in list mode."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"File name"</string> </resources> diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml index 477944a51..f35f46c0c 100644 --- a/res/values-en-rIN/strings.xml +++ b/res/values-en-rIN/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Extract here"</string> + <string name="menu_browse" msgid="6007716414766674967">"Browse"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"You can’t move files from another app."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Showing in grid mode."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Showing in list mode."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"File name"</string> </resources> diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index 09b071f76..68a382f45 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Extraer aquí"</string> + <string name="menu_browse" msgid="6007716414766674967">"Explorar"</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> @@ -312,6 +314,6 @@ <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> <string name="list_mode_showing" msgid="1225413902295895166">"Se muestra en modo de lista."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Nombre del archivo"</string> </resources> diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index c82e9fa4c..737500313 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Extraer aquí"</string> + <string name="menu_browse" msgid="6007716414766674967">"Explorar"</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> @@ -312,6 +314,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"No puedes mover archivos de otra aplicación."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Mostrando modo de cuadrícula."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Mostrando modo de lista."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Nombre del archivo"</string> </resources> diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml index 3b6338d57..15b81449a 100644 --- a/res/values-et/strings.xml +++ b/res/values-et/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Ekstrakti siia"</string> + <string name="menu_browse" msgid="6007716414766674967">"Sirvimine"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Te ei saa faile teisest rakendusest teisaldada."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Kuvatud ruudustikuvaates."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Kuvatud loendivaates."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Faili nimi"</string> </resources> diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml index 5b8c88f14..94305a6d7 100644 --- a/res/values-eu/strings.xml +++ b/res/values-eu/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Erauzi hona"</string> + <string name="menu_browse" msgid="6007716414766674967">"Arakatu"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Ezin dituzu mugitu beste aplikazio batzuetako fitxategiak."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Sareta moduan ikusgai."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Zerrenda moduan ikusgai."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Fitxategiaren izena"</string> </resources> diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 1f3c0e261..c108d9f07 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"استخراج در اینجا"</string> + <string name="menu_browse" msgid="6007716414766674967">"مرور کردن"</string> <string name="menu_rename" msgid="1883113442688817554">"تغییر نام"</string> <string name="menu_inspect" msgid="7279855349299446224">"دریافت اطلاعات"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"فایلهای پنهان نشان داده شود"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"نمیتوانید فایلها را از برنامه دیگری انتقال دهید."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"نمایش در حالت جدولی."</string> <string name="list_mode_showing" msgid="1225413902295895166">"نمایش در حالت فهرست."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"نام فایل"</string> </resources> diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml index 4f7a53706..7b888bfd4 100644 --- a/res/values-fi/strings.xml +++ b/res/values-fi/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Pura tähän"</string> + <string name="menu_browse" msgid="6007716414766674967">"Selaa"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Et voi siirtää tiedostoja toisesta sovelluksesta."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Näytetään ruudukkotilassa."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Näytetään luettelotilassa."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Tiedostonimi"</string> </resources> diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml index 22031245e..62d18393d 100644 --- a/res/values-fr-rCA/strings.xml +++ b/res/values-fr-rCA/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Extraire ici"</string> + <string name="menu_browse" msgid="6007716414766674967">"Parcourir"</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> @@ -312,6 +314,6 @@ <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> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Nom de fichier"</string> </resources> diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index b248c4859..3c1475290 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Extraire ici"</string> + <string name="menu_browse" msgid="6007716414766674967">"Parcourir"</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> @@ -312,6 +314,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Vous ne pouvez pas déplacer de fichiers depuis une autre application."</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> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Nom du fichier"</string> </resources> diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml index 323ec058d..d45dbc211 100644 --- a/res/values-gl/strings.xml +++ b/res/values-gl/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Extraer aquí"</string> + <string name="menu_browse" msgid="6007716414766674967">"Explorar"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Non se poden mover ficheiros desde outra aplicación."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Mostrando modo de grade."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Mostrando modo de lista."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Nome do ficheiro"</string> </resources> diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml index db1be59cb..7f5ffa3e0 100644 --- a/res/values-gu/strings.xml +++ b/res/values-gu/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"અહીં એક્સ્ટ્રેક્ટ કરો"</string> + <string name="menu_browse" msgid="6007716414766674967">"બ્રાઉઝ કરો"</string> <string name="menu_rename" msgid="1883113442688817554">"નામ બદલો"</string> <string name="menu_inspect" msgid="7279855349299446224">"માહિતી મેળવો"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"છુપાવેલી ફાઇલો બતાવો"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"તમે કોઈ અન્ય ઍપમાંથી ફાઇલો ખસેડી શકતાં નથી."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"ગ્રિડ મોડમાં બતાવી રહ્યાં છીએ."</string> <string name="list_mode_showing" msgid="1225413902295895166">"સૂચિ મોડમાં બતાવી રહ્યાં છીએ."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"ફાઇલનું નામ"</string> </resources> diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index b6fc7d83d..7fc004024 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"यहां एक्सट्रैक्ट करें"</string> + <string name="menu_browse" msgid="6007716414766674967">"ब्राउज़ करें"</string> <string name="menu_rename" msgid="1883113442688817554">"नाम बदलें"</string> <string name="menu_inspect" msgid="7279855349299446224">"जानकारी पाएं"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"छिपी हुई फ़ाइलें दिखाएं"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"आप किसी दूसरे ऐप्लिकेशन से फ़ाइलें नहीं ले जा सकते."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"ग्रिड मोड में दिखाया जा रहा है."</string> <string name="list_mode_showing" msgid="1225413902295895166">"सूची मोड में दिखाया जा रहा है."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"फ़ाइल का नाम"</string> </resources> diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml index 5998f4a98..e12bc50f0 100644 --- a/res/values-hr/strings.xml +++ b/res/values-hr/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Izdvoji ovdje"</string> + <string name="menu_browse" msgid="6007716414766674967">"Pregledaj"</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> @@ -312,6 +314,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Ne možete premjestiti datoteke iz druge aplikacije."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Prikazivanje u načinu rešetke."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Prikazivanje u načinu popisa."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Naziv datoteke"</string> </resources> diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml index db82943b7..7119be420 100644 --- a/res/values-hu/strings.xml +++ b/res/values-hu/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Kibontás ide"</string> + <string name="menu_browse" msgid="6007716414766674967">"Böngészés"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Nem lehet áthelyezni fájlokat más alkalmazásból."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Megjelenítés rácsnézetben."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Megjelenítés listanézetben."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Fájlnév"</string> </resources> diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml index 9cf0e2a60..bf75c96c1 100644 --- a/res/values-hy/strings.xml +++ b/res/values-hy/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Դուրս բերել այստեղ"</string> + <string name="menu_browse" msgid="6007716414766674967">"Դիտարկել"</string> <string name="menu_rename" msgid="1883113442688817554">"Վերանվանել"</string> <string name="menu_inspect" msgid="7279855349299446224">"Տեղեկություններ"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Ցուցադրել թաքցված ֆայլերը"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Դուք չեք կարող տեղափոխել ֆայլեր այլ հավելվածից։"</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Ցուցադրվում է ցանցի տեսքով։"</string> <string name="list_mode_showing" msgid="1225413902295895166">"Ցուցադրվում է ցանկի տեսքով։"</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Ֆայլի անվանումը"</string> </resources> diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index d5e864c0f..5ac5aa336 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Ekstrak di sini"</string> + <string name="menu_browse" msgid="6007716414766674967">"Cari"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Anda tidak dapat memindahkan file ke aplikasi lain."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Menampilkan dalam mode petak."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Menampilkan dalam mode daftar."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Nama file"</string> </resources> diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml index 4ec26ccb4..f78a5fc63 100644 --- a/res/values-is/strings.xml +++ b/res/values-is/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Draga út hingað"</string> + <string name="menu_browse" msgid="6007716414766674967">"Skoða"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Ekki er hægt að færa skrár úr öðru forriti."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Sýnir töfluyfirlit."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Sýnir listayfirlit."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Skráarheiti"</string> </resources> diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 4ce7438fc..a289cd8b2 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Estrai qui"</string> + <string name="menu_browse" msgid="6007716414766674967">"Sfoglia"</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> @@ -312,6 +314,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Impossibile spostare file da un\'altra app."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Visualizzazione in modalità griglia."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Visualizzazione in modalità elenco."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Nome file"</string> </resources> diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index 76860185b..c3c3aff29 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"חילוץ לכאן"</string> + <string name="menu_browse" msgid="6007716414766674967">"עיון"</string> <string name="menu_rename" msgid="1883113442688817554">"שינוי שם"</string> <string name="menu_inspect" msgid="7279855349299446224">"מידע על המסמך"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"הצגת קבצים מוסתרים"</string> @@ -312,6 +314,7 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"אי אפשר להעביר קבצים מאפליקציה אחרת."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"הצגה בתצוגת טבלה."</string> <string name="list_mode_showing" msgid="1225413902295895166">"הצגה בתצוגת רשימה."</string> - <!-- no translation found for bullet (5606740650312122766) --> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <!-- no translation found for file_name_hint (7843637320487415838) --> <skip /> </resources> diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index aeb7992f6..2f3c14114 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"ここに抽出"</string> + <string name="menu_browse" msgid="6007716414766674967">"参照"</string> <string name="menu_rename" msgid="1883113442688817554">"名前を変更"</string> <string name="menu_inspect" msgid="7279855349299446224">"詳細情報"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"非表示のファイルを表示"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"別のアプリからファイルを移動することはできません。"</string> <string name="grid_mode_showing" msgid="2803166871485028508">"グリッドモードで表示しています。"</string> <string name="list_mode_showing" msgid="1225413902295895166">"リストモードで表示しています。"</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"ファイル名"</string> </resources> diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml index 592103f84..ddf8bfcd4 100644 --- a/res/values-ka/strings.xml +++ b/res/values-ka/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"ამოღება აქ"</string> + <string name="menu_browse" msgid="6007716414766674967">"დათვალიერება"</string> <string name="menu_rename" msgid="1883113442688817554">"გადარქმევა"</string> <string name="menu_inspect" msgid="7279855349299446224">"ინფორმაციის მიღება"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"გამოჩნდეს დამალული ფაილები"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"ფაილების სხვა აპიდან გადმოტანა შეუძლებელია."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"ნაჩვენებია ბადის რეჟიმში."</string> <string name="list_mode_showing" msgid="1225413902295895166">"ნაჩვენებია სიის რეჟიმში."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"ფაილის სახელი"</string> </resources> diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml index a8f6f25e6..2d6645340 100644 --- a/res/values-kk/strings.xml +++ b/res/values-kk/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Шығарып алу орны"</string> + <string name="menu_browse" msgid="6007716414766674967">"Шолу"</string> <string name="menu_rename" msgid="1883113442688817554">"Атын өзгерту"</string> <string name="menu_inspect" msgid="7279855349299446224">"Ақпарат алу"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Жасырын файлдарды көрсету"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Файлдарды басқа қолданбадан тасымалдай алмайсыз."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Тор режимінде көрсетіледі."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Тізім режимінде көрсетіледі."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Файл атауы"</string> </resources> diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml index ba7900c21..dbe6f87e1 100644 --- a/res/values-km/strings.xml +++ b/res/values-km/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"ស្រង់ចេញទីនេះ"</string> + <string name="menu_browse" msgid="6007716414766674967">"រុករក"</string> <string name="menu_rename" msgid="1883113442688817554">"ប្ដូរឈ្មោះ"</string> <string name="menu_inspect" msgid="7279855349299446224">"ទទួលព័ត៌មាន"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"បង្ហាញឯកសារដែលបានលាក់"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"អ្នកមិនអាចផ្លាស់ទីឯកសារពីកម្មវិធីផ្សេងទៀតបានទេ។"</string> <string name="grid_mode_showing" msgid="2803166871485028508">"បង្ហាញក្នុងមុខងារក្រឡា។"</string> <string name="list_mode_showing" msgid="1225413902295895166">"បង្ហាញក្នុងមុខងារបញ្ជី។"</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"ឈ្មោះឯកសារ"</string> </resources> diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml index 47bb3985d..ab92d4130 100644 --- a/res/values-kn/strings.xml +++ b/res/values-kn/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"ಇಲ್ಲಿ ಎಕ್ಸ್ಟ್ರ್ಯಾಕ್ಟ್ ಮಾಡಿ"</string> + <string name="menu_browse" msgid="6007716414766674967">"ಬ್ರೌಸ್ ಮಾಡಿ"</string> <string name="menu_rename" msgid="1883113442688817554">"ಮರುಹೆಸರಿಸು"</string> <string name="menu_inspect" msgid="7279855349299446224">"ಮಾಹಿತಿಯನ್ನು ಪಡೆಯಿರಿ"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"ಮರೆಮಾಡಿದ ಫೈಲ್ಗಳನ್ನು ತೋರಿಸಿ"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"ನೀವು ಬೇರೊಂದು ಆ್ಯಪ್ನಿಂದ ಫೈಲ್ಗಳನ್ನು ಸರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"ಗ್ರಿಡ್ ಮೋಡ್ನಲ್ಲಿ ತೋರಿಸಲಾಗುತ್ತಿದೆ."</string> <string name="list_mode_showing" msgid="1225413902295895166">"ಪಟ್ಟಿ ಮೋಡ್ನಲ್ಲಿ ತೋರಿಸಲಾಗುತ್ತಿದೆ."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"ಫೈಲ್ ಹೆಸರು"</string> </resources> diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index 6090f1185..a852f9df8 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"여기에서 추출"</string> + <string name="menu_browse" msgid="6007716414766674967">"둘러보기"</string> <string name="menu_rename" msgid="1883113442688817554">"이름 바꾸기"</string> <string name="menu_inspect" msgid="7279855349299446224">"정보 확인"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"숨겨진 파일 표시"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"파일을 다른 앱에서 이동할 수 없습니다."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"그리드 모드로 표시 중입니다."</string> <string name="list_mode_showing" msgid="1225413902295895166">"목록 모드로 표시 중입니다."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"파일 이름"</string> </resources> diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml index 3853ecbf7..1e9a3dcf3 100644 --- a/res/values-ky/strings.xml +++ b/res/values-ky/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Бул жерге чыгаруу"</string> + <string name="menu_browse" msgid="6007716414766674967">"Серептөө"</string> <string name="menu_rename" msgid="1883113442688817554">"Аталышын өзгөртүү"</string> <string name="menu_inspect" msgid="7279855349299446224">"Маалымат алуу"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Жашырылган файлдар көрүнсүн"</string> @@ -110,7 +112,7 @@ <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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Башка колдонмодогу файлдарды жылдырууга болбойт."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Торчо режиминде көрсөтүлүүдө."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Тизме режиминде көрсөтүлүүдө."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Файлдын аты"</string> </resources> diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml index 321c2c528..46370f5c0 100644 --- a/res/values-lo/strings.xml +++ b/res/values-lo/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"ແຍກໄຟລ໌ອອກບ່ອນນີ້"</string> + <string name="menu_browse" msgid="6007716414766674967">"ເລືອກເບິ່ງ"</string> <string name="menu_rename" msgid="1883113442688817554">"ປ່ຽນຊື່"</string> <string name="menu_inspect" msgid="7279855349299446224">"ຂໍຂໍ້ມູນ"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"ສະແດງໄຟລ໌ທີ່ເຊື່ອງໄວ້"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"ບໍ່ສາມາດຍ້າຍໄຟລ໌ຈາກແອັບອື່ນໄດ້."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"ກຳລັງສະແດງໃນໂໝດຕາຕະລາງ."</string> <string name="list_mode_showing" msgid="1225413902295895166">"ກຳລັງສະແດງໃນໂໝດລາຍຊື່."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"ຊື່ໄຟລ໌"</string> </resources> diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml index 415b5469e..1398ebe85 100644 --- a/res/values-lt/strings.xml +++ b/res/values-lt/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Išskleisti čia"</string> + <string name="menu_browse" msgid="6007716414766674967">"Naršyti"</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> @@ -334,6 +336,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Negalite perkelti failų iš kitos programos."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Rodoma tinklelio režimu."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Rodoma sąrašo režimu."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Failo pavadinimas"</string> </resources> diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml index 444f8e5bd..8879c27de 100644 --- a/res/values-lv/strings.xml +++ b/res/values-lv/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Izvilkt šeit"</string> + <string name="menu_browse" msgid="6007716414766674967">"Pārlūkot"</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> @@ -312,6 +314,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Jūs nevarat pārvietot failus no citas lietotnes."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Tiek attēlots režģa režīms."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Tiek attēlots saraksta režīms."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Faila nosaukums"</string> </resources> diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml index ef94b2eba..d61524719 100644 --- a/res/values-mk/strings.xml +++ b/res/values-mk/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Извлечи овде"</string> + <string name="menu_browse" msgid="6007716414766674967">"Прелистувај"</string> <string name="menu_rename" msgid="1883113442688817554">"Преименувај"</string> <string name="menu_inspect" msgid="7279855349299446224">"Добијте информации"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Прикажи скриени датотеки"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Не може да преместувате датотеки од друга апликација."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Се прикажува во режим на решетка."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Се прикажува во режим на список."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Име на датотека"</string> </resources> diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml index 462184507..116ae0291 100644 --- a/res/values-ml/strings.xml +++ b/res/values-ml/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"ഇവിടെ എക്സ്ട്രാക്റ്റുചെയ്യൂ"</string> + <string name="menu_browse" msgid="6007716414766674967">"ബ്രൗസ് ചെയ്യുക"</string> <string name="menu_rename" msgid="1883113442688817554">"പേര് മാറ്റുക"</string> <string name="menu_inspect" msgid="7279855349299446224">"വിവരങ്ങൾ നേടുക"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"മറച്ചിരിക്കുന്ന ഫയൽ കാണിക്കൂ"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"മറ്റ് ആപ്പിൽ നിന്ന് ഫയലുകൾ നീക്കാൻ നിങ്ങൾക്ക് കഴിയില്ല."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"ഗ്രിഡ് മോഡിൽ കാണിക്കുന്നു."</string> <string name="list_mode_showing" msgid="1225413902295895166">"ലിസ്റ്റ് മോഡിൽ കാണിക്കുന്നു."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"ഫയലിന്റെ പേര്"</string> </resources> diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml index e5d0af2a0..28c3f1670 100644 --- a/res/values-mn/strings.xml +++ b/res/values-mn/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Энд задлах"</string> + <string name="menu_browse" msgid="6007716414766674967">"Үзэх"</string> <string name="menu_rename" msgid="1883113442688817554">"Нэр өөрчлөх"</string> <string name="menu_inspect" msgid="7279855349299446224">"Мэдээлэл авах"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Нуусан файлудыг харуул"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Та өөр аппаас файлууд зөөх боломжгүй."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Хүснэгтийн горимд харуулж байна."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Жагсаалтын горимд харуулж байна."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Файлын нэр"</string> </resources> diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml index 2579e8d79..60b72c986 100644 --- a/res/values-mr/strings.xml +++ b/res/values-mr/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"इथे काढा"</string> + <string name="menu_browse" msgid="6007716414766674967">"ब्राउझ करा"</string> <string name="menu_rename" msgid="1883113442688817554">"नाव बदला"</string> <string name="menu_inspect" msgid="7279855349299446224">"माहिती मिळवा"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"लपवलेल्या फाइल दाखवा"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"तुम्ही दुसऱ्या ॲपमधील फाइल हलवू शकत नाही."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"ग्रिड मोडमध्ये दाखवत आहे."</string> <string name="list_mode_showing" msgid="1225413902295895166">"सूची मोडमध्ये दाखवत आहे."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"फाइलचे नाव"</string> </resources> diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml index af2c3d4c1..fe02922e9 100644 --- a/res/values-ms/strings.xml +++ b/res/values-ms/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Ekstrak di sini"</string> + <string name="menu_browse" msgid="6007716414766674967">"Semak imbas"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Anda tidak boleh mengalihkan fail daripada apl lain."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Ditunjukkan dalam mod grid."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Ditunjukkan dalam mod senarai."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Nama fail"</string> </resources> diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml index ea68c88ec..573d0bf48 100644 --- a/res/values-my/strings.xml +++ b/res/values-my/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"ဤနေရာတွင် ထုတ်ယူရန်"</string> + <string name="menu_browse" msgid="6007716414766674967">"ကြည့်ရန်"</string> <string name="menu_rename" msgid="1883113442688817554">"အမည်ပြောင်းပါ"</string> <string name="menu_inspect" msgid="7279855349299446224">"အချက်အလက် ရယူရန်"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"ဝှက်ထားသည့်ဖိုင်များ ပြရန်"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"အခြားအက်ပ်မှဖိုင်ကို ရွှေ့၍မရပါ။"</string> <string name="grid_mode_showing" msgid="2803166871485028508">"ဇယားကွက်မုဒ်ဖြင့် ပြသရန်။"</string> <string name="list_mode_showing" msgid="1225413902295895166">"စာရင်းမုဒ်ဖြင့် ပြသရန်။"</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"ဖိုင်အမည်"</string> </resources> diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index 1c1e6cf0c..d1a9661ee 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Pakk ut her"</string> + <string name="menu_browse" msgid="6007716414766674967">"Bla gjennom"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Du kan ikke flytte filer fra en annen app."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Viser i rutenettmodus."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Viser i listemodus."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Filnavn"</string> </resources> diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml index c52382d79..cb267f0ca 100644 --- a/res/values-ne/strings.xml +++ b/res/values-ne/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"यहाँ एक्स्ट्रयाक्ट गर्नुहोस्"</string> + <string name="menu_browse" msgid="6007716414766674967">"ब्राउज गर्नुहोस्"</string> <string name="menu_rename" msgid="1883113442688817554">"पुनःनामाकरण गर्नुहोस्"</string> <string name="menu_inspect" msgid="7279855349299446224">"जानकारी प्राप्त गर्नुहोस्"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"लुकाइएका फाइलहरू देखाउनुहोस्"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"तपाईं अर्को एपमा रहेका फाइलहरू सार्न सक्नुहुन्न।"</string> <string name="grid_mode_showing" msgid="2803166871485028508">"ग्रिड मोडमा देखाइँदै।"</string> <string name="list_mode_showing" msgid="1225413902295895166">"सूची मोडमा देखाइँदै।"</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"फाइलको नाम"</string> </resources> diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index 0b720010b..4f7add78d 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Hier uitpakken"</string> + <string name="menu_browse" msgid="6007716414766674967">"Browsen"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Je kunt geen bestanden verplaatsen vanuit een andere app."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Tonen in rastermodus."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Tonen in lijstmodus."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Bestandsnaam"</string> </resources> diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml index 186dd9b78..ef985fcbc 100644 --- a/res/values-or/strings.xml +++ b/res/values-or/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"ଏଠାରେ ଏକ୍ସଟ୍ରାକ୍ଟ କରନ୍ତୁ"</string> + <string name="menu_browse" msgid="6007716414766674967">"ବ୍ରାଉଜ କରନ୍ତୁ"</string> <string name="menu_rename" msgid="1883113442688817554">"ରିନେମ କରନ୍ତୁ"</string> <string name="menu_inspect" msgid="7279855349299446224">"ସୂଚନା ପାଆନ୍ତୁ"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"ଲୁକ୍କାୟିତ ଫାଇଲ ଦେଖାନ୍ତୁ"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"ଆପଣ ଅନ୍ୟ ଏକ ଆପରୁ ଫାଇଲଗୁଡ଼ିକ ମୁଭ୍ କରିପାରିବେ ନାହିଁ।"</string> <string name="grid_mode_showing" msgid="2803166871485028508">"ଗ୍ରିଡ୍ ମୋଡରେ ଦେଖାଉଛି।"</string> <string name="list_mode_showing" msgid="1225413902295895166">"ତାଲିକା ମୋଡରେ ଦେଖାଉଛି।"</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"ଫାଇଲ ନାମ"</string> </resources> diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml index 1aec03539..ac450d395 100644 --- a/res/values-pa/strings.xml +++ b/res/values-pa/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"ਇੱਥੇ ਐਕਸਟਰੈਕਟ ਕਰੋ"</string> + <string name="menu_browse" msgid="6007716414766674967">"ਬ੍ਰਾਊਜ਼ ਕਰੋ"</string> <string name="menu_rename" msgid="1883113442688817554">"ਨਾਮ ਬਦਲੋ"</string> <string name="menu_inspect" msgid="7279855349299446224">"ਜਾਣਕਾਰੀ ਪ੍ਰਾਪਤ ਕਰੋ"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"ਲੁਕਾਈਆਂ ਗਈਆਂ ਫ਼ਾਈਲਾਂ ਦਿਖਾਓ"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"ਤੁਸੀਂ ਕਿਸੇ ਹੋਰ ਐਪ ਤੋਂ ਫ਼ਾਈਲਾਂ ਨਹੀਂ ਲਿਜਾ ਸਕਦੇ।"</string> <string name="grid_mode_showing" msgid="2803166871485028508">"ਗ੍ਰਿਡ ਮੋਡ ਵਿੱਚ ਦਿਖਾਈਆਂ ਜਾ ਰਹੀਆਂ ਹਨ"</string> <string name="list_mode_showing" msgid="1225413902295895166">"ਸੂਚੀ ਮੋਡ ਵਿੱਚ ਦਿਖਾਈਆਂ ਜਾ ਰਹੀਆਂ ਹਨ।"</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"ਫ਼ਾਈਲ ਦਾ ਨਾਮ"</string> </resources> diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index 01c9a7339..3e592bc4a 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Rozpakuj tutaj"</string> + <string name="menu_browse" msgid="6007716414766674967">"Przeglądaj"</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> @@ -334,6 +336,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Nie można przenosić plików z innej aplikacji."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Wyświetlanie w trybie siatki."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Wyświetlanie w trybie listy."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Nazwa pliku"</string> </resources> diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml index a203d5885..72b72aa1c 100644 --- a/res/values-pt-rBR/strings.xml +++ b/res/values-pt-rBR/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Extrair aqui"</string> + <string name="menu_browse" msgid="6007716414766674967">"Procurar"</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> @@ -312,6 +314,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Não é possível mover arquivos de outro app."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Exibindo modo de grade."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Exibindo modo de lista."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Nome do arquivo"</string> </resources> diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index f9a0238b3..88466b258 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Extrair para aqui"</string> + <string name="menu_browse" msgid="6007716414766674967">"Procurar"</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> @@ -312,6 +314,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Não pode mover ficheiros de outra app."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"A mostrar no modo de grelha…"</string> <string name="list_mode_showing" msgid="1225413902295895166">"A mostrar no modo de lista…"</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Nome do ficheiro"</string> </resources> diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml index a203d5885..72b72aa1c 100644 --- a/res/values-pt/strings.xml +++ b/res/values-pt/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Extrair aqui"</string> + <string name="menu_browse" msgid="6007716414766674967">"Procurar"</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> @@ -312,6 +314,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Não é possível mover arquivos de outro app."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Exibindo modo de grade."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Exibindo modo de lista."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Nome do arquivo"</string> </resources> diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml index 114b7b5fd..82f43949e 100644 --- a/res/values-ro/strings.xml +++ b/res/values-ro/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Extrage aici"</string> + <string name="menu_browse" msgid="6007716414766674967">"Răsfoiește"</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> @@ -312,6 +314,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Nu poți muta fișiere din altă aplicație."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Se afișează în modul grilă."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Se afișează în modul listă."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Numele fișierului"</string> </resources> diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 003dcf581..931934b27 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Извлечь в текущую папку"</string> + <string name="menu_browse" msgid="6007716414766674967">"Просмотреть"</string> <string name="menu_rename" msgid="1883113442688817554">"Переименовать"</string> <string name="menu_inspect" msgid="7279855349299446224">"Сведения о файле"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Показывать скрытые файлы"</string> @@ -334,6 +336,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Перемещать файлы из другого приложения нельзя."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Показано в виде таблицы."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Показано в виде списка."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Имя файла"</string> </resources> diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml index 9ae7e52fd..9dbe949c9 100644 --- a/res/values-si/strings.xml +++ b/res/values-si/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"මෙතනට උපුටා ගන්න"</string> + <string name="menu_browse" msgid="6007716414766674967">"බ්රවුස් කරන්න"</string> <string name="menu_rename" msgid="1883113442688817554">"යළි නම් කරන්න"</string> <string name="menu_inspect" msgid="7279855349299446224">"තොරතුරු ලබා ගන්න"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"සැඟවුණු ගොනු පෙන්වන්න"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"ඔබට වෙනත් යෙදුමකින් ගොනු ගෙන ඒමට නොහැකිය."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"ජාලක ප්රකාරය තුළ පෙන්වමින්."</string> <string name="list_mode_showing" msgid="1225413902295895166">"ලැයිස්තු ප්රකාරය තුළ පෙන්වමින්."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"ගොනුවේ නම"</string> </resources> diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml index e73cc5f0f..353cfa113 100644 --- a/res/values-sk/strings.xml +++ b/res/values-sk/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Extrahovať tu"</string> + <string name="menu_browse" msgid="6007716414766674967">"Prehliadať"</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> @@ -334,6 +336,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Nemôžete presúvať súbory z inej aplikácie."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Zobrazované v režime mriežky."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Zobrazované v režime zoznamu."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Názov súboru"</string> </resources> diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml index 40430030b..f6d15591f 100644 --- a/res/values-sl/strings.xml +++ b/res/values-sl/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Ekstrahiraj sem"</string> + <string name="menu_browse" msgid="6007716414766674967">"Prebrskaj"</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> @@ -334,6 +336,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Datotek iz druge aplikacije ni mogoče premakniti."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Prikazano v načinu mreže"</string> <string name="list_mode_showing" msgid="1225413902295895166">"Prikazano v načinu seznama"</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Ime datoteke"</string> </resources> diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml index 66acc554c..c8cd908ae 100644 --- a/res/values-sq/strings.xml +++ b/res/values-sq/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Nxirr këtu"</string> + <string name="menu_browse" msgid="6007716414766674967">"Shfleto"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Nuk mund t\'i zhvendosësh skedarët nga një aplikacion tjetër."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Po shfaq në modalitetin \"rrjetë\"."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Po shfaq në modalitetin \"listë\"."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Emri i skedarit"</string> </resources> diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml index 035bdf97d..627e35356 100644 --- a/res/values-sr/strings.xml +++ b/res/values-sr/strings.xml @@ -18,7 +18,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="missing_rename_error" msgid="9098952207447981103">"Морате да преименујете ово"</string> <string name="add_folder_name_error" msgid="6014615052491406810">"Морате да додате назив фолдера"</string> - <string name="files_label" msgid="771781190045103748">"Датотеке"</string> + <string name="files_label" msgid="771781190045103748">"Фајлови"</string> <string name="downloads_label" msgid="5462789470049501103">"Преузимања"</string> <!-- no translation found for app_label (8089292432455111409) --> <skip /> @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Издвој овде"</string> + <string name="menu_browse" msgid="6007716414766674967">"Прегледај"</string> <string name="menu_rename" msgid="1883113442688817554">"Преименуј"</string> <string name="menu_inspect" msgid="7279855349299446224">"Прикажи информације"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Приказуј скривене датотеке"</string> @@ -272,7 +274,7 @@ <item quantity="other">Изабрано је <xliff:g id="COUNT_1">%1$d</xliff:g> ставки</item> </plurals> <string name="root_info_header_recent" msgid="5654901877295332262">"Недавне датотеке"</string> - <string name="root_info_header_global_search" msgid="4904078222280496152">"Датотеке"</string> + <string name="root_info_header_global_search" msgid="4904078222280496152">"Фајлови"</string> <string name="root_info_header_downloads" msgid="8848161246921154115">"Датотеке у Преузимањима"</string> <string name="root_info_header_storage" msgid="2989014130584927442">"Датотеке на уређају <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="root_info_header_folder" msgid="5851172222368049864">"Датотеке у фолдеру <xliff:g id="FOLDER">%1$s</xliff:g>"</string> @@ -312,6 +314,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Не можете да премештате датотеке из друге апликације."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Приказује се у режиму мреже."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Приказује се у режиму листе."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Назив фајла"</string> </resources> diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index 0040eaa36..dab4bfbe2 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Extrahera hit"</string> + <string name="menu_browse" msgid="6007716414766674967">"Bläddra"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Du kan inte flytta filer från en annan app."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Visas i rutnätsläge."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Visas i listläge."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Filnamn"</string> </resources> diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml index 18a0bce3e..7ec3309cf 100644 --- a/res/values-sw/strings.xml +++ b/res/values-sw/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Dondoa hapa"</string> + <string name="menu_browse" msgid="6007716414766674967">"Vinjari"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Huwezi kuhamisha faili kutoka programu nyingine."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Kuonyesha katika hali ya gridi."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Kuonyesha katika hali ya orodha."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Jina la faili"</string> </resources> diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml index e4b46e2e0..35a856f23 100644 --- a/res/values-ta/strings.xml +++ b/res/values-ta/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"இங்கே பிரித்தெடு"</string> + <string name="menu_browse" msgid="6007716414766674967">"பிரவுசிங் செய்"</string> <string name="menu_rename" msgid="1883113442688817554">"பெயர் மாற்று"</string> <string name="menu_inspect" msgid="7279855349299446224">"தகவலைப் பெறு"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"மறைக்கப்பட்ட ஃபைல்களைக் காட்டு"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"வேறொரு ஆப்ஸிலிருந்து ஃபைல்களை நகர்த்த முடியாது."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"கட்டக் காட்சியில் காட்டுகிறது."</string> <string name="list_mode_showing" msgid="1225413902295895166">"பட்டியல் காட்சியில் காட்டுகிறது."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"ஃபைல் பெயர்"</string> </resources> diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml index 178a14435..ba463359d 100644 --- a/res/values-te/strings.xml +++ b/res/values-te/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"ఇక్కడికి సంగ్రహించండి"</string> + <string name="menu_browse" msgid="6007716414766674967">"బ్రౌజ్ చేయండి"</string> <string name="menu_rename" msgid="1883113442688817554">"పేరు మార్చు"</string> <string name="menu_inspect" msgid="7279855349299446224">"సమాచారాన్ని పొందండి"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"దాచబడిన ఫైళ్లను చూపించు"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"మీరు వేరే ఇతర యాప్ నుండి ఫైల్స్ను తరలించలేరు."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"గ్రిడ్ మోడ్లో చూపుతోంది."</string> <string name="list_mode_showing" msgid="1225413902295895166">"లిస్ట్ మోడ్లో చూపుతోంది."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"ఫైల్ పేరు"</string> </resources> diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml index 6fdee1ef1..10181068d 100644 --- a/res/values-th/strings.xml +++ b/res/values-th/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"แตกไฟล์ที่นี่"</string> + <string name="menu_browse" msgid="6007716414766674967">"เรียกดู"</string> <string name="menu_rename" msgid="1883113442688817554">"เปลี่ยนชื่อ"</string> <string name="menu_inspect" msgid="7279855349299446224">"รับข้อมูล"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"แสดงไฟล์ที่ซ่อนไว้"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"คุณย้ายไฟล์จากแอปอื่นไม่ได้"</string> <string name="grid_mode_showing" msgid="2803166871485028508">"กำลังแสดงในโหมดตารางกริด"</string> <string name="list_mode_showing" msgid="1225413902295895166">"กำลังแสดงในโหมดรายการ"</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"ชื่อไฟล์"</string> </resources> diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml index a834e85d6..3befbf583 100644 --- a/res/values-tl/strings.xml +++ b/res/values-tl/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"I-extract dito"</string> + <string name="menu_browse" msgid="6007716414766674967">"Mag-browse"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Hindi ka makakapaglipat ng mga file mula sa ibang app."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Ipinapakita sa grid mode."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Ipinapakita sa list mode."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Pangalan ng file"</string> </resources> diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index 7d63323c7..490f9ca29 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Buraya çıkar"</string> + <string name="menu_browse" msgid="6007716414766674967">"Göz at"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Başka bir uygulamadan dosya taşıyamazsınız."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Tablo modunda gösteriliyor."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Liste modunda gösteriliyor."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Dosya adı"</string> </resources> diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index ff0908cd1..52f36ec44 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Розпакувати тут"</string> + <string name="menu_browse" msgid="6007716414766674967">"Переглянути"</string> <string name="menu_rename" msgid="1883113442688817554">"Перейменувати"</string> <string name="menu_inspect" msgid="7279855349299446224">"Переглянути інформацію"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"Показувати приховані файли"</string> @@ -334,6 +336,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Не можна переміщувати файли з іншого додатка."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Перегляд у режимі таблиці."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Перегляд у режимі списку."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Назва файлу"</string> </resources> diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml index 8e18775b3..9f20a9957 100644 --- a/res/values-ur/strings.xml +++ b/res/values-ur/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"یہاں نکالیں"</string> + <string name="menu_browse" msgid="6007716414766674967">"براؤز کریں"</string> <string name="menu_rename" msgid="1883113442688817554">"نام تبدیل کریں"</string> <string name="menu_inspect" msgid="7279855349299446224">"معلومات حاصل کریں"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"پوشیدہ فائلز دکھائیں"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"آپ کسی اور ایپ سے فائلیں منتقل نہیں کر سکتے ہیں۔"</string> <string name="grid_mode_showing" msgid="2803166871485028508">"گرڈ وضع میں دکھائی جا رہی ہیں۔"</string> <string name="list_mode_showing" msgid="1225413902295895166">"فہرست وضع میں دکھائی جا رہی ہیں۔"</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"فائل کا نام"</string> </resources> diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml index 28ef40fd0..8e7c154f9 100644 --- a/res/values-uz/strings.xml +++ b/res/values-uz/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Shu yerga chiqarish"</string> + <string name="menu_browse" msgid="6007716414766674967">"Kezish"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Fayllarni boshqa ilovadan koʻchirish imkonsiz."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Jadval shaklida chiqarilmoqda."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Roʻyxat shaklida chiqarilmoqda."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Fayl nomi"</string> </resources> diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index 06812bf71..9d3fe1683 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Trích xuất ở đây"</string> + <string name="menu_browse" msgid="6007716414766674967">"Duyệt xem"</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 các tệp bị ẩn"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Bạn không thể di chuyển các tệp từ một ứng dụng khác."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Đang hiển thị ở chế độ lưới."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Đang hiển thị ở chế độ danh sách."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Tên tệp"</string> </resources> diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 262899eaf..939830937 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"解压缩到此处"</string> + <string name="menu_browse" msgid="6007716414766674967">"浏览"</string> <string name="menu_rename" msgid="1883113442688817554">"重命名"</string> <string name="menu_inspect" msgid="7279855349299446224">"获取信息"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"显示隐藏的文件"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"您无法移动其他应用中的文件。"</string> <string name="grid_mode_showing" msgid="2803166871485028508">"目前以网格模式显示。"</string> <string name="list_mode_showing" msgid="1225413902295895166">"目前以列表模式显示。"</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"文件名"</string> </resources> diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml index 5412fd3f6..aa923d75b 100644 --- a/res/values-zh-rHK/strings.xml +++ b/res/values-zh-rHK/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"從這裡擷取"</string> + <string name="menu_browse" msgid="6007716414766674967">"瀏覽"</string> <string name="menu_rename" msgid="1883113442688817554">"重新命名"</string> <string name="menu_inspect" msgid="7279855349299446224">"顯示資訊"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"顯示已隱藏的檔案"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"你無法移動其他應用程式的檔案。"</string> <string name="grid_mode_showing" msgid="2803166871485028508">"用格狀模式顯示緊。"</string> <string name="list_mode_showing" msgid="1225413902295895166">"用清單模式顯示緊。"</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"檔案名稱"</string> </resources> diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index 4f933af44..9c99307b2 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"從這裡擷取"</string> + <string name="menu_browse" msgid="6007716414766674967">"瀏覽"</string> <string name="menu_rename" msgid="1883113442688817554">"重新命名"</string> <string name="menu_inspect" msgid="7279855349299446224">"取得資訊"</string> <string name="menu_show_hidden_files" msgid="5140676344684492769">"顯示隱藏的檔案"</string> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"你無法將其他應用程式中的檔案移動至此。"</string> <string name="grid_mode_showing" msgid="2803166871485028508">"目前以格線模式顯示。"</string> <string name="list_mode_showing" msgid="1225413902295895166">"目前以清單模式顯示。"</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"檔案名稱"</string> </resources> diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml index 35483b5c1..80c39b98f 100644 --- a/res/values-zu/strings.xml +++ b/res/values-zu/strings.xml @@ -46,6 +46,8 @@ <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_extract_here" msgid="8725302045721604762">"Khipha lapha"</string> + <string name="menu_browse" msgid="6007716414766674967">"Bhrawuza"</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> @@ -290,6 +292,6 @@ <string name="drag_from_another_app" msgid="8310249276199969905">"Awukwazi ukuhambisa amafayela kusuka kolunye uhlelo lokusebenza."</string> <string name="grid_mode_showing" msgid="2803166871485028508">"Ibonisa kumodi yegridi."</string> <string name="list_mode_showing" msgid="1225413902295895166">"Ibonisa kumodi yohlu."</string> - <!-- no translation found for bullet (5606740650312122766) --> - <skip /> + <string name="bullet" msgid="5606740650312122766">"•"</string> + <string name="file_name_hint" msgid="7843637320487415838">"Igama lefayela"</string> </resources> diff --git a/res/values/strings.xml b/res/values/strings.xml index fc97d2c7d..c3f11bab4 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -429,6 +429,7 @@ =1 {Zipping <xliff:g id="filename" example="foobar.txt">{filename}</xliff:g>} other {Zipping # files} }</string> + <string name="job_progress_panel_title" translatable="false">File Progress</string> <!-- Text in an alert dialog asking user to grant app access to a given directory in an external storage volume --> <string name="open_external_dialog_request">Grant <xliff:g id="appName" example="System Settings"><b>^1</b></xliff:g> @@ -611,4 +612,6 @@ <!-- Unicode Character “•” (U+2022). --> <string name="bullet">\u2022</string> + <!-- Text used at the top of the text field when saving a document. [CHAR_LIMIT=100] --> + <string name="file_name_hint">File name</string> </resources> diff --git a/src/com/android/documentsui/AbstractActionHandler.java b/src/com/android/documentsui/AbstractActionHandler.java index de193e235..89e9bc2d6 100644 --- a/src/com/android/documentsui/AbstractActionHandler.java +++ b/src/com/android/documentsui/AbstractActionHandler.java @@ -20,7 +20,8 @@ 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.util.FlagUtils.isDesktopFileHandlingFlagEnabled; -import static com.android.documentsui.util.FlagUtils.isUseSearchV2RwFlagEnabled; +import static com.android.documentsui.util.FlagUtils.isUseSearchV2FlagEnabled; +import static com.android.documentsui.util.FlagUtils.isZipNgFlagEnabled; import android.app.PendingIntent; import android.content.ActivityNotFoundException; @@ -458,17 +459,17 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA private boolean viewDocument(DocumentInfo doc) { if (doc.isPartial()) { - Log.w(TAG, "Can't view partial file."); + Log.w(TAG, "Cannot view partial file"); return false; } - if (doc.isInArchive()) { - Log.w(TAG, "Can't view files in archives."); + if (!isZipNgFlagEnabled() && doc.isInArchive()) { + Log.w(TAG, "Cannot view file in archive"); return false; } if (doc.isDirectory()) { - Log.w(TAG, "Can't view directories."); + Log.w(TAG, "Cannot view directory"); return true; } @@ -916,7 +917,7 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA mState.stack.changeRoot(mActivity.getCurrentRoot()); } - if (isUseSearchV2RwFlagEnabled()) { + if (isUseSearchV2FlagEnabled()) { return onCreateLoaderV2(id, args); } return onCreateLoaderV1(id, args); diff --git a/src/com/android/documentsui/BaseActivity.java b/src/com/android/documentsui/BaseActivity.java index ab40eca3f..8a5779a69 100644 --- a/src/com/android/documentsui/BaseActivity.java +++ b/src/com/android/documentsui/BaseActivity.java @@ -577,23 +577,32 @@ public abstract class BaseActivity View root = findViewById(R.id.coordinator_layout); root.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); - root.setOnApplyWindowInsetsListener((v, insets) -> { - root.setPadding(insets.getSystemWindowInsetLeft(), - insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), 0); - - // When use_material3 flag is ON, no additional bottom gap in full screen mode. - if (!isUseMaterial3FlagEnabled()) { - 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()); - } + root.setOnApplyWindowInsetsListener( + (v, insets) -> { + root.setPadding( + insets.getSystemWindowInsetLeft(), + insets.getSystemWindowInsetTop(), + insets.getSystemWindowInsetRight(), + 0); + + // When use_material3 flag is ON and FEATURE_FREEFORM_WINDOW_MANAGEMENT is + // enabled, then there should not be any additional bottom gap in full screen + // mode. Otherwise need to take into account the system window insets such as + // the bottom swipe up navigation gesture. + if (!isUseMaterial3FlagEnabled() + || !getApplicationContext() + .getPackageManager() + .hasSystemFeature( + PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT)) { + 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()); + } - return insets.consumeSystemWindowInsets(); - }); + return insets.consumeSystemWindowInsets(); + }); getWindow().setNavigationBarDividerColor(Color.TRANSPARENT); if (Build.VERSION.SDK_INT >= 29) { diff --git a/src/com/android/documentsui/DragAndDropManager.java b/src/com/android/documentsui/DragAndDropManager.java index bed8764ae..158d43c95 100644 --- a/src/com/android/documentsui/DragAndDropManager.java +++ b/src/com/android/documentsui/DragAndDropManager.java @@ -16,6 +16,8 @@ package com.android.documentsui; +import static com.android.documentsui.util.FlagUtils.isUseMaterial3FlagEnabled; + import android.content.ClipData; import android.content.Context; import android.graphics.drawable.Drawable; @@ -277,7 +279,9 @@ public interface DragAndDropManager { final Drawable icon; final int size = srcs.size(); - if (size == 1) { + // If use_material3 flag is ON, we always show the icon/title for the first file even + // when we have multiple files. + if (size == 1 || isUseMaterial3FlagEnabled()) { DocumentInfo doc = srcs.get(0); title = doc.displayName; icon = iconHelper.getDocumentIcon(mContext, doc); @@ -287,6 +291,10 @@ public interface DragAndDropManager { icon = mDefaultShadowIcon; } + if (isUseMaterial3FlagEnabled()) { + mShadowBuilder.updateDragFileCount(size); + } + mShadowBuilder.updateTitle(title); mShadowBuilder.updateIcon(icon); diff --git a/src/com/android/documentsui/DragShadowBuilder.java b/src/com/android/documentsui/DragShadowBuilder.java index 10a0106d5..be76302e8 100644 --- a/src/com/android/documentsui/DragShadowBuilder.java +++ b/src/com/android/documentsui/DragShadowBuilder.java @@ -16,7 +16,7 @@ package com.android.documentsui; -import com.android.documentsui.DragAndDropManager.State; +import static com.android.documentsui.util.FlagUtils.isUseMaterial3FlagEnabled; import android.content.Context; import android.graphics.Canvas; @@ -29,6 +29,12 @@ import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; +import androidx.annotation.Nullable; + +import com.android.documentsui.DragAndDropManager.State; + +import java.text.NumberFormat; + class DragShadowBuilder extends View.DragShadowBuilder { private final View mShadowView; @@ -37,8 +43,18 @@ class DragShadowBuilder extends View.DragShadowBuilder { private final int mWidth; private final int mHeight; private final int mShadowRadius; - private int mPadding; + private final int mPadding; private Paint paint; + // This will be null if use_material3 flag is OFF. + private final @Nullable View mAdditionalShadowView; + // This will always be 0 if the use_material3 flag is OFF. + private int mDragFileCount = 0; + // The following 5 dimensions will be 0 if the use_material3 flag is OFF. + private final int mDragContentRadius; + private final int mAdditionalLayerOffset; + private final int mDragFileCounterOffset; + private final int mShadow2Radius; + private final int mShadowYOffset; DragShadowBuilder(Context context) { mWidth = context.getResources().getDimensionPixelSize(R.dimen.drag_shadow_width); @@ -49,6 +65,28 @@ class DragShadowBuilder extends View.DragShadowBuilder { mShadowView = LayoutInflater.from(context).inflate(R.layout.drag_shadow_layout, null); mTitle = (TextView) mShadowView.findViewById(android.R.id.title); mIcon = (DropBadgeView) mShadowView.findViewById(android.R.id.icon); + if (isUseMaterial3FlagEnabled()) { + mAdditionalShadowView = + LayoutInflater.from(context).inflate(R.layout.additional_drag_shadow, null); + mDragContentRadius = + context.getResources().getDimensionPixelSize(R.dimen.drag_content_radius); + mAdditionalLayerOffset = + context.getResources() + .getDimensionPixelSize(R.dimen.drag_additional_layer_offset); + mDragFileCounterOffset = + context.getResources().getDimensionPixelSize(R.dimen.drag_file_counter_offset); + mShadow2Radius = + context.getResources().getDimensionPixelSize(R.dimen.drag_shadow_2_radius); + mShadowYOffset = + context.getResources().getDimensionPixelSize(R.dimen.drag_shadow_y_offset); + } else { + mAdditionalShadowView = null; + mDragContentRadius = 0; + mAdditionalLayerOffset = 0; + mDragFileCounterOffset = 0; + mShadow2Radius = 0; + mShadowYOffset = 0; + } // Important for certain APIs mShadowView.setLayerType(View.LAYER_TYPE_SOFTWARE, paint); @@ -67,23 +105,86 @@ class DragShadowBuilder extends View.DragShadowBuilder { Rect r = canvas.getClipBounds(); // Calling measure is necessary in order for all child views to get correctly laid out. mShadowView.measure( - View.MeasureSpec.makeMeasureSpec(r.right- r.left, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(r.right - r.left, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(r.bottom - r.top , View.MeasureSpec.EXACTLY)); mShadowView.layout(r.left, r.top, r.right, r.bottom); // Since DragShadow is not an actual view drawn in hardware-accelerated window, // android:elevation does not work; we need to draw the shadow ourselves manually. paint.setColor(Color.TRANSPARENT); - // Shadow 1 - int opacity = (int) (255 * 0.1); - paint.setShadowLayer(mShadowRadius, 0, 0, Color.argb(opacity, 0, 0, 0)); - canvas.drawRect(r.left + mPadding, r.top + mPadding, r.right - mPadding, - r.bottom - mPadding, paint); - // Shadow 2 - opacity = (int) (255 * 0.24); - paint.setShadowLayer(mShadowRadius, 0, mShadowRadius, Color.argb(opacity, 0, 0, 0)); - canvas.drawRect(r.left + mPadding, r.top + mPadding, r.right - mPadding, - r.bottom - mPadding, paint); + + // Layers on the canvas (from bottom to top): + // 1. Two shadows for the additional drag layer (if drag file count > 1) + // 2. The additional layer view itself (if drag file count > 1) + // 3. Two shadows for the drag content layer (icon, title) + // 4. The drag content layer itself + final int shadowOneOpacity = (int) (255 * 0.15); + final int shadowTwoOpacity = (int) (255 * 0.30); + if (mAdditionalShadowView != null && mDragFileCount > 1) { + mAdditionalShadowView.measure( + View.MeasureSpec.makeMeasureSpec(r.right - r.left, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(r.bottom - r.top , View.MeasureSpec.EXACTLY)); + mAdditionalShadowView.layout(r.left, r.top, r.right, r.bottom); + // Shadow 1 + paint.setShadowLayer( + mShadowRadius, 0, mShadowYOffset, Color.argb(shadowOneOpacity, 0, 0, 0)); + canvas.drawRoundRect( + r.left + mShadowRadius, + r.top + mDragFileCounterOffset + mAdditionalLayerOffset, + r.right - mDragFileCounterOffset - mAdditionalLayerOffset, + r.bottom - mShadowRadius, + mDragContentRadius, + mDragContentRadius, + paint); + // Shadow 2 + paint.setShadowLayer( + mShadow2Radius, 0, mShadowYOffset, Color.argb(shadowTwoOpacity, 0, 0, 0)); + canvas.drawRoundRect( + r.left + mShadowRadius, + r.top + mDragFileCounterOffset + mAdditionalLayerOffset, + r.right - mDragFileCounterOffset - mAdditionalLayerOffset, + r.bottom - mShadowRadius, + mDragContentRadius, + mDragContentRadius, + paint); + mAdditionalShadowView.draw(canvas); + } + + if (isUseMaterial3FlagEnabled()) { + // Shadow 1 + paint.setShadowLayer( + mShadowRadius, 0, mShadowYOffset, Color.argb(shadowOneOpacity, 0, 0, 0)); + canvas.drawRoundRect( + r.left + mShadowRadius + mAdditionalLayerOffset, + r.top + mDragFileCounterOffset, + r.right - mDragFileCounterOffset, + r.bottom - mShadowRadius - mAdditionalLayerOffset, + mDragContentRadius, + mDragContentRadius, + paint); + // Shadow 2 + paint.setShadowLayer( + mShadow2Radius, 0, mShadowYOffset, Color.argb(shadowTwoOpacity, 0, 0, 0)); + canvas.drawRoundRect( + r.left + mShadowRadius + mAdditionalLayerOffset, + r.top + mDragFileCounterOffset, + r.right - mDragFileCounterOffset, + r.bottom - mShadowRadius - mAdditionalLayerOffset, + mDragContentRadius, + mDragContentRadius, + paint); + } else { + // Shadow 1 + int opacity = (int) (255 * 0.1); + paint.setShadowLayer(mShadowRadius, 0, 0, Color.argb(opacity, 0, 0, 0)); + canvas.drawRect(r.left + mPadding, r.top + mPadding, r.right - mPadding, + r.bottom - mPadding, paint); + // Shadow 2 + opacity = (int) (255 * 0.24); + paint.setShadowLayer(mShadowRadius, 0, mShadowRadius, Color.argb(opacity, 0, 0, 0)); + canvas.drawRect(r.left + mPadding, r.top + mPadding, r.right - mPadding, + r.bottom - mPadding, paint); + } mShadowView.draw(canvas); } @@ -98,4 +199,19 @@ class DragShadowBuilder extends View.DragShadowBuilder { void onStateUpdated(@State int state) { mIcon.updateState(state); } + + void updateDragFileCount(int count) { + if (!isUseMaterial3FlagEnabled()) { + return; + } + mDragFileCount = count; + TextView dragFileCountView = mShadowView.findViewById(R.id.drag_file_counter); + if (dragFileCountView != null) { + dragFileCountView.setVisibility(count > 1 ? View.VISIBLE : View.GONE); + if (count > 1) { + NumberFormat numberFormat = NumberFormat.getInstance(); + dragFileCountView.setText(numberFormat.format(count)); + } + } + } } diff --git a/src/com/android/documentsui/HorizontalBreadcrumb.java b/src/com/android/documentsui/HorizontalBreadcrumb.java index 94f0e13f9..9d2fc723e 100644 --- a/src/com/android/documentsui/HorizontalBreadcrumb.java +++ b/src/com/android/documentsui/HorizontalBreadcrumb.java @@ -16,6 +16,8 @@ package com.android.documentsui; +import static com.android.documentsui.util.FlagUtils.isUseMaterial3FlagEnabled; + import android.content.Context; import android.util.AttributeSet; import android.view.GestureDetector; @@ -25,6 +27,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.Nullable; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -45,6 +48,9 @@ public final class HorizontalBreadcrumb extends RecyclerView implements Breadcru private LinearLayoutManager mLayoutManager; private BreadcrumbAdapter mAdapter; private IntConsumer mClickListener; + // Represents the top divider (border) of the breadcrumb on the compact size screen. + // It will be null on other screen sizes, or when the use_material3 flag is OFF. + private @Nullable View mTopDividerView; public HorizontalBreadcrumb(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); @@ -61,12 +67,14 @@ public final class HorizontalBreadcrumb extends RecyclerView implements Breadcru @Override public void setup(Environment env, com.android.documentsui.base.State state, - IntConsumer listener) { + IntConsumer listener, + @Nullable View topDivider) { mClickListener = listener; mLayoutManager = new HorizontalBreadcrumbLinearLayoutManager( getContext(), LinearLayoutManager.HORIZONTAL, false); mAdapter = new BreadcrumbAdapter(state, env, this::onKey); + mTopDividerView = topDivider; // Since we are using GestureDetector to detect click events, a11y services don't know which // views are clickable because we aren't using View.OnClickListener. Thus, we need to use a // custom accessibility delegate to route click events correctly. @@ -109,6 +117,9 @@ public final class HorizontalBreadcrumb extends RecyclerView implements Breadcru setVisibility(GONE); setAdapter(null); } + if (mTopDividerView != null) { + mTopDividerView.setVisibility(visibility ? VISIBLE : GONE); + } mAdapter.updateLastItemSize(); } @@ -174,8 +185,6 @@ public final class HorizontalBreadcrumb extends RecyclerView implements Breadcru @Override public void onBindViewHolder(BreadcrumbHolder holder, int position) { - final int padding = (int) holder.itemView.getResources() - .getDimension(R.dimen.breadcrumb_item_padding); final boolean isFirst = position == 0; // Note that when isFirst is true, there might not be a DocumentInfo on the stack as it // could be an error state screen accessible from the root info. @@ -183,9 +192,45 @@ public final class HorizontalBreadcrumb extends RecyclerView implements Breadcru holder.mTitle.setText( isFirst ? mEnv.getCurrentRoot().title : mState.stack.get(position).displayName); - holder.mTitle.setEnabled(isLast); - holder.mTitle.setPadding(isFirst ? padding * 3 : padding, - padding, isLast ? padding * 2 : padding, padding); + if (isUseMaterial3FlagEnabled()) { + // The last path part in the breadcrumb is not clickable. + holder.mTitle.setEnabled(!isLast); + } else { + holder.mTitle.setEnabled(isLast); + } + if (isUseMaterial3FlagEnabled()) { + final int paddingHorizontal = + (int) + holder.itemView + .getResources() + .getDimension(R.dimen.breadcrumb_item_padding_horizontal); + final int paddingVertical = + (int) + holder.itemView + .getResources() + .getDimension(R.dimen.breadcrumb_item_padding_vertical); + final int arrowPadding = + (int) + holder.itemView + .getResources() + .getDimension(R.dimen.breadcrumb_item_arrow_padding); + holder.mTitle.setPadding( + paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical); + + ViewGroup.MarginLayoutParams params = + (ViewGroup.MarginLayoutParams) holder.mArrow.getLayoutParams(); + params.setMarginStart(arrowPadding); + params.setMarginEnd(arrowPadding); + holder.mArrow.setLayoutParams(params); + } else { + final int padding = (int) holder.itemView.getResources() + .getDimension(R.dimen.breadcrumb_item_padding); + holder.mTitle.setPadding( + isFirst ? padding * 3 : padding, + padding, + isLast ? padding * 2 : padding, + padding); + } holder.mArrow.setVisibility(isLast ? View.GONE : View.VISIBLE); holder.itemView.setOnKeyListener(mClickListener); diff --git a/src/com/android/documentsui/IconUtils.java b/src/com/android/documentsui/IconUtils.java index 1763fd2a3..477209150 100644 --- a/src/com/android/documentsui/IconUtils.java +++ b/src/com/android/documentsui/IconUtils.java @@ -16,15 +16,56 @@ package com.android.documentsui; +import static com.android.documentsui.util.FlagUtils.isUseMaterial3FlagEnabled; + import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; +import android.content.res.Resources; +import android.graphics.Outline; import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon; import android.util.TypedValue; +import android.view.View; +import android.view.ViewOutlineProvider; +import android.widget.ImageView; import com.android.documentsui.base.UserId; +import com.android.documentsui.util.ColorUtils; + +import java.util.HashMap; +import java.util.Map; public class IconUtils { + // key: drawable resource id, value: color attribute id + private static final Map<Integer, Integer> sCustomIconColorMap = new HashMap<>(); + + static { + if (isUseMaterial3FlagEnabled()) { + // Use Resources.getSystem().getIdentifier() here instead of R.drawable.ic_doc_folder + // because com.android.internal.R is not public. + sCustomIconColorMap.put( + Resources.getSystem().getIdentifier("ic_doc_folder", "drawable", "android"), + com.google.android.material.R.attr.colorPrimaryFixedDim); + sCustomIconColorMap.put( + Resources.getSystem().getIdentifier("ic_doc_generic", "drawable", "android"), + com.google.android.material.R.attr.colorOutline); + sCustomIconColorMap.put( + Resources.getSystem() + .getIdentifier("ic_doc_certificate", "drawable", "android"), + com.google.android.material.R.attr.colorOutline); + sCustomIconColorMap.put( + Resources.getSystem().getIdentifier("ic_doc_codes", "drawable", "android"), + com.google.android.material.R.attr.colorOutline); + sCustomIconColorMap.put( + Resources.getSystem().getIdentifier("ic_doc_contact", "drawable", "android"), + com.google.android.material.R.attr.colorOutline); + sCustomIconColorMap.put( + Resources.getSystem().getIdentifier("ic_doc_font", "drawable", "android"), + com.google.android.material.R.attr.colorOutline); + } + } + public static Drawable loadPackageIcon(Context context, UserId userId, String authority, int icon, boolean maybeShowBadge) { if (icon != 0) { @@ -61,7 +102,17 @@ public class IconUtils { */ public static Drawable loadMimeIcon(Context context, String mimeType) { if (mimeType == null) return null; - return context.getContentResolver().getTypeInfo(mimeType).getIcon().loadDrawable(context); + Icon icon = context.getContentResolver().getTypeInfo(mimeType).getIcon(); + Drawable drawable = icon.loadDrawable(context); + // TODO(b/400263417): Remove this once RRO mime icons support dynamic colors. + if (isUseMaterial3FlagEnabled() + && drawable != null + && sCustomIconColorMap.containsKey(icon.getResId())) { + drawable.setTint( + ColorUtils.resolveMaterialColorAttribute( + context, sCustomIconColorMap.get(icon.getResId()))); + } + return drawable; } public static Drawable applyTintColor(Context context, int drawableId, int tintColorId) { @@ -80,4 +131,32 @@ public class IconUtils { context.getTheme().resolveAttribute(tintAttrId, outValue, true); return applyTintColor(context, drawableId, outValue.resourceId); } + + /** + * When a ImageView loads a thumbnail from a bitmap, we usually uses a CardView to wrap it to + * apply CardView's corner radius to the ImageView. This causes the corner pixelation of the + * thumbnail especially when there's a border (stroke) around the CardView. This method creates + * a custom clip outline with the correct shape to fix this issue. + * + * @param imageView ImageView to apply clip outline. + * @param strokeWidth stroke width of the thumbnail. + * @param cornerRadius corner radius of the thumbnail. + */ + public static void applyThumbnailClipOutline( + ImageView imageView, int strokeWidth, int cornerRadius) { + ViewOutlineProvider outlineProvider = + new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect( + strokeWidth, + strokeWidth, + view.getWidth() - strokeWidth, + view.getHeight() - strokeWidth, + cornerRadius); + } + }; + imageView.setOutlineProvider(outlineProvider); + imageView.setClipToOutline(true); + } } diff --git a/src/com/android/documentsui/JobPanelController.kt b/src/com/android/documentsui/JobPanelController.kt new file mode 100644 index 000000000..a8ab8b0a4 --- /dev/null +++ b/src/com/android/documentsui/JobPanelController.kt @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.documentsui + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.util.Log +import android.view.LayoutInflater +import android.view.MenuItem +import android.view.ViewGroup +import android.widget.PopupWindow +import android.widget.ProgressBar +import com.android.documentsui.base.Menus +import com.android.documentsui.services.FileOperationService +import com.android.documentsui.services.FileOperationService.EXTRA_PROGRESS +import com.android.documentsui.services.Job +import com.android.documentsui.services.JobProgress + +/** + * JobPanelController is responsible for receiving broadcast updates from the [FileOperationService] + * and updating a given menu item to reflect the current progress. + */ +class JobPanelController(private val mContext: Context) : BroadcastReceiver() { + companion object { + private const val TAG = "JobPanelController" + private const val MAX_PROGRESS = 100 + } + + private enum class State { + INVISIBLE, INDETERMINATE, VISIBLE + } + + /** The current state of the menu progress item. */ + private var mState = State.INVISIBLE + + /** The total progress from 0 to MAX_PROGRESS. */ + private var mTotalProgress = 0 + + /** List of jobs currently tracked by this class. */ + private val mCurrentJobs = LinkedHashMap<String, JobProgress>() + + /** Current menu item being controlled by this class. */ + private var mMenuItem: MenuItem? = null + + init { + val filter = IntentFilter(FileOperationService.ACTION_PROGRESS) + mContext.registerReceiver(this, filter, Context.RECEIVER_NOT_EXPORTED) + } + + private fun updateMenuItem(animate: Boolean) { + mMenuItem?.let { + Menus.setEnabledAndVisible(it, mState != State.INVISIBLE) + val icon = it.actionView as ProgressBar + when (mState) { + State.INDETERMINATE -> icon.isIndeterminate = true + State.VISIBLE -> icon.apply { + isIndeterminate = false + setProgress(mTotalProgress, animate) + } + State.INVISIBLE -> {} + } + } + } + + /** + * Sets the menu item controlled by this class. The item's actionView must be a [ProgressBar]. + */ + @Suppress("ktlint:standard:comment-wrapping") + fun setMenuItem(menuItem: MenuItem) { + val progressIcon = menuItem.actionView as ProgressBar + progressIcon.max = MAX_PROGRESS + progressIcon.setOnClickListener { view -> + val panel = LayoutInflater.from(mContext).inflate( + R.layout.job_progress_panel, + /* root= */ null + ) + val popupWidth = mContext.resources.getDimension(R.dimen.job_progress_panel_width) + + mContext.resources.getDimension(R.dimen.job_progress_panel_margin) + val popup = PopupWindow( + /* contentView= */ panel, + /* width= */ popupWidth.toInt(), + /* height= */ ViewGroup.LayoutParams.WRAP_CONTENT, + /* focusable= */ true + ) + popup.showAsDropDown( + /* anchor= */ view, + /* xoff= */ view.width - popupWidth.toInt(), + /* yoff= */ 0 + ) + } + mMenuItem = menuItem + updateMenuItem(animate = false) + } + + override fun onReceive(context: Context?, intent: Intent) { + val progresses = intent.getParcelableArrayListExtra<JobProgress>( + EXTRA_PROGRESS, + JobProgress::class.java + ) + updateProgress(progresses!!) + } + + private fun updateProgress(progresses: List<JobProgress>) { + var requiredBytes = 0L + var currentBytes = 0L + var allFinished = true + + for (jobProgress in progresses) { + Log.d(TAG, "Received $jobProgress") + mCurrentJobs.put(jobProgress.id, jobProgress) + } + for (jobProgress in mCurrentJobs.values) { + if (jobProgress.state != Job.STATE_COMPLETED) { + allFinished = false + } + if (jobProgress.requiredBytes != -1L && jobProgress.currentBytes != -1L) { + requiredBytes += jobProgress.requiredBytes + currentBytes += jobProgress.currentBytes + } + } + + if (mCurrentJobs.isEmpty()) { + mState = State.INVISIBLE + } else if (requiredBytes != 0L) { + mState = State.VISIBLE + mTotalProgress = (MAX_PROGRESS * currentBytes / requiredBytes).toInt() + } else if (allFinished) { + mState = State.VISIBLE + mTotalProgress = MAX_PROGRESS + } else { + mState = State.INDETERMINATE + } + updateMenuItem(animate = true) + } +} diff --git a/src/com/android/documentsui/MenuManager.java b/src/com/android/documentsui/MenuManager.java index 5f17d7e02..a46659c77 100644 --- a/src/com/android/documentsui/MenuManager.java +++ b/src/com/android/documentsui/MenuManager.java @@ -25,6 +25,7 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; +import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; @@ -158,11 +159,11 @@ public abstract class MenuManager { } /** - * @see DirectoryFragment#onCreateContextMenu - * * Called when user tries to generate a context menu anchored to a file when the selection * doesn't contain any folder. * + * @see DirectoryFragment#onCreateContextMenu + * * @param selectionDetails * containsFiles may return false because this may be called when user right clicks on an * unselectable item in pickers @@ -183,15 +184,20 @@ public abstract class MenuManager { updateRename(rename, selectionDetails); updateViewInOwner(viewInOwner, selectionDetails); + if (isZipNgFlagEnabled()) { + updateExtractHere(menu.findItem(R.id.dir_menu_extract_here), selectionDetails); + updateBrowse(menu.findItem(R.id.dir_menu_browse), selectionDetails); + } + updateContextMenu(menu, selectionDetails); } /** - * @see DirectoryFragment#onCreateContextMenu - * * Called when user tries to generate a context menu anchored to a folder when the selection * doesn't contain any file. * + * @see DirectoryFragment#onCreateContextMenu + * * @param selectionDetails * containDirectories may return false because this may be called when user right clicks on * an unselectable item in pickers @@ -276,6 +282,15 @@ public abstract class MenuManager { public abstract void updateKeyboardShortcutsMenu( List<KeyboardShortcutGroup> data, IntFunction<String> stringSupplier); + /** + * Called on option menu creation to instantiate the job progress item if applicable. + * + * @param menu The option menu created. + */ + public void instantiateJobProgress(Menu menu) { + // This icon is not shown in the picker. + } + protected void updateModePicker(MenuItem grid, MenuItem list) { // The order of enabling disabling menu item in wrong order removed accessibility focus. if (mState.derivedMode != State.MODE_LIST) { @@ -383,6 +398,14 @@ public abstract class MenuManager { Menus.setEnabledAndVisible(extractTo, false); } + protected void updateExtractHere(@NonNull MenuItem it, @NonNull SelectionDetails selection) { + Menus.setEnabledAndVisible(it, false); + } + + protected void updateBrowse(@NonNull MenuItem it, @NonNull SelectionDetails selection) { + Menus.setEnabledAndVisible(it, false); + } + protected void updatePasteInto(MenuItem pasteInto, SelectionDetails selectionDetails) { Menus.setEnabledAndVisible(pasteInto, false); } @@ -404,25 +427,42 @@ public abstract class MenuManager { } protected abstract void updateSelectAll(MenuItem selectAll); + protected abstract void updateSelectAll(MenuItem selectAll, SelectionDetails selectionDetails); + protected abstract void updateDeselectAll( MenuItem deselectAll, SelectionDetails selectionDetails); + protected abstract void updateCreateDir(MenuItem createDir); /** * Access to meta data about the selection. */ public interface SelectionDetails { + /** Gets the total number of items (files and directories) in the selection. */ + int size(); + + /** Returns whether the selection contains at least a directory. */ boolean containsDirectories(); + /** Returns whether the selection contains at least a file. */ boolean containsFiles(); - int size(); - + /** + * Returns whether the selection contains at least a file that has not been fully downloaded + * yet. + */ boolean containsPartialFiles(); + /** Returns whether the selection contains at least a file located in a mounted archive. */ boolean containsFilesInArchive(); + /** + * Returns whether the selection contains exactly one file which is also a supported archive + * type. + */ + boolean isArchive(); + // TODO: Update these to express characteristics instead of answering concrete questions, // since the answer to those questions is (or can be) activity specific. boolean canDelete(); diff --git a/src/com/android/documentsui/NavigationViewManager.java b/src/com/android/documentsui/NavigationViewManager.java index 86b5e517f..bbae22d42 100644 --- a/src/com/android/documentsui/NavigationViewManager.java +++ b/src/com/android/documentsui/NavigationViewManager.java @@ -18,6 +18,7 @@ package com.android.documentsui; import static com.android.documentsui.base.SharedMinimal.VERBOSE; import static com.android.documentsui.util.FlagUtils.isUseMaterial3FlagEnabled; +import static com.android.documentsui.util.FlagUtils.isVisualSignalsFlagEnabled; import android.content.res.Resources; import android.content.res.TypedArray; @@ -27,10 +28,10 @@ import android.graphics.drawable.Drawable; import android.util.Log; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; import android.view.ViewOutlineProvider; import android.view.Window; import android.view.WindowManager; -import android.widget.FrameLayout; import androidx.annotation.ColorRes; import androidx.annotation.Nullable; @@ -144,7 +145,13 @@ public class NavigationViewManager extends SelectionTracker.SelectionObserver<St mState = state; mEnv = env; mBreadcrumb = breadcrumb; - mBreadcrumb.setup(env, state, this::onNavigationItemSelected); + mBreadcrumb.setup( + env, + state, + this::onNavigationItemSelected, + isUseMaterial3FlagEnabled() + ? activity.findViewById(R.id.breadcrumb_top_divider) + : null); mConfigStore = configStore; mInjector = injector; mProfileTabs = @@ -297,7 +304,10 @@ public class NavigationViewManager extends SelectionTracker.SelectionObserver<St } public void update() { - updateScrollFlag(); + // If use_material3 flag is ON, we don't want any scroll behavior, thus skipping this logic. + if (!isUseMaterial3FlagEnabled()) { + updateScrollFlag(); + } updateToolbar(); mProfileTabs.updateView(); @@ -400,6 +410,9 @@ public class NavigationViewManager extends SelectionTracker.SelectionObserver<St mActivity.getResources().getBoolean(R.bool.full_bar_search_view); boolean showSearchBar = mActivity.getResources().getBoolean(R.bool.show_search_bar); mInjector.searchManager.install(mToolbar.getMenu(), fullBarSearch, showSearchBar); + if (isVisualSignalsFlagEnabled()) { + mInjector.menuManager.instantiateJobProgress(mToolbar.getMenu()); + } } mInjector.menuManager.updateOptionMenu(mToolbar.getMenu()); mInjector.searchManager.showMenu(mState.stack); @@ -467,8 +480,11 @@ public class NavigationViewManager extends SelectionTracker.SelectionObserver<St } if (!mIsActionModeActivated) { - FrameLayout.LayoutParams headerLayoutParams = - (FrameLayout.LayoutParams) mHeader.getLayoutParams(); + // This could be either FrameLayout.LayoutParams (when use_material3 flag is OFF) or + // LinearLayout.LayoutParams (when use_material3 flag is ON), so use the common parent + // class instead to make it work for both scenarios. + ViewGroup.MarginLayoutParams headerLayoutParams = + (ViewGroup.MarginLayoutParams) mHeader.getLayoutParams(); headerLayoutParams.setMargins(0, /* top= */ headerTopOffset, 0, 0); mHeader.setLayoutParams(headerLayoutParams); } @@ -498,7 +514,7 @@ public class NavigationViewManager extends SelectionTracker.SelectionObserver<St } interface Breadcrumb { - void setup(Environment env, State state, IntConsumer listener); + void setup(Environment env, State state, IntConsumer listener, @Nullable View topDivider); void show(boolean visibility); diff --git a/src/com/android/documentsui/ProfileTabs.java b/src/com/android/documentsui/ProfileTabs.java index 5aacc22b0..74db6f4bd 100644 --- a/src/com/android/documentsui/ProfileTabs.java +++ b/src/com/android/documentsui/ProfileTabs.java @@ -157,9 +157,12 @@ public class ProfileTabs implements ProfileTabsAddons { int tabMarginSide = (int) mTabsContainer.getContext().getResources() .getDimension(R.dimen.profile_tab_margin_side); if (isUseMaterial3FlagEnabled()) { - // M3 uses the margin value as the right margin, except for the last child. + final boolean isRtl = mTabs.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; + // if use_material3 flag is ON, we uses the margin value as the right margin + // (left margin for RTL), except for the last child. if (i != mTabs.getTabCount() - 1) { - marginLayoutParams.setMargins(0, 0, tabMarginSide, 0); + marginLayoutParams.setMargins( + isRtl ? tabMarginSide : 0, 0, isRtl ? 0 : tabMarginSide, 0); } } else { marginLayoutParams.setMargins(tabMarginSide, 0, tabMarginSide, 0); diff --git a/src/com/android/documentsui/UserManagerState.java b/src/com/android/documentsui/UserManagerState.java index d2ddae615..1023c8c1d 100644 --- a/src/com/android/documentsui/UserManagerState.java +++ b/src/com/android/documentsui/UserManagerState.java @@ -22,7 +22,6 @@ import static com.android.documentsui.DevicePolicyResources.Drawables.Style.SOLI 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; @@ -263,35 +262,13 @@ public interface UserManagerState { } synchronized (mCanForwardToProfileIdMap) { if (!mCanForwardToProfileIdMap.containsKey(userId)) { - - UserHandle handle = UserHandle.of(userId.getIdentifier()); - - // Decide if to use the parent's access, or this handle's access. - if (isCrossProfileContentSharingStrategyDelegatedFromParent(handle)) { - UserHandle parentHandle = mUserManager.getProfileParent(handle); - // Couldn't resolve parent to check access, so fail closed. - if (parentHandle == null) { - mCanForwardToProfileIdMap.put(userId, false); - } else if (mCurrentUser.getIdentifier() - == parentHandle.getIdentifier()) { - // Check if the parent is the current user, if so this profile - // is also accessible. - mCanForwardToProfileIdMap.put(userId, true); - - } else { - UserId parent = UserId.of(parentHandle); - mCanForwardToProfileIdMap.put( - userId, - doesCrossProfileForwardingActivityExistForUser( - mCurrentStateIntent, parent)); - } - } else { - // Update the profile map for this profile. - mCanForwardToProfileIdMap.put( - userId, - doesCrossProfileForwardingActivityExistForUser( - mCurrentStateIntent, userId)); - } + mCanForwardToProfileIdMap.put( + userId, + isCrossProfileAllowedToUser( + mContext, + mCurrentStateIntent, + UserId.CURRENT_USER, + userId)); } } } else { @@ -331,43 +308,37 @@ public interface UserManagerState { 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; - } + result.add(mCurrentUser); + boolean currentUserIsManaged = + mUserManager.isManagedProfile(mCurrentUser.getIdentifier()); - @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)); + for (UserHandle handle : userProfiles) { + if (SdkLevel.isAtLeastV()) { + if (!isProfileAllowed(handle)) { + continue; + } } 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)); + // Only allow managed profiles + the parent user on lower than V. + if (currentUserIsManaged + && mUserManager.getProfileParent(mCurrentUser.getUserHandle()) + == handle) { + // Intentionally empty so that this profile gets added. + } else if (!mUserManager.isManagedProfile(handle.getIdentifier())) { + continue; } } + + // Ensure the system user doesn't get added twice. + if (result.contains(UserId.of(handle))) continue; + result.add(UserId.of(handle)); } - if (result.isEmpty()) { - result.add(mCurrentUser); - } + + return result; } /** @@ -444,33 +415,6 @@ public interface UserManagerState { 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(); @@ -651,50 +595,124 @@ public interface UserManagerState { */ private void getCanForwardToProfileIdMapInternal(Intent intent) { - Map<UserId, Boolean> profileIsAccessibleToProcessOwner = new HashMap<>(); + synchronized (mCanForwardToProfileIdMap) { + mCanForwardToProfileIdMap.clear(); + for (UserId userId : getUserIds()) { + mCanForwardToProfileIdMap.put( + userId, + isCrossProfileAllowedToUser( + mContext, intent, mCurrentUser, userId)); + } + } + } - List<UserId> delegatedFromParent = new ArrayList<>(); + /** + * Determines if the provided UserIds support CrossProfile content sharing. + * + * <p>This method accepts a pair of user handles (from/to) and determines if CrossProfile + * access is permitted between those two profiles. + * + * <p>There are differences is on how the access is determined based on the platform SDK: + * + * <p>For Platform SDK < V: + * + * <p>A check for CrossProfileIntentForwarders in the origin (from) profile that target the + * destination (to) profile. If such a forwarder exists, then access is allowed, and denied + * otherwise. + * + * <p>For Platform SDK >= V: + * + * <p>The method now takes into account access delegation, which was first added in Android + * V. + * + * <p>For profiles that set the [CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT] + * property in its [UserProperties], its parent profile will be substituted in for its side + * of the check. + * + * <p>ex. For access checks between a Managed (from) and Private (to) profile, where: - + * Managed does not delegate to its parent - Private delegates to its parent + * + * <p>The following logic is performed: Managed -> parent(Private) + * + * <p>The same check in the other direction would yield: parent(Private) -> Managed + * + * <p>Note how the private profile is never actually used for either side of the check, + * since it is delegating its access check to the parent. And thus, if Managed can access + * the parent, it can also access the private. + * + * @param context Current context object, for switching user contexts. + * @param intent The current intent the Photopicker is running under. + * @param fromUser The Origin profile, where the user is coming from + * @param toUser The destination profile, where the user is attempting to go to. + * @return Whether CrossProfile content sharing is supported in this handle. + */ + private boolean isCrossProfileAllowedToUser( + Context context, Intent intent, UserId fromUser, UserId toUser) { - for (UserId userId : getUserIds()) { + // Early exit conditions, accessing self. + // NOTE: It is also possible to reach this state if this method is recursively checking + // from: parent(A) to:parent(B) where A and B are both children of the same parent. + if (fromUser.getIdentifier() == toUser.getIdentifier()) { + return true; + } - // Early exit, self is always accessible. - if (userId.getIdentifier() == mCurrentUser.getIdentifier()) { - profileIsAccessibleToProcessOwner.put(userId, true); - continue; - } + // Decide if we should use actual from or parent(from) + UserHandle currentFromUser = + getProfileToCheckCrossProfileAccess(fromUser.getUserHandle()); - // CrossProfileContentSharingStrategyDelegatedFromParent is only V+ sdks. - if (SdkLevel.isAtLeastV() - && isCrossProfileContentSharingStrategyDelegatedFromParent( - UserHandle.of(userId.getIdentifier()))) { - delegatedFromParent.add(userId); - continue; - } + // Decide if we should use actual to or parent(to) + UserHandle currentToUser = getProfileToCheckCrossProfileAccess(toUser.getUserHandle()); - // Check for cross profile & add to the map. - profileIsAccessibleToProcessOwner.put( - userId, doesCrossProfileForwardingActivityExistForUser(intent, userId)); + // When the from/to has changed from the original parameters, recursively restart the + // checks with the new from/to handles. + if (fromUser.getIdentifier() != currentFromUser.getIdentifier() + || toUser.getIdentifier() != currentToUser.getIdentifier()) { + return isCrossProfileAllowedToUser( + context, intent, UserId.of(currentFromUser), UserId.of(currentToUser)); } - // For profiles that delegate their access to the parent, set the access for - // those profiles - // equal to the same as their parent. - for (UserId userId : delegatedFromParent) { - UserHandle parent = - mUserManager.getProfileParent(UserHandle.of(userId.getIdentifier())); - profileIsAccessibleToProcessOwner.put( - userId, - profileIsAccessibleToProcessOwner.getOrDefault( - UserId.of(parent), /* default= */ false)); - } + PackageManager pm = context.getPackageManager(); + return doesCrossProfileIntentForwarderExist(intent, pm, fromUser, toUser); + } - synchronized (mCanForwardToProfileIdMap) { - mCanForwardToProfileIdMap.clear(); - for (Map.Entry<UserId, Boolean> entry : - profileIsAccessibleToProcessOwner.entrySet()) { - mCanForwardToProfileIdMap.put(entry.getKey(), entry.getValue()); + /** + * Determines if the target UserHandle delegates its content sharing to its parent. + * + * @param userHandle The target handle to check delegation for. + * @return TRUE if V+ and the handle delegates to parent. False otherwise. + */ + private boolean isCrossProfileStrategyDelegatedToParent(UserHandle userHandle) { + if (SdkLevel.isAtLeastV()) { + if (mUserManager == null) { + Log.e(TAG, "Cannot obtain user manager"); + return false; + } + UserProperties userProperties = mUserManager.getUserProperties(userHandle); + if (userProperties.getCrossProfileContentSharingStrategy() + == userProperties.CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT) { + return true; } } + return false; + } + + /** + * Acquires the correct {@link UserHandle} which should be used for CrossProfile access + * checks. + * + * @param userHandle the origin handle. + * @return The UserHandle that should be used for cross profile access checks. In the event + * the origin handle delegates its access, this may not be the same handle as the origin + * handle. + */ + private UserHandle getProfileToCheckCrossProfileAccess(UserHandle userHandle) { + if (mUserManager == null) { + Log.e(TAG, "Cannot obtain user manager"); + return null; + } + return isCrossProfileStrategyDelegatedToParent(userHandle) + ? mUserManager.getProfileParent(userHandle) + : userHandle; } /** @@ -706,16 +724,18 @@ public interface UserManagerState { * @return whether a CrossProfileIntentForwardingActivity could be found for the given * intent, and user. */ - private boolean doesCrossProfileForwardingActivityExistForUser( - Intent intent, UserId targetUserId) { + private boolean doesCrossProfileIntentForwarderExist( + Intent intent, PackageManager pm, UserId fromUser, UserId targetUserId) { - final PackageManager pm = mContext.getPackageManager(); final Intent intentToCheck = (Intent) intent.clone(); intentToCheck.setComponent(null); intentToCheck.setPackage(null); for (ResolveInfo resolveInfo : - pm.queryIntentActivities(intentToCheck, PackageManager.MATCH_DEFAULT_ONLY)) { + pm.queryIntentActivitiesAsUser( + intentToCheck, + PackageManager.MATCH_DEFAULT_ONLY, + fromUser.getUserHandle())) { if (resolveInfo.isCrossProfileIntentForwarderActivity()) { /* diff --git a/src/com/android/documentsui/archives/ArchiveRegistry.java b/src/com/android/documentsui/archives/ArchiveRegistry.java index 91e0e20f5..3417e45ad 100644 --- a/src/com/android/documentsui/archives/ArchiveRegistry.java +++ b/src/com/android/documentsui/archives/ArchiveRegistry.java @@ -24,13 +24,12 @@ import static org.apache.commons.compress.compressors.CompressorStreamFactory.XZ import androidx.annotation.Nullable; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - import org.apache.commons.compress.compressors.brotli.BrotliUtils; import org.apache.commons.compress.compressors.xz.XZUtils; +import java.util.HashMap; +import java.util.Map; + /** * To query how to generate ArchiveHandle, how to create CompressInputStream and how to create * ArchiveInputStream by using MIME type in ArchiveRegistry. @@ -136,8 +135,4 @@ final class ArchiveRegistry { static Integer getArchiveType(String mimeType) { return sHandleArchiveMap.get(mimeType); } - - static Set<String> getSupportList() { - return sHandleArchiveMap.keySet(); - } } diff --git a/src/com/android/documentsui/archives/ArchivesProvider.java b/src/com/android/documentsui/archives/ArchivesProvider.java index 3406cd708..dd221f416 100644 --- a/src/com/android/documentsui/archives/ArchivesProvider.java +++ b/src/com/android/documentsui/archives/ArchivesProvider.java @@ -44,7 +44,6 @@ import java.io.InputStream; import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.Set; /** * Provides basic implementation for creating, extracting and accessing @@ -62,7 +61,6 @@ public class ArchivesProvider extends DocumentsProvider { private static final String TAG = "ArchivesProvider"; private static final String METHOD_ACQUIRE_ARCHIVE = "acquireArchive"; private static final String METHOD_RELEASE_ARCHIVE = "releaseArchive"; - private static final Set<String> ZIP_MIME_TYPES = ArchiveRegistry.getSupportList(); @GuardedBy("mArchives") private final Map<Key, Loader> mArchives = new HashMap<>(); @@ -235,16 +233,9 @@ public class ArchivesProvider extends DocumentsProvider { return loader.get().openDocumentThumbnail(documentId, sizeHint, signal); } - /** - * Returns true if the passed mime type is supported by the helper. - */ + /** Returns whether the given mime type is a supported archive type. */ public static boolean isSupportedArchiveType(String mimeType) { - for (final String zipMimeType : ZIP_MIME_TYPES) { - if (zipMimeType.equals(mimeType)) { - return true; - } - } - return false; + return ArchiveRegistry.getArchiveType(mimeType) != null; } /** diff --git a/src/com/android/documentsui/base/DocumentInfo.java b/src/com/android/documentsui/base/DocumentInfo.java index ad09c45cf..6306f14f1 100644 --- a/src/com/android/documentsui/base/DocumentInfo.java +++ b/src/com/android/documentsui/base/DocumentInfo.java @@ -17,6 +17,7 @@ package com.android.documentsui.base; import static com.android.documentsui.base.SharedMinimal.DEBUG; +import static com.android.documentsui.util.FlagUtils.isZipNgFlagEnabled; import android.content.ContentProviderClient; import android.content.ContentResolver; @@ -319,7 +320,8 @@ public class DocumentInfo implements Durable, Parcelable { // Containers are documents which can be opened in DocumentsUI as folders. public boolean isContainer() { - return isDirectory() || (isArchive() && !isInArchive() && !isPartial()); + return isDirectory() || (isArchive() && !isPartial() && (isZipNgFlagEnabled() + || !isInArchive())); } public boolean isVirtual() { @@ -342,7 +344,6 @@ public class DocumentInfo implements Durable, Parcelable { return userId.buildDocumentUriAsUser(authority, documentId); } - /** * Returns a tree document uri representing this {@link DocumentInfo}. The URI may contain user * information. Use this when uri is needed externally. diff --git a/src/com/android/documentsui/base/UserId.java b/src/com/android/documentsui/base/UserId.java index 21842917a..7aff61e9b 100644 --- a/src/com/android/documentsui/base/UserId.java +++ b/src/com/android/documentsui/base/UserId.java @@ -95,6 +95,13 @@ public final class UserId { } /** + * Return this User's {@link UserHandle}. + */ + public UserHandle getUserHandle() { + return mUserHandle; + } + + /** * Return a package manager instance of this user. */ public PackageManager getPackageManager(Context context) { diff --git a/src/com/android/documentsui/dirlist/AnimationView.java b/src/com/android/documentsui/dirlist/AnimationView.java index d17bddf98..5813085b3 100644 --- a/src/com/android/documentsui/dirlist/AnimationView.java +++ b/src/com/android/documentsui/dirlist/AnimationView.java @@ -16,19 +16,22 @@ package com.android.documentsui.dirlist; -import androidx.annotation.IntDef; -import androidx.fragment.app.FragmentTransaction; +import static com.android.documentsui.util.FlagUtils.isUseMaterial3FlagEnabled; import android.content.Context; import android.os.Bundle; import android.util.AttributeSet; import android.widget.LinearLayout; +import androidx.annotation.IntDef; +import androidx.fragment.app.FragmentTransaction; + import com.android.documentsui.R; import com.android.documentsui.base.Shared; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; /** * This class exists solely to support animated transition of our directory fragment. @@ -51,6 +54,8 @@ public class AnimationView extends LinearLayout { public static final int ANIM_LEAVE = 3; public static final int ANIM_ENTER = 4; + private final ArrayList<OnSizeChangedListener> mOnSizeChangedListeners = new ArrayList<>(); + private float mPosition = 0f; // The distance the animation will cover...currently matches the height of the @@ -65,11 +70,45 @@ public class AnimationView extends LinearLayout { super(context, attrs); } + /** + * A listener of the onSizeChanged method. + */ + public interface OnSizeChangedListener { + /** + * Called on the View's onSizeChanged. + */ + void onSizeChanged(); + } + + /** + * Adds a listener of the onSizeChanged method. + */ + public void addOnSizeChangedListener(OnSizeChangedListener listener) { + if (isUseMaterial3FlagEnabled()) { + mOnSizeChangedListeners.add(listener); + } + } + + /** + * Removes a listener of the onSizeChanged method. + */ + public void removeOnSizeChangedListener(OnSizeChangedListener listener) { + if (isUseMaterial3FlagEnabled()) { + mOnSizeChangedListeners.remove(listener); + } + } + + @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mSpan = h; setPosition(mPosition); + if (isUseMaterial3FlagEnabled()) { + for (int i = mOnSizeChangedListeners.size() - 1; i >= 0; --i) { + mOnSizeChangedListeners.get(i).onSizeChanged(); + } + } } public float getPosition() { diff --git a/src/com/android/documentsui/dirlist/DirectoryAddonsAdapter.java b/src/com/android/documentsui/dirlist/DirectoryAddonsAdapter.java index 8989853a0..8be400924 100644 --- a/src/com/android/documentsui/dirlist/DirectoryAddonsAdapter.java +++ b/src/com/android/documentsui/dirlist/DirectoryAddonsAdapter.java @@ -16,6 +16,8 @@ package com.android.documentsui.dirlist; +import static com.android.documentsui.util.FlagUtils.isUseMaterial3FlagEnabled; + import android.os.UserManager; import android.view.ViewGroup; @@ -207,6 +209,11 @@ final class DirectoryAddonsAdapter extends DocumentsAdapter { return; } + if (isUseMaterial3FlagEnabled()) { + // Do not add a visual break between folders and documents in Material3. + return; + } + // Walk down the list of IDs till we encounter something that's not a directory, and // insert a whitespace element - this introduces a visual break in the grid between // folders and documents. diff --git a/src/com/android/documentsui/dirlist/DirectoryFragment.java b/src/com/android/documentsui/dirlist/DirectoryFragment.java index 855a8273d..2911d04e9 100644 --- a/src/com/android/documentsui/dirlist/DirectoryFragment.java +++ b/src/com/android/documentsui/dirlist/DirectoryFragment.java @@ -23,6 +23,7 @@ import static com.android.documentsui.base.State.MODE_GRID; import static com.android.documentsui.base.State.MODE_LIST; import static com.android.documentsui.util.FlagUtils.isDesktopFileHandlingFlagEnabled; import static com.android.documentsui.util.FlagUtils.isUseMaterial3FlagEnabled; +import static com.android.documentsui.util.FlagUtils.isZipNgFlagEnabled; import android.app.ActivityManager; import android.content.BroadcastReceiver; @@ -107,6 +108,7 @@ import com.android.documentsui.clipping.ClipStore; import com.android.documentsui.clipping.DocumentClipper; import com.android.documentsui.clipping.UrisSupplier; import com.android.documentsui.dirlist.AnimationView.AnimationType; +import com.android.documentsui.dirlist.AnimationView.OnSizeChangedListener; import com.android.documentsui.picker.PickActivity; import com.android.documentsui.services.FileOperation; import com.android.documentsui.services.FileOperationService; @@ -187,7 +189,7 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On private SelectionMetadata mSelectionMetadata; private KeyInputHandler mKeyListener; private @Nullable DragHoverListener mDragHoverListener; - private View mRootView; + private AnimationView mRootView; private IconHelper mIconHelper; private SwipeRefreshLayout mRefreshLayout; private RecyclerView mRecView; @@ -415,13 +417,27 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On || Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action); } + private OnSizeChangedListener mOnSizeChangedListener = + new AnimationView.OnSizeChangedListener() { + @Override + public void onSizeChanged() { + if (isUseMaterial3FlagEnabled() && mState.derivedMode != MODE_LIST) { + // Update the grid layout when the window size changes. + updateLayout(mState.derivedMode); + } + } + }; + @Override public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mHandler = new Handler(Looper.getMainLooper()); mActivity = (BaseActivity) getActivity(); - mRootView = inflater.inflate(R.layout.fragment_directory, container, false); + mRootView = (AnimationView) inflater.inflate(R.layout.fragment_directory, container, false); + if (isUseMaterial3FlagEnabled()) { + mRootView.addOnSizeChangedListener(mOnSizeChangedListener); + } mProgressBar = mRootView.findViewById(R.id.progressbar); assert mProgressBar != null; @@ -496,6 +512,10 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On mModel.removeUpdateListener(mAdapter.getModelUpdateListener()); setPreDrawListenerEnabled(false); + if (isUseMaterial3FlagEnabled()) { + mRootView.removeOnSizeChangedListener(mOnSizeChangedListener); + } + super.onDestroyView(); } @@ -808,7 +828,6 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On if (mLayout != null) { mLayout.setSpanCount(mColumnCount); } - int pad = getDirectoryPadding(mode); mAppBarHeight = getAppBarLayoutHeight(); mSaveLayoutHeight = getSaveLayoutHeight(); @@ -827,6 +846,13 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On } private int getSaveLayoutHeight() { + // When use_material3 flag is on, the bottom section not only includes the container_save, + // but also includes the breadcrumb and the divider, so we need to use the total height + // for their parent container. + if (isUseMaterial3FlagEnabled()) { + View bottomSection = getActivity().findViewById(R.id.bottom_container); + return bottomSection == null ? 0 : bottomSection.getHeight(); + } View containerSave = getActivity().findViewById(R.id.container_save); return containerSave == null ? 0 : containerSave.getHeight(); } @@ -939,11 +965,13 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On mSelectionMgr.copySelection(selection); final int id = item.getItemId(); - if (isDesktopFileHandlingFlagEnabled() && 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. + if ((isDesktopFileHandlingFlagEnabled() && id == R.id.dir_menu_open) + || (isZipNgFlagEnabled() && id == R.id.dir_menu_browse)) { + // The "Open" menu item is displayed in desktop mode. + // The "Browse" menu item is displayed for supported archives in advanced ZIP mode. + // These menu items behave the same as a double click on the matching document which + // is handled by onItemActivated but since onItemActivated requires a RecyclerView + // 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) { diff --git a/src/com/android/documentsui/dirlist/DocumentHolder.java b/src/com/android/documentsui/dirlist/DocumentHolder.java index 8e5f50636..957975c4b 100644 --- a/src/com/android/documentsui/dirlist/DocumentHolder.java +++ b/src/com/android/documentsui/dirlist/DocumentHolder.java @@ -58,8 +58,6 @@ public abstract class DocumentHolder static final float DISABLED_ALPHA = isUseMaterial3FlagEnabled() ? 0.6f : 0.3f; - static final int THUMBNAIL_STROKE_WIDTH = isUseMaterial3FlagEnabled() ? 2 : 0; - protected final Context mContext; protected @Nullable String mModelId; diff --git a/src/com/android/documentsui/dirlist/DocumentsSwipeRefreshLayout.java b/src/com/android/documentsui/dirlist/DocumentsSwipeRefreshLayout.java index 838b1fa72..64409673e 100644 --- a/src/com/android/documentsui/dirlist/DocumentsSwipeRefreshLayout.java +++ b/src/com/android/documentsui/dirlist/DocumentsSwipeRefreshLayout.java @@ -22,13 +22,13 @@ 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; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.android.documentsui.R; +import com.android.documentsui.util.ColorUtils; /** * A {@link SwipeRefreshLayout} that does not intercept any touch events. This relies on its nested @@ -46,20 +46,12 @@ public class DocumentsSwipeRefreshLayout extends SwipeRefreshLayout { super(context, attrs); if (isUseMaterial3FlagEnabled()) { - 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); + setColorSchemeColors( + ColorUtils.resolveMaterialColorAttribute( + context, com.google.android.material.R.attr.colorOnPrimaryContainer)); + setProgressBackgroundColorSchemeColor( + ColorUtils.resolveMaterialColorAttribute( + context, com.google.android.material.R.attr.colorPrimaryContainer)); } else { final int[] styledAttrs = {android.R.attr.colorAccent}; diff --git a/src/com/android/documentsui/dirlist/GridDocumentHolder.java b/src/com/android/documentsui/dirlist/GridDocumentHolder.java index f2802ff66..703f870e2 100644 --- a/src/com/android/documentsui/dirlist/GridDocumentHolder.java +++ b/src/com/android/documentsui/dirlist/GridDocumentHolder.java @@ -41,6 +41,7 @@ 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.DocumentInfo; import com.android.documentsui.base.Shared; @@ -79,6 +80,8 @@ final class GridDocumentHolder extends DocumentHolder { // Non-null only when useMaterial3 flag is ON. private final @Nullable MaterialCardView mIconWrapper; + // It will be 0 when use_material flag is OFF. + private final int mThumbnailStrokeWidth; GridDocumentHolder(Context context, ViewGroup parent, IconHelper iconHelper, ConfigStore configStore) { @@ -90,12 +93,16 @@ final class GridDocumentHolder extends DocumentHolder { mIconLayout = null; mIconMimeSm = null; mIconCheck = null; + mThumbnailStrokeWidth = + context.getResources() + .getDimensionPixelSize(R.dimen.thumbnail_border_width); } else { mBullet = null; mIconWrapper = null; mIconLayout = itemView.findViewById(R.id.icon); mIconMimeSm = (ImageView) itemView.findViewById(R.id.icon_mime_sm); mIconCheck = (ImageView) itemView.findViewById(R.id.icon_check); + mThumbnailStrokeWidth = 0; } mTitle = (TextView) itemView.findViewById(android.R.id.title); @@ -106,6 +113,13 @@ final class GridDocumentHolder extends DocumentHolder { mIconBadge = (ImageView) itemView.findViewById(R.id.icon_profile_badge); mPreviewIcon = itemView.findViewById(R.id.preview_icon); + if (isUseMaterial3FlagEnabled()) { + int clipCornerRadius = context.getResources() + .getDimensionPixelSize(R.dimen.thumbnail_clip_corner_radius); + IconUtils.applyThumbnailClipOutline( + mIconThumb, mThumbnailStrokeWidth, clipCornerRadius); + } + mIconHelper = iconHelper; if (SdkLevel.isAtLeastT() && !mConfigStore.isPrivateSpaceInDocsUIEnabled()) { @@ -157,7 +171,7 @@ final class GridDocumentHolder extends DocumentHolder { if (selected) { mIconWrapper.setStrokeWidth(0); } else if (mIconThumb.getDrawable() != null) { - mIconWrapper.setStrokeWidth(THUMBNAIL_STROKE_WIDTH); + mIconWrapper.setStrokeWidth(mThumbnailStrokeWidth); } } } @@ -258,7 +272,7 @@ final class GridDocumentHolder extends DocumentHolder { // Show stroke when thumbnail is loaded. if (mIconWrapper != null) { mIconWrapper.setStrokeWidth( - thumbnailLoaded ? THUMBNAIL_STROKE_WIDTH : 0); + thumbnailLoaded ? mThumbnailStrokeWidth : 0); } }); } else { @@ -293,8 +307,8 @@ final class GridDocumentHolder extends DocumentHolder { } } - if (mBullet != null && (mDetails.getVisibility() == View.GONE - || mDate.getText().isEmpty())) { + if (mBullet != null && (mDetails.getText() == null || mDetails.getText().length() == 0 + || mDate.getText() == null || mDate.getText().length() == 0)) { // There is no need for the bullet separating the details and date. mBullet.setVisibility(View.GONE); } diff --git a/src/com/android/documentsui/dirlist/ListDocumentHolder.java b/src/com/android/documentsui/dirlist/ListDocumentHolder.java index 0d0f79919..a0db097d0 100644 --- a/src/com/android/documentsui/dirlist/ListDocumentHolder.java +++ b/src/com/android/documentsui/dirlist/ListDocumentHolder.java @@ -43,6 +43,7 @@ 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.DocumentInfo; import com.android.documentsui.base.Lookup; @@ -78,6 +79,8 @@ final class ListDocumentHolder extends DocumentHolder { private final ImageView mIconBadge; private final View mIconLayout; final View mPreviewIcon; + // It will be 0 when use_material flag is OFF. + private final int mThumbnailStrokeWidth; private final IconHelper mIconHelper; private final Lookup<String, String> mFileTypeLookup; @@ -103,6 +106,17 @@ final class ListDocumentHolder extends DocumentHolder { // Warning: mDetails view doesn't exists in layout-sw720dp-land layout mDetails = (LinearLayout) itemView.findViewById(R.id.line2); mPreviewIcon = itemView.findViewById(R.id.preview_icon); + if (isUseMaterial3FlagEnabled()) { + mThumbnailStrokeWidth = + context.getResources() + .getDimensionPixelSize(R.dimen.thumbnail_border_width); + int clipCornerRadius = context.getResources() + .getDimensionPixelSize(R.dimen.thumbnail_clip_corner_radius); + IconUtils.applyThumbnailClipOutline( + mIconThumb, mThumbnailStrokeWidth, clipCornerRadius); + } else { + mThumbnailStrokeWidth = 0; + } mIconHelper = iconHelper; mFileTypeLookup = fileTypeLookup; @@ -152,7 +166,7 @@ final class ListDocumentHolder extends DocumentHolder { if (selected) { mIconWrapper.setStrokeWidth(0); } else if (mIconThumb.getDrawable() != null) { - mIconWrapper.setStrokeWidth(2); + mIconWrapper.setStrokeWidth(mThumbnailStrokeWidth); } } } @@ -271,7 +285,8 @@ final class ListDocumentHolder extends DocumentHolder { thumbnailLoaded -> { // Show stroke when thumbnail is loaded. if (isUseMaterial3FlagEnabled() && mIconWrapper != null) { - mIconWrapper.setStrokeWidth(thumbnailLoaded ? THUMBNAIL_STROKE_WIDTH : 0); + mIconWrapper.setStrokeWidth( + thumbnailLoaded ? mThumbnailStrokeWidth : 0); } }); diff --git a/src/com/android/documentsui/dirlist/SelectionMetadata.java b/src/com/android/documentsui/dirlist/SelectionMetadata.java index 74b6061b3..0d0644502 100644 --- a/src/com/android/documentsui/dirlist/SelectionMetadata.java +++ b/src/com/android/documentsui/dirlist/SelectionMetadata.java @@ -18,6 +18,7 @@ package com.android.documentsui.dirlist; import static com.android.documentsui.base.DocumentInfo.getCursorInt; import static com.android.documentsui.base.DocumentInfo.getCursorString; +import static com.android.documentsui.util.FlagUtils.isZipNgFlagEnabled; import android.database.Cursor; import android.provider.DocumentsContract.Document; @@ -56,7 +57,13 @@ public class SelectionMetadata extends SelectionObserver<String> private int mWritableDirectoryCount = 0; private int mNoDeleteCount = 0; private int mNoRenameCount = 0; + + /** Number of files that are located in mounted archives. */ private int mInArchiveCount = 0; + + /** Number of archives. */ + private int mArchiveCount = 0; + private boolean mSupportsSettings = false; public SelectionMetadata(Function<String, Cursor> docFinder) { @@ -79,6 +86,9 @@ public class SelectionMetadata extends SelectionObserver<String> mDirectoryCount += delta; } else { mFileCount += delta; + if (ArchivesProvider.isSupportedArchiveType(mimeType)) { + mArchiveCount += delta; + } } final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS); @@ -97,9 +107,8 @@ public class SelectionMetadata extends SelectionObserver<String> if ((docFlags & Document.FLAG_PARTIAL) != 0) { mPartialCount += delta; } - mSupportsSettings = (docFlags & Document.FLAG_SUPPORTS_SETTINGS) != 0 && - (mFileCount + mDirectoryCount) == 1; + mSupportsSettings = (docFlags & Document.FLAG_SUPPORTS_SETTINGS) != 0 && size() == 1; final String authority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY); if (ArchivesProvider.AUTHORITY.equals(authority)) { @@ -115,6 +124,8 @@ public class SelectionMetadata extends SelectionObserver<String> mWritableDirectoryCount = 0; mNoDeleteCount = 0; mNoRenameCount = 0; + mInArchiveCount = 0; + mArchiveCount = 0; } @Override @@ -143,6 +154,11 @@ public class SelectionMetadata extends SelectionObserver<String> } @Override + public boolean isArchive() { + return mDirectoryCount == 0 && mFileCount == 1 && mArchiveCount == 1; + } + + @Override public boolean canDelete() { return size() > 0 && mNoDeleteCount == 0; } @@ -169,6 +185,7 @@ public class SelectionMetadata extends SelectionObserver<String> @Override public boolean canOpen() { - return size() == 1 && mDirectoryCount == 0 && mInArchiveCount == 0 && mPartialCount == 0; + return mFileCount == 1 && mDirectoryCount == 0 && mPartialCount == 0 && ( + isZipNgFlagEnabled() || mInArchiveCount == 0); } } diff --git a/src/com/android/documentsui/files/FilesActivity.java b/src/com/android/documentsui/files/FilesActivity.java index 6328a031a..b254ce525 100644 --- a/src/com/android/documentsui/files/FilesActivity.java +++ b/src/com/android/documentsui/files/FilesActivity.java @@ -19,6 +19,7 @@ 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.util.FlagUtils.isUseMaterial3FlagEnabled; +import static com.android.documentsui.util.FlagUtils.isVisualSignalsFlagEnabled; import static com.android.documentsui.util.FlagUtils.isZipNgFlagEnabled; import android.app.ActivityManager.TaskDescription; @@ -134,7 +135,7 @@ public class FilesActivity extends BaseActivity implements AbstractActionHandler return clipper.hasItemsToPaste(); } }, - getApplicationContext(), + isVisualSignalsFlagEnabled() ? this : getApplicationContext(), mInjector.selectionMgr, mProviders::getApplicationName, mInjector.getModel()::getItemUri, @@ -211,9 +212,13 @@ public class FilesActivity extends BaseActivity implements AbstractActionHandler updateTaskDescription(intent); } - // Set save container background to transparent for edge to edge nav bar. - View saveContainer = findViewById(R.id.container_save); - saveContainer.setBackgroundColor(Color.TRANSPARENT); + // When the use_material3 flag is on, the file path bar is at the bottom of the layout and + // hence the edge to edge nav bar is no longer required. + if (!isUseMaterial3FlagEnabled()) { + // Set save container background to transparent for edge to edge nav bar. + View saveContainer = findViewById(R.id.container_save); + saveContainer.setBackgroundColor(Color.TRANSPARENT); + } presentFileErrors(icicle, intent); } diff --git a/src/com/android/documentsui/files/MenuManager.java b/src/com/android/documentsui/files/MenuManager.java index 9b3564eeb..2c85dcb01 100644 --- a/src/com/android/documentsui/files/MenuManager.java +++ b/src/com/android/documentsui/files/MenuManager.java @@ -17,6 +17,7 @@ package com.android.documentsui.files; import static com.android.documentsui.util.FlagUtils.isDesktopFileHandlingFlagEnabled; +import static com.android.documentsui.util.FlagUtils.isVisualSignalsFlagEnabled; import android.content.Context; import android.content.res.Resources; @@ -29,9 +30,12 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.recyclerview.selection.SelectionTracker; +import com.android.documentsui.JobPanelController; import com.android.documentsui.R; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.Features; @@ -55,6 +59,7 @@ public final class MenuManager extends com.android.documentsui.MenuManager { private final SelectionTracker<String> mSelectionManager; private final Lookup<String, Uri> mUriLookup; private final LookupApplicationName mAppNameLookup; + @Nullable private final JobPanelController mJobPanelController; public MenuManager( Features features, @@ -74,6 +79,12 @@ public final class MenuManager extends com.android.documentsui.MenuManager { mSelectionManager = selectionManager; mAppNameLookup = appNameLookup; mUriLookup = uriLookup; + + if (isVisualSignalsFlagEnabled()) { + mJobPanelController = new JobPanelController(context); + } else { + mJobPanelController = null; + } } @Override @@ -141,6 +152,14 @@ public final class MenuManager extends com.android.documentsui.MenuManager { } @Override + public void instantiateJobProgress(Menu menu) { + if (mJobPanelController == null) { + return; + } + mJobPanelController.setMenuItem(menu.findItem(R.id.option_menu_job_progress)); + } + + @Override protected void updateSettings(MenuItem settings, RootInfo root) { Menus.setEnabledAndVisible(settings, root.hasSettings()); } @@ -212,6 +231,16 @@ public final class MenuManager extends com.android.documentsui.MenuManager { } @Override + protected void updateExtractHere(@NonNull MenuItem it, @NonNull SelectionDetails selection) { + Menus.setEnabledAndVisible(it, selection.isArchive()); + } + + @Override + protected void updateBrowse(@NonNull MenuItem it, @NonNull SelectionDetails selection) { + Menus.setEnabledAndVisible(it, selection.isArchive()); + } + + @Override protected void updatePasteInto(MenuItem pasteInto, SelectionDetails selectionDetails) { Menus.setEnabledAndVisible(pasteInto, selectionDetails.canPasteInto() && mDirDetails.hasItemsToPaste()); diff --git a/src/com/android/documentsui/loaders/BaseFileLoader.kt b/src/com/android/documentsui/loaders/BaseFileLoader.kt index dd76217ac..fcb1d4cb0 100644 --- a/src/com/android/documentsui/loaders/BaseFileLoader.kt +++ b/src/com/android/documentsui/loaders/BaseFileLoader.kt @@ -77,7 +77,7 @@ abstract class BaseFileLoader( private var mResult: DirectoryResult? = null override fun cancelLoadInBackground() { - Log.d(TAG, "BasedFileLoader.cancelLoadInBackground") + Log.d(TAG, "${this::class.simpleName}.cancelLoadInBackground") super.cancelLoadInBackground() synchronized(this) { @@ -86,7 +86,7 @@ abstract class BaseFileLoader( } override fun deliverResult(result: DirectoryResult?) { - Log.d(TAG, "BasedFileLoader.deliverResult") + Log.d(TAG, "${this::class.simpleName}.deliverResult") if (isReset) { closeResult(result) return @@ -104,7 +104,7 @@ abstract class BaseFileLoader( } override fun onStartLoading() { - Log.d(TAG, "BasedFileLoader.onStartLoading") + Log.d(TAG, "${this::class.simpleName}.onStartLoading") val isCursorStale: Boolean = checkIfCursorStale(mResult) if (mResult != null && !isCursorStale) { deliverResult(mResult) @@ -115,17 +115,17 @@ abstract class BaseFileLoader( } override fun onStopLoading() { - Log.d(TAG, "BasedFileLoader.onStopLoading") + Log.d(TAG, "${this::class.simpleName}.onStopLoading") cancelLoad() } override fun onCanceled(result: DirectoryResult?) { - Log.d(TAG, "BasedFileLoader.onCanceled") + Log.d(TAG, "${this::class.simpleName}.onCanceled") closeResult(result) } override fun onReset() { - Log.d(TAG, "BasedFileLoader.onReset") + Log.d(TAG, "${this::class.simpleName}.onReset") super.onReset() // Ensure the loader is stopped diff --git a/src/com/android/documentsui/loaders/FolderLoader.kt b/src/com/android/documentsui/loaders/FolderLoader.kt index a166ca752..40c15dfe1 100644 --- a/src/com/android/documentsui/loaders/FolderLoader.kt +++ b/src/com/android/documentsui/loaders/FolderLoader.kt @@ -60,7 +60,7 @@ class FolderLoader( mListedDir.authority, mListedDir.documentId ) - var cursor = + val cursor = queryLocation(mRoot.rootId, folderChildrenUri, mOptions.otherQueryArgs, ALL_RESULTS) ?: emptyCursor() cursor.registerContentObserver(mObserver) diff --git a/src/com/android/documentsui/picker/PickActivity.java b/src/com/android/documentsui/picker/PickActivity.java index 68a797397..4f875072e 100644 --- a/src/com/android/documentsui/picker/PickActivity.java +++ b/src/com/android/documentsui/picker/PickActivity.java @@ -224,9 +224,11 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons { } else if (mState.action == ACTION_OPEN_TREE || mState.action == ACTION_PICK_COPY_DESTINATION) { PickFragment.show(getSupportFragmentManager()); - } else { + } else if (!isUseMaterial3FlagEnabled()) { // If PickFragment or SaveFragment does not show, // Set save container background to transparent for edge to edge nav bar. + // However when the use_material3 flag is on, the file path bar is at the bottom of the + // layout and hence the edge to edge nav bar is no longer required. View saveContainer = findViewById(R.id.container_save); saveContainer.setBackgroundColor(Color.TRANSPARENT); } diff --git a/src/com/android/documentsui/picker/PickFragment.java b/src/com/android/documentsui/picker/PickFragment.java index e9610a510..0d20083a8 100644 --- a/src/com/android/documentsui/picker/PickFragment.java +++ b/src/com/android/documentsui/picker/PickFragment.java @@ -22,7 +22,9 @@ import static com.android.documentsui.services.FileOperationService.OPERATION_DE import static com.android.documentsui.services.FileOperationService.OPERATION_EXTRACT; import static com.android.documentsui.services.FileOperationService.OPERATION_MOVE; import static com.android.documentsui.services.FileOperationService.OPERATION_UNKNOWN; +import static com.android.documentsui.util.FlagUtils.isUseMaterial3FlagEnabled; +import android.content.pm.PackageManager; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -179,13 +181,28 @@ public class PickFragment extends Fragment { switch (mAction) { case State.ACTION_OPEN_TREE: mPick.setText(getString(R.string.open_tree_button)); - mPick.setWidth(Integer.MAX_VALUE); - mCancel.setVisibility(View.GONE); + // When use_material3 flag is enabled, all form factors should have the pick button + // wrap the text content instead of taking up the full width. + if (!isUseMaterial3FlagEnabled()) { + mCancel.setVisibility(View.GONE); + mPick.setWidth(Integer.MAX_VALUE); + mPickOverlay.setVisibility( + mPickTarget.isBlockedFromTree() && mRestrictScopeStorage + ? View.VISIBLE + : View.GONE); + } else if (!getActivity() + .getPackageManager() + .hasSystemFeature(PackageManager.FEATURE_PC)) { + // On non-desktop devices the back gesture is used to cancel the picker, so + // don't show the "Cancel" button on these devices and instead enable the pick + // overlay which enables showing a toast when the disabled button is pressed. + mCancel.setVisibility(View.GONE); + mPickOverlay.setVisibility( + mPickTarget.isBlockedFromTree() && mRestrictScopeStorage + ? View.VISIBLE + : View.GONE); + } mPick.setEnabled(!(mPickTarget.isBlockedFromTree() && mRestrictScopeStorage)); - mPickOverlay.setVisibility( - mPickTarget.isBlockedFromTree() && mRestrictScopeStorage - ? View.VISIBLE - : View.GONE); break; case State.ACTION_PICK_COPY_DESTINATION: int titleId; diff --git a/src/com/android/documentsui/picker/SaveFragment.java b/src/com/android/documentsui/picker/SaveFragment.java index f881768b9..8316688e7 100644 --- a/src/com/android/documentsui/picker/SaveFragment.java +++ b/src/com/android/documentsui/picker/SaveFragment.java @@ -16,7 +16,11 @@ package com.android.documentsui.picker; +import static com.android.documentsui.util.FlagUtils.isUseMaterial3FlagEnabled; + import android.content.Context; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.text.Editable; import android.text.TextUtils; @@ -42,6 +46,9 @@ import com.android.documentsui.base.BooleanConsumer; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.Shared; +import com.google.android.material.button.MaterialButton; +import com.google.android.material.textfield.TextInputLayout; + /** * Display document title editor and save button. */ @@ -54,6 +61,7 @@ public class SaveFragment extends Fragment { private DocumentInfo mReplaceTarget; private EditText mDisplayName; private TextView mSave; + private MaterialButton mCancel; private ProgressBar mProgress; private boolean mIgnoreNextEdit; @@ -84,9 +92,16 @@ public class SaveFragment extends Fragment { final View view = inflater.inflate(R.layout.fragment_save, container, false); - final ImageView icon = (ImageView) view.findViewById(android.R.id.icon); - icon.setImageDrawable( - IconUtils.loadMimeIcon(context, getArguments().getString(EXTRA_MIME_TYPE))); + final Drawable icon = + IconUtils.loadMimeIcon(context, getArguments().getString(EXTRA_MIME_TYPE)); + if (isUseMaterial3FlagEnabled()) { + final TextInputLayout titleWrapper = + (TextInputLayout) view.findViewById(R.id.title_wrapper); + titleWrapper.setStartIconDrawable(icon); + } else { + final ImageView iconHolder = view.findViewById(android.R.id.icon); + iconHolder.setImageDrawable(icon); + } mDisplayName = (EditText) view.findViewById(android.R.id.title); mDisplayName.addTextChangedListener(mDisplayNameWatcher); @@ -122,6 +137,19 @@ public class SaveFragment extends Fragment { mSave.setOnClickListener(mSaveListener); mSave.setEnabled(false); + mCancel = (MaterialButton) view.findViewById(android.R.id.button2); + // For >600dp, this button is always available (via the values-600dp layout override). + // However on smaller layouts, the button is default GONE to save on space (the back gesture + // can cancel the saver) and when FEATURE_PC is set a cancel button is required due to the + // lack of a back gesture (mainly mouse support). + if (isUseMaterial3FlagEnabled() + && mCancel != null + && context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) { + mCancel.setOnClickListener(mCancelListener); + mCancel.setVisibility(View.VISIBLE); + mCancel.setEnabled(true); + } + mProgress = (ProgressBar) view.findViewById(android.R.id.progress); return view; @@ -173,6 +201,13 @@ public class SaveFragment extends Fragment { }; + private View.OnClickListener mCancelListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + mInjector.actions.finishPicking(); + } + }; + private void performSave() { if (mReplaceTarget != null) { mInjector.actions.saveDocument(getChildFragmentManager(), mReplaceTarget); diff --git a/src/com/android/documentsui/queries/SearchChipViewManager.java b/src/com/android/documentsui/queries/SearchChipViewManager.java index f673b7408..bf3d1e865 100644 --- a/src/com/android/documentsui/queries/SearchChipViewManager.java +++ b/src/com/android/documentsui/queries/SearchChipViewManager.java @@ -387,7 +387,10 @@ public class SearchChipViewManager { .getDimensionPixelSize(R.dimen.focus_ring_width); chip.setChipStrokeWidth(focusRingWidth); } else { - chip.setChipStrokeWidth(1f); + final int strokeWidth = mChipGroup + .getResources() + .getDimensionPixelSize(R.dimen.search_chip_inactive_stroke_width); + chip.setChipStrokeWidth(strokeWidth); } } @@ -518,7 +521,7 @@ public class SearchChipViewManager { } // Let the first checked chip can be shown. - View parent = (View) mChipGroup.getParent(); + View parent = (View) mChipGroup.getParent().getParent(); if (parent instanceof HorizontalScrollView) { final int scrollToX = isRtl ? parent.getWidth() : 0; ((HorizontalScrollView) parent).smoothScrollTo(scrollToX, 0); diff --git a/src/com/android/documentsui/services/FileOperationService.java b/src/com/android/documentsui/services/FileOperationService.java index dcb2c1db4..14b87ef5b 100644 --- a/src/com/android/documentsui/services/FileOperationService.java +++ b/src/com/android/documentsui/services/FileOperationService.java @@ -68,6 +68,9 @@ public class FileOperationService extends Service implements Job.Listener { public static final String EXTRA_OPERATION = "com.android.documentsui.OPERATION"; public static final String EXTRA_CANCEL = "com.android.documentsui.CANCEL"; + public static final String ACTION_PROGRESS = "com.android.documentsui.action.PROGRESS"; + public static final String EXTRA_PROGRESS = "com.android.documentsui.PROGRESS"; + @IntDef({ OPERATION_UNKNOWN, OPERATION_COPY, @@ -580,6 +583,7 @@ public class FileOperationService extends Service implements Job.Listener { private final class GlobalJobMonitor implements Runnable { private static final long PROGRESS_INTERVAL_MILLIS = 500L; private boolean mRunning = false; + private long mLastId = 0; private void start() { if (!mRunning) { @@ -602,9 +606,9 @@ public class FileOperationService extends Service implements Job.Listener { } Intent intent = new Intent(); intent.setPackage(getPackageName()); - intent.setAction("com.android.documentsui.PROGRESS"); - intent.putExtra("id", 0); - intent.putParcelableArrayListExtra("progress", progress); + intent.setAction(ACTION_PROGRESS); + intent.putExtra("id", mLastId++); + intent.putParcelableArrayListExtra(EXTRA_PROGRESS, progress); sendBroadcast(intent); } diff --git a/src/com/android/documentsui/services/Job.java b/src/com/android/documentsui/services/Job.java index 0f432cc19..95ad8b335 100644 --- a/src/com/android/documentsui/services/Job.java +++ b/src/com/android/documentsui/services/Job.java @@ -76,11 +76,11 @@ abstract public class Job implements Runnable { @Retention(RetentionPolicy.SOURCE) @IntDef({STATE_CREATED, STATE_STARTED, STATE_SET_UP, STATE_COMPLETED, STATE_CANCELED}) - @interface State {} - static final int STATE_CREATED = 0; - static final int STATE_STARTED = 1; - static final int STATE_SET_UP = 2; - static final int STATE_COMPLETED = 3; + public @interface State {} + public static final int STATE_CREATED = 0; + public static final int STATE_STARTED = 1; + public static final int STATE_SET_UP = 2; + public static final int STATE_COMPLETED = 3; /** * A job is in canceled state as long as {@link #cancel()} is called on it, even after it is * completed. diff --git a/src/com/android/documentsui/sorting/TableHeaderController.java b/src/com/android/documentsui/sorting/TableHeaderController.java index cb72ac916..fda7b2713 100644 --- a/src/com/android/documentsui/sorting/TableHeaderController.java +++ b/src/com/android/documentsui/sorting/TableHeaderController.java @@ -28,10 +28,11 @@ import javax.annotation.Nullable; /** View controller for table header that associates header cells in table header and columns. */ public final class TableHeaderController implements SortController.WidgetController { private final HeaderCell mTitleCell; - private final HeaderCell mSummaryCell; - private final HeaderCell mSizeCell; - private final HeaderCell mFileTypeCell; - private final HeaderCell mDateCell; + // The 4 cells below will be null in compact/medium screen sizes when use_material3 flag is ON. + private final @Nullable HeaderCell mSummaryCell; + private final @Nullable HeaderCell mSizeCell; + private final @Nullable HeaderCell mFileTypeCell; + private final @Nullable HeaderCell mDateCell; private final SortModel mModel; // We assign this here porque each method reference creates a new object // instance (which is wasteful). @@ -66,10 +67,18 @@ public final class TableHeaderController implements SortController.WidgetControl private void onModelUpdate(SortModel model, int updateTypeUnspecified) { bindCell(mTitleCell, SortModel.SORT_DIMENSION_ID_TITLE); - bindCell(mSummaryCell, SortModel.SORT_DIMENSION_ID_SUMMARY); - bindCell(mSizeCell, SortModel.SORT_DIMENSION_ID_SIZE); - bindCell(mFileTypeCell, SortModel.SORT_DIMENSION_ID_FILE_TYPE); - bindCell(mDateCell, SortModel.SORT_DIMENSION_ID_DATE); + if (mSummaryCell != null) { + bindCell(mSummaryCell, SortModel.SORT_DIMENSION_ID_SUMMARY); + } + if (mSizeCell != null) { + bindCell(mSizeCell, SortModel.SORT_DIMENSION_ID_SIZE); + } + if (mFileTypeCell != null) { + bindCell(mFileTypeCell, SortModel.SORT_DIMENSION_ID_FILE_TYPE); + } + if (mDateCell != null) { + bindCell(mDateCell, SortModel.SORT_DIMENSION_ID_DATE); + } } @Override diff --git a/src/com/android/documentsui/util/ColorUtils.kt b/src/com/android/documentsui/util/ColorUtils.kt new file mode 100644 index 000000000..ee67b7832 --- /dev/null +++ b/src/com/android/documentsui/util/ColorUtils.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.documentsui.util + +import android.content.Context +import android.util.TypedValue +import androidx.annotation.AttrRes + +class ColorUtils { + companion object { + /** + * Resolve a color attribute from the Material3 theme, example usage. + * resolveMaterialColorAttribute(context, com.google.android.material.R.attr.XXX). + */ + @JvmStatic + fun resolveMaterialColorAttribute(context: Context, @AttrRes colorAttrId: Int): Int { + val typedValue = TypedValue() + context.theme.resolveAttribute(colorAttrId, typedValue, true) + return typedValue.data + } + } +} diff --git a/src/com/android/documentsui/util/FlagUtils.kt b/src/com/android/documentsui/util/FlagUtils.kt index 191a1f8d7..cf81d5966 100644 --- a/src/com/android/documentsui/util/FlagUtils.kt +++ b/src/com/android/documentsui/util/FlagUtils.kt @@ -31,12 +31,12 @@ class FlagUtils { @JvmStatic fun isZipNgFlagEnabled(): Boolean { - return Flags.zipNgRo() + return Flags.zipNgRo() && Flags.useMaterial3() } @JvmStatic - fun isUseSearchV2RwFlagEnabled(): Boolean { - return Flags.useSearchV2Rw() + fun isUseSearchV2FlagEnabled(): Boolean { + return Flags.useSearchV2ReadOnly() } @JvmStatic diff --git a/tests/common/com/android/documentsui/bots/DirectoryListBot.java b/tests/common/com/android/documentsui/bots/DirectoryListBot.java index 314013e53..8884bf0f2 100644 --- a/tests/common/com/android/documentsui/bots/DirectoryListBot.java +++ b/tests/common/com/android/documentsui/bots/DirectoryListBot.java @@ -16,6 +16,8 @@ package com.android.documentsui.bots; +import static com.android.documentsui.util.FlagUtils.isUseMaterial3FlagEnabled; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNotNull; @@ -71,7 +73,7 @@ public class DirectoryListBot extends Bots.BaseBot { mDirListId = mTargetPackage + ":id/dir_list"; mItemRootId = mTargetPackage + ":id/item_root"; mPreviewId = mTargetPackage + ":id/preview_icon"; - mIconId = mTargetPackage + ":id/icon"; + mIconId = mTargetPackage + (isUseMaterial3FlagEnabled() ? ":id/icon_wrapper" : ":id/icon"); } public void assertDocumentsCount(int count) throws UiObjectNotFoundException { diff --git a/tests/common/com/android/documentsui/testing/MutableJobProgress.kt b/tests/common/com/android/documentsui/testing/MutableJobProgress.kt new file mode 100644 index 000000000..b2dd595f9 --- /dev/null +++ b/tests/common/com/android/documentsui/testing/MutableJobProgress.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.documentsui.testing + +import com.android.documentsui.services.Job +import com.android.documentsui.services.JobProgress + +data class MutableJobProgress( + var id: String, + @Job.State var state: Int, + var msg: String?, + var hasFailures: Boolean, + var currentBytes: Long = -1, + var requiredBytes: Long = -1, + var msRemaining: Long = -1, +) { + fun toJobProgress() = + JobProgress(id, state, msg, hasFailures, currentBytes, requiredBytes, msRemaining) +} diff --git a/tests/common/com/android/documentsui/testing/TestMenu.java b/tests/common/com/android/documentsui/testing/TestMenu.java index 9795fd373..a97e46e5d 100644 --- a/tests/common/com/android/documentsui/testing/TestMenu.java +++ b/tests/common/com/android/documentsui/testing/TestMenu.java @@ -26,7 +26,6 @@ import com.android.documentsui.R; import org.mockito.Mockito; /** - * * Test copy of {@link android.view.Menu}. * * We use abstract so we don't have to implement all the necessary methods from the interface, @@ -55,6 +54,8 @@ public abstract class TestMenu implements Menu { R.id.dir_menu_paste_into_folder, R.id.dir_menu_inspect, R.id.dir_menu_open_in_new_window, + R.id.dir_menu_extract_here, + R.id.dir_menu_browse, R.id.root_menu_eject_root, R.id.root_menu_open_in_new_window, R.id.root_menu_paste_into_folder, @@ -89,7 +90,6 @@ public abstract class TestMenu implements Menu { } - public static TestMenu create(int... ids) { final TestMenu menu = Mockito.mock(TestMenu.class, Mockito.withSettings().defaultAnswer(Mockito.CALLS_REAL_METHODS)); @@ -103,7 +103,8 @@ public abstract class TestMenu implements Menu { item.setActionView(Mockito.mock(SearchView.class)); } - if (id == R.id.option_menu_extract_all) { + if (id == R.id.option_menu_extract_all || id == R.id.dir_menu_extract_here + || id == R.id.dir_menu_browse) { item.setEnabled(false); item.setVisible(false); } diff --git a/tests/common/com/android/documentsui/testing/TestMenuItem.java b/tests/common/com/android/documentsui/testing/TestMenuItem.java index 97ac602db..5463237b2 100644 --- a/tests/common/com/android/documentsui/testing/TestMenuItem.java +++ b/tests/common/com/android/documentsui/testing/TestMenuItem.java @@ -27,14 +27,12 @@ import androidx.annotation.StringRes; import org.mockito.Mockito; /** -* -* Test copy of {@link android.view.MenuItem}. -* -* We use abstract so we don't have to implement all the necessary methods from the interface, -* and we use Mockito to just mock out the methods we need. -* To get an instance, use {@link #create(int)}. -*/ - + * Test copy of {@link android.view.MenuItem}. + * + * We use abstract so we don't have to implement all the necessary methods from the interface, + * and we use Mockito to just mock out the methods we need. + * To get an instance, use {@link #create(int)}. + */ public abstract class TestMenuItem implements MenuItem { boolean enabled; diff --git a/tests/common/com/android/documentsui/testing/TestSelectionDetails.java b/tests/common/com/android/documentsui/testing/TestSelectionDetails.java index e798174f8..4411209d1 100644 --- a/tests/common/com/android/documentsui/testing/TestSelectionDetails.java +++ b/tests/common/com/android/documentsui/testing/TestSelectionDetails.java @@ -30,6 +30,7 @@ public class TestSelectionDetails implements SelectionDetails { public boolean containsFilesInArchive; public boolean containDirectories; public boolean containFiles; + public boolean isArchive; public boolean canPasteInto; public boolean canExtract; public boolean canOpen; @@ -56,6 +57,11 @@ public class TestSelectionDetails implements SelectionDetails { } @Override + public boolean isArchive() { + return isArchive; + } + + @Override public boolean canRename() { return canRename; } @@ -89,4 +95,4 @@ public class TestSelectionDetails implements SelectionDetails { public int size() { return size; } - } +} diff --git a/tests/functional/com/android/documentsui/FilesActivityUiTest.java b/tests/functional/com/android/documentsui/FilesActivityUiTest.java index f1f505235..6c2397068 100644 --- a/tests/functional/com/android/documentsui/FilesActivityUiTest.java +++ b/tests/functional/com/android/documentsui/FilesActivityUiTest.java @@ -17,11 +17,14 @@ package com.android.documentsui; import static com.android.documentsui.flags.Flags.FLAG_HIDE_ROOTS_ON_DESKTOP_RO; +import static com.android.documentsui.flags.Flags.FLAG_USE_SEARCH_V2_READ_ONLY; +import static com.android.documentsui.flags.Flags.FLAG_USE_MATERIAL3; import android.app.Instrumentation; import android.net.Uri; import android.os.RemoteException; 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; @@ -92,13 +95,23 @@ public class FilesActivityUiTest extends ActivityTestJunit4<FilesActivity> { bots.main.assertWindowTitle("Images"); } + private void filesListed() throws Exception { + bots.directory.assertDocumentsPresent("file0.log", "file1.png", "file2.csv"); + } + @Test + @RequiresFlagsDisabled(FLAG_USE_SEARCH_V2_READ_ONLY) public void testFilesListed() throws Exception { - bots.directory.assertDocumentsPresent("file0.log", "file1.png", "file2.csv"); + filesListed(); } @Test - public void testFilesList_LiveUpdate() throws Exception { + @RequiresFlagsEnabled({FLAG_USE_SEARCH_V2_READ_ONLY, FLAG_USE_MATERIAL3}) + public void testFilesListed_searchV2() throws Exception { + filesListed(); + } + + private void filesListed_LiveUpdates() throws Exception { mDocsHelper.createDocument(rootDir0, "yummers/sandwich", "Ham & Cheese.sandwich"); bots.directory.waitForDocument("Ham & Cheese.sandwich"); @@ -107,6 +120,18 @@ public class FilesActivityUiTest extends ActivityTestJunit4<FilesActivity> { } @Test + @RequiresFlagsDisabled(FLAG_USE_SEARCH_V2_READ_ONLY) + public void testFilesList_LiveUpdate() throws Exception { + filesListed_LiveUpdates(); + } + + @Test + @RequiresFlagsEnabled({FLAG_USE_SEARCH_V2_READ_ONLY, FLAG_USE_MATERIAL3}) + public void testFilesList_LiveUpdate_searchV2() throws Exception { + filesListed_LiveUpdates(); + } + + @Test public void testNavigate_byBreadcrumb() throws Exception { bots.directory.openDocument(dirName1); bots.directory.waitForDocument(childDir1); // wait for known content diff --git a/tests/functional/com/android/documentsui/JobPanelUiTest.kt b/tests/functional/com/android/documentsui/JobPanelUiTest.kt new file mode 100644 index 000000000..5b28b1f5d --- /dev/null +++ b/tests/functional/com/android/documentsui/JobPanelUiTest.kt @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.documentsui + +import android.content.Intent +import android.platform.test.annotations.RequiresFlagsEnabled +import android.platform.test.flag.junit.CheckFlagsRule +import android.platform.test.flag.junit.DeviceFlagsValueProvider +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.doesNotExist +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import com.android.documentsui.files.FilesActivity +import com.android.documentsui.flags.Flags.FLAG_USE_MATERIAL3 +import com.android.documentsui.flags.Flags.FLAG_VISUAL_SIGNALS_RO +import com.android.documentsui.services.FileOperationService.ACTION_PROGRESS +import com.android.documentsui.services.FileOperationService.EXTRA_PROGRESS +import com.android.documentsui.services.Job +import com.android.documentsui.services.JobProgress +import com.android.documentsui.testing.MutableJobProgress +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RequiresFlagsEnabled(FLAG_USE_MATERIAL3, FLAG_VISUAL_SIGNALS_RO) +@RunWith(AndroidJUnit4::class) +class JobPanelUiTest : ActivityTestJunit4<FilesActivity>() { + @get:Rule + val mCheckFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + + private var mLastId = 0L + + private fun sendProgress(progresses: ArrayList<JobProgress>, id: Long = mLastId++) { + val context = InstrumentationRegistry.getInstrumentation().targetContext + var intent = Intent(ACTION_PROGRESS).apply { + `package` = context.packageName + putExtra("id", id) + putParcelableArrayListExtra(EXTRA_PROGRESS, progresses) + } + context.sendBroadcast(intent) + } + + @Before + override fun setUp() { + super.setUp() + } + + @After + override fun tearDown() { + super.tearDown() + } + + @Test + fun testJobPanelAppearsOnClick() { + onView(withId(R.id.option_menu_job_progress)).check(doesNotExist()) + onView(withId(R.id.job_progress_panel_title)).check(doesNotExist()) + + val progress = MutableJobProgress( + id = "jobId1", + state = Job.STATE_SET_UP, + msg = "Job started", + hasFailures = false, + currentBytes = 4, + requiredBytes = 10, + msRemaining = -1 + ) + sendProgress(arrayListOf(progress.toJobProgress())) + + onView(withId(R.id.option_menu_job_progress)) + .check(matches(isDisplayed())) + .perform(click()) + onView(withId(R.id.job_progress_panel_title)).check(matches(isDisplayed())) + } +} diff --git a/tests/functional/com/android/documentsui/TrampolineActivityTest.kt b/tests/functional/com/android/documentsui/TrampolineActivityTest.kt index 6bf0975ad..10b31d1eb 100644 --- a/tests/functional/com/android/documentsui/TrampolineActivityTest.kt +++ b/tests/functional/com/android/documentsui/TrampolineActivityTest.kt @@ -15,10 +15,8 @@ */ package com.android.documentsui -import android.app.Instrumentation import android.content.Intent import android.content.Intent.ACTION_GET_CONTENT -import android.content.IntentFilter import android.os.Build.VERSION_CODES import android.platform.test.annotations.RequiresFlagsEnabled import android.platform.test.flag.junit.CheckFlagsRule @@ -34,7 +32,6 @@ import com.android.documentsui.flags.Flags.FLAG_REDIRECT_GET_CONTENT_RO import com.android.documentsui.picker.TrampolineActivity import java.util.Optional import java.util.regex.Pattern -import org.junit.After import org.junit.Assert.assertNotNull import org.junit.Before import org.junit.BeforeClass @@ -56,25 +53,28 @@ class TrampolineActivityTest() { const val UI_TIMEOUT = 5000L val PHOTOPICKER_PACKAGE_REGEX: Pattern = Pattern.compile(".*(photopicker|media\\.module).*") val DOCUMENTSUI_PACKAGE_REGEX: Pattern = Pattern.compile(".*documentsui.*") + val STACK_LIST_REGEX: Pattern = Pattern.compile( + "taskId=(?<taskId>[0-9]+):(.+?)(photopicker|media\\.module|documentsui)", + Pattern.MULTILINE + ) private lateinit var device: UiDevice - private lateinit var monitor: Instrumentation.ActivityMonitor + fun removePhotopickerAndDocumentsUITasks() { + // Get the current list of tasks that are visible. + val result = device.executeShellCommand("am stack list") + + // Identify any that are from DocumentsUI or Photopicker and close them. + val matcher = STACK_LIST_REGEX.matcher(result) + while (matcher.find()) { + device.executeShellCommand("am stack remove ${matcher.group("taskId")}") + } + } @BeforeClass @JvmStatic fun setUp() { device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) - - // Monitor to wait for the activity that starts with the `ACTION_GET_CONTENT` intent. - val intentFilter = IntentFilter().apply { addAction(ACTION_GET_CONTENT) } - monitor = - Instrumentation.ActivityMonitor( - intentFilter, - null, // Expected result from startActivityForResult. - true, // Whether to block until activity started or not. - ) - InstrumentationRegistry.getInstrumentation().addMonitor(monitor) } } @@ -157,24 +157,20 @@ class TrampolineActivityTest() { @Before fun setUp() { + removePhotopickerAndDocumentsUITasks() + val context = InstrumentationRegistry.getInstrumentation().targetContext val intent = Intent(ACTION_GET_CONTENT) intent.setClass(context, TrampolineActivity::class.java) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) intent.setType(testData.mimeType) if (testData.extraMimeTypes.isPresent) { - testData.extraMimeTypes.get() - .forEach { intent.putExtra(Intent.EXTRA_MIME_TYPES, it) } + intent.putExtra(Intent.EXTRA_MIME_TYPES, testData.extraMimeTypes.get()) } context.startActivity(intent) } - @After - fun tearDown() { - monitor.waitForActivityWithTimeout(UI_TIMEOUT)?.finish() - } - @Test fun testCorrectAppIsLaunched() { val bySelector = when (testData.expectedApp) { @@ -208,6 +204,11 @@ class TrampolineActivityTest() { @get:Rule val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + @Before + fun setUp() { + removePhotopickerAndDocumentsUITasks() + } + @Test fun testReferredGetContentFromPhotopickerShouldNotRedirectBack() { val context = InstrumentationRegistry.getInstrumentation().targetContext diff --git a/tests/functional/com/android/documentsui/archives/ArchiveHandleTest.java b/tests/functional/com/android/documentsui/archives/ArchiveHandleTest.java index d8a1f4225..46b2698df 100644 --- a/tests/functional/com/android/documentsui/archives/ArchiveHandleTest.java +++ b/tests/functional/com/android/documentsui/archives/ArchiveHandleTest.java @@ -22,6 +22,8 @@ import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static java.util.Objects.requireNonNull; + import android.os.ParcelFileDescriptor; import androidx.annotation.NonNull; @@ -49,27 +51,24 @@ public class ArchiveHandleTest { @Rule public ArchiveFileTestRule mArchiveFileTestRule = new ArchiveFileTestRule(); - - private ArchiveHandle prepareArchiveHandle(String archivePath, String suffix, - String mimeType) throws IOException, CompressorException, ArchiveException { - ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule - .openAssetFile(archivePath, suffix); + private ArchiveHandle prepareArchiveHandle(String archivePath, String suffix, String mimeType) + throws IOException, CompressorException, ArchiveException { + ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule.openAssetFile(archivePath, + suffix); return ArchiveHandle.create(parcelFileDescriptor, mimeType); } - private static ArchiveEntry getFileInArchive(Enumeration<ArchiveEntry> enumeration, - String pathInArchive) { + private static ArchiveEntry getFileInArchive(Enumeration<ArchiveEntry> enumeration) { while (enumeration.hasMoreElements()) { ArchiveEntry entry = enumeration.nextElement(); - if (entry.getName().equals(pathInArchive)) { + if (entry.getName().equals("hello/inside_folder/hello_insside.txt")) { return entry; } } return null; } - private static class ArchiveEntryRecord implements ArchiveEntry { private final String mName; private final long mSize; @@ -91,11 +90,9 @@ public class ArchiveHandleTest { return false; } - if (obj instanceof ArchiveEntryRecord) { - ArchiveEntryRecord recordB = (ArchiveEntryRecord) obj; - return mName.equals(recordB.mName) - && mSize == recordB.mSize - && mIsDirectory == recordB.mIsDirectory; + if (obj instanceof ArchiveEntryRecord record) { + return mName.equals(record.mName) && mSize == record.mSize + && mIsDirectory == record.mIsDirectory; } return false; @@ -124,13 +121,13 @@ public class ArchiveHandleTest { @NonNull @Override public String toString() { - return String.format(Locale.ENGLISH, "name: %s, size: %d, isDirectory: %b", - mName, mSize, mIsDirectory); + return String.format(Locale.ENGLISH, "name: %s, size: %d, isDirectory: %b", mName, + mSize, mIsDirectory); } } private static List<ArchiveEntry> transformToIterable(Enumeration<ArchiveEntry> enumeration) { - List list = new ArrayList<ArchiveEntry>(); + List<ArchiveEntry> list = new ArrayList<>(); while (enumeration.hasMoreElements()) { list.add(new ArchiveEntryRecord(enumeration.nextElement())); } @@ -183,311 +180,259 @@ public class ArchiveHandleTest { } @Test - public void buildArchiveHandle_withoutFileDescriptor_shouldBeIllegal() throws Exception { - try { - ArchiveHandle.create(null, - "application/x-7z-compressed"); - fail("It should not be here!"); - } catch (NullPointerException e) { - /* do nothing */ - } - } - - @Test - public void buildArchiveHandle_withWrongMimeType_shouldBeIllegal() throws Exception { - ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule - .openAssetFile("archives/7z/hello.7z", ".7z"); - - try { - ArchiveHandle.create(parcelFileDescriptor, null); - fail("It should not be here!"); - } catch (IllegalArgumentException e) { - /* do nothing */ - } - } - - @Test public void buildArchiveHandle_sevenZFile_shouldNotNull() throws Exception { - ArchiveHandle archiveHandle = prepareArchiveHandle("archives/7z/hello.7z", - ".7z", "application/x-7z-compressed"); - - assertThat(archiveHandle).isNotNull(); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/7z/hello.7z", ".7z", + "application/x-7z-compressed")) { + assertThat(archiveHandle).isNotNull(); + } } @Test public void buildArchiveHandle_zipFile_shouldNotNull() throws Exception { - ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", - ".zip", "application/zip"); - - assertThat(archiveHandle).isNotNull(); - } - - @Test - public void buildArchiveHandle_zipWithWrongMimeType_shouldBeNull() throws Exception { - try { - prepareArchiveHandle("archives/zip/hello.zip", - ".zip", "application/xxxzip"); - fail("It should not be here!"); - } catch (UnsupportedOperationException e) { - /* do nothing */ + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", ".zip", + "application/zip")) { + assertThat(archiveHandle).isNotNull(); } } @Test public void buildArchiveHandle_tarFile_shouldNotNull() throws Exception { - ArchiveHandle archiveHandle = prepareArchiveHandle("archives/tar/hello.tar", - ".tar", "application/x-gtar"); - - assertThat(archiveHandle).isNotNull(); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/tar/hello.tar", ".tar", + "application/x-gtar")) { + assertThat(archiveHandle).isNotNull(); + } } @Test public void buildArchiveHandle_tgzFile_shouldNotNull() throws Exception { - ArchiveHandle archiveHandle = prepareArchiveHandle("archives/tar_gz/hello.tgz", - ".tgz", "application/x-compressed-tar"); - - assertThat(archiveHandle).isNotNull(); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/tar_gz/hello.tgz", ".tgz", + "application/x-compressed-tar")) { + assertThat(archiveHandle).isNotNull(); + } } @Test public void buildArchiveHandle_tarGzFile_shouldNotNull() throws Exception { - ArchiveHandle archiveHandle = - prepareArchiveHandle("archives/tar_gz/hello_tar_gz", ".tar.gz", - "application/x-compressed-tar"); - - assertThat(archiveHandle).isNotNull(); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/tar_gz/hello_tar_gz", + ".tar.gz", "application/x-compressed-tar")) { + assertThat(archiveHandle).isNotNull(); + } } @Test public void buildArchiveHandle_tarBzipFile_shouldNotNull() throws Exception { - ArchiveHandle archiveHandle = - prepareArchiveHandle("archives/tar_bz2/hello.tar.bz2", - ".tar.bz2", "application/x-bzip-compressed-tar"); - - assertThat(archiveHandle).isNotNull(); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/tar_bz2/hello.tar.bz2", + ".tar.bz2", "application/x-bzip-compressed-tar")) { + assertThat(archiveHandle).isNotNull(); + } } @Test public void buildArchiveHandle_tarXzFile_shouldNotNull() throws Exception { - ArchiveHandle archiveHandle = - prepareArchiveHandle("archives/xz/hello.tar.xz", ".tar.xz", - "application/x-xz-compressed-tar"); - - assertThat(archiveHandle).isNotNull(); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/xz/hello.tar.xz", + ".tar.xz", "application/x-xz-compressed-tar")) { + assertThat(archiveHandle).isNotNull(); + } } @Test public void buildArchiveHandle_tarBrFile_shouldNotNull() throws Exception { - ArchiveHandle archiveHandle = - prepareArchiveHandle("archives/brotli/hello.tar.br", ".tar.br", - "application/x-brotli-compressed-tar"); - - assertThat(archiveHandle).isNotNull(); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/brotli/hello.tar.br", + ".tar.br", "application/x-brotli-compressed-tar")) { + assertThat(archiveHandle).isNotNull(); + } } @Test public void getMimeType_sevenZFile_shouldBeSevenZ() throws CompressorException, ArchiveException, IOException { - ArchiveHandle archiveHandle = prepareArchiveHandle("archives/7z/hello.7z", - ".7z", "application/x-7z-compressed"); - - assertThat(archiveHandle.getMimeType()).isEqualTo("application/x-7z-compressed"); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/7z/hello.7z", ".7z", + "application/x-7z-compressed")) { + assertThat(archiveHandle.getMimeType()).isEqualTo("application/x-7z-compressed"); + } } @Test public void getMimeType_tarBrotli_shouldBeBrotliCompressedTar() throws CompressorException, ArchiveException, IOException { - ArchiveHandle archiveHandle = - prepareArchiveHandle("archives/brotli/hello.tar.br", ".tar.br", - "application/x-brotli-compressed-tar"); - - assertThat(archiveHandle.getMimeType()) - .isEqualTo("application/x-brotli-compressed-tar"); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/brotli/hello.tar.br", + ".tar.br", "application/x-brotli-compressed-tar")) { + assertThat(archiveHandle.getMimeType()).isEqualTo( + "application/x-brotli-compressed-tar"); + } } @Test public void getMimeType_tarXz_shouldBeXzCompressedTar() throws CompressorException, ArchiveException, IOException { - ArchiveHandle archiveHandle = - prepareArchiveHandle("archives/xz/hello.tar.xz", ".tar.xz", - "application/x-xz-compressed-tar"); - - assertThat(archiveHandle.getMimeType()) - .isEqualTo("application/x-xz-compressed-tar"); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/xz/hello.tar.xz", + ".tar.xz", "application/x-xz-compressed-tar")) { + assertThat(archiveHandle.getMimeType()).isEqualTo("application/x-xz-compressed-tar"); + } } @Test public void getMimeType_tarGz_shouldBeCompressedTar() throws CompressorException, ArchiveException, IOException { - ArchiveHandle archiveHandle = - prepareArchiveHandle("archives/tar_gz/hello_tar_gz", ".tar.gz", - "application/x-compressed-tar"); - - assertThat(archiveHandle.getMimeType()) - .isEqualTo("application/x-compressed-tar"); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/tar_gz/hello_tar_gz", + ".tar.gz", "application/x-compressed-tar")) { + assertThat(archiveHandle.getMimeType()).isEqualTo("application/x-compressed-tar"); + } } @Test public void getCommonArchive_tarBrFile_shouldBeCommonArchiveInputHandle() throws Exception { - ArchiveHandle archiveHandle = - prepareArchiveHandle("archives/brotli/hello.tar.br", ".tar.br", - "application/x-brotli-compressed-tar"); - - assertThat(archiveHandle.toString()).contains("CommonArchiveInputHandle"); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/brotli/hello.tar.br", + ".tar.br", "application/x-brotli-compressed-tar")) { + assertThat(archiveHandle.toString()).contains("CommonArchiveInputHandle"); + } } @Test public void getCommonArchive_sevenZFile_shouldBeSevenZFileHandle() throws Exception { - ArchiveHandle archiveHandle = prepareArchiveHandle("archives/7z/hello.7z", - ".7z", "application/x-7z-compressed"); - - assertThat(archiveHandle.toString()).contains("SevenZFileHandle"); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/7z/hello.7z", ".7z", + "application/x-7z-compressed")) { + assertThat(archiveHandle.toString()).contains("SevenZFileHandle"); + } } - @Test public void getCommonArchive_zipFile_shouldBeZipFileHandle() throws Exception { - ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", - ".zip", "application/zip"); - - assertThat(archiveHandle.toString()).contains("ZipFileHandle"); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", ".zip", + "application/zip")) { + assertThat(archiveHandle.toString()).contains("ZipFileHandle"); + } } @Test public void close_zipFile_shouldBeSuccess() throws Exception { - ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", - ".zip", "application/zip"); - - archiveHandle.close(); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", ".zip", + "application/zip")) { + assertThat(archiveHandle).isNotNull(); + } } @Test public void close_sevenZFile_shouldBeSuccess() throws Exception { - ArchiveHandle archiveHandle = prepareArchiveHandle("archives/7z/hello.7z", - ".7z", "application/x-7z-compressed"); - - archiveHandle.close(); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/7z/hello.7z", ".7z", + "application/x-7z-compressed")) { + assertThat(archiveHandle).isNotNull(); + } } @Test public void closeInputStream_zipFile_shouldBeSuccess() throws Exception { - ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", - ".zip", "application/zip"); - - InputStream inputStream = archiveHandle.getInputStream( - getFileInArchive(archiveHandle.getEntries(), - "hello/inside_folder/hello_insside.txt")); - - assertThat(inputStream).isNotNull(); - - inputStream.close(); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", ".zip", + "application/zip")) { + try (InputStream inputStream = archiveHandle.getInputStream( + requireNonNull(getFileInArchive(archiveHandle.getEntries())))) { + assertThat(inputStream).isNotNull(); + } + } } @Test public void close_zipFile_shouldNotOpen() throws Exception { - ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule - .openAssetFile("archives/zip/hello.zip", ".zip"); + ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule.openAssetFile( + "archives/zip/hello.zip", ".zip"); - ArchiveHandle archiveHandle = ArchiveHandle.create(parcelFileDescriptor, - "application/zip"); + ArchiveHandle archiveHandle = ArchiveHandle.create(parcelFileDescriptor, "application/zip"); archiveHandle.close(); - FileInputStream fileInputStream = - new FileInputStream(parcelFileDescriptor.getFileDescriptor()); + FileInputStream fileInputStream = new FileInputStream( + parcelFileDescriptor.getFileDescriptor()); assertThat(fileInputStream).isNotNull(); } @Test public void getInputStream_zipFile_shouldHaveTheSameContent() throws Exception { - ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule - .openAssetFile("archives/zip/hello.zip", ".zip"); + ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule.openAssetFile( + "archives/zip/hello.zip", ".zip"); String expectedContent = mArchiveFileTestRule.getAssetText( "archives/original/hello/inside_folder/hello_insside.txt"); - ArchiveHandle archiveHandle = ArchiveHandle.create(parcelFileDescriptor, - "application/zip"); + ArchiveHandle archiveHandle = ArchiveHandle.create(parcelFileDescriptor, "application/zip"); InputStream inputStream = archiveHandle.getInputStream( - getFileInArchive(archiveHandle.getEntries(), - "hello/inside_folder/hello_insside.txt")); + requireNonNull(getFileInArchive(archiveHandle.getEntries()))); - assertThat(ArchiveFileTestRule.getStringFromInputStream(inputStream)) - .isEqualTo(expectedContent); + assertThat(ArchiveFileTestRule.getStringFromInputStream(inputStream)).isEqualTo( + expectedContent); } @Test public void getInputStream_zipFileNotExistEntry_shouldFail() throws Exception { - ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", - ".zip", "application/zip"); - - ArchiveEntry archiveEntry = mock(ArchiveEntry.class); - when(archiveEntry.getName()).thenReturn("/not_exist_entry"); - - try { - archiveHandle.getInputStream(archiveEntry); - fail("It should not be here."); - } catch (ClassCastException e) { - /* do nothing */ + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", ".zip", + "application/zip")) { + ArchiveEntry archiveEntry = mock(ArchiveEntry.class); + when(archiveEntry.getName()).thenReturn("/not_exist_entry"); + + try { + archiveHandle.getInputStream(archiveEntry); + fail("It should not be here."); + } catch (ClassCastException e) { + /* do nothing */ + } } } @Test public void getInputStream_directoryEntry_shouldFail() throws Exception { - ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", - ".zip", "application/zip"); - - ArchiveEntry archiveEntry = mock(ArchiveEntry.class); - when(archiveEntry.isDirectory()).thenReturn(true); - - try { - archiveHandle.getInputStream(archiveEntry); - fail("It should not be here."); - } catch (IllegalArgumentException e) { - /* expected, do nothing */ + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", ".zip", + "application/zip")) { + ArchiveEntry archiveEntry = mock(ArchiveEntry.class); + when(archiveEntry.isDirectory()).thenReturn(true); + + try { + archiveHandle.getInputStream(archiveEntry); + fail("It should not be here."); + } catch (IllegalArgumentException e) { + /* expected, do nothing */ + } } } @Test public void getInputStream_negativeSizeEntry_shouldFail() throws Exception { - ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", - ".zip", "application/zip"); - - ArchiveEntry archiveEntry = mock(ArchiveEntry.class); - when(archiveEntry.isDirectory()).thenReturn(false); - when(archiveEntry.getSize()).thenReturn(-1L); - - try { - archiveHandle.getInputStream(archiveEntry); - fail("It should not be here."); - } catch (IllegalArgumentException e) { - /* expected, do nothing */ + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", ".zip", + "application/zip")) { + ArchiveEntry archiveEntry = mock(ArchiveEntry.class); + when(archiveEntry.isDirectory()).thenReturn(false); + when(archiveEntry.getSize()).thenReturn(-1L); + + try { + archiveHandle.getInputStream(archiveEntry); + fail("It should not be here."); + } catch (IllegalArgumentException e) { + /* expected, do nothing */ + } } } @Test public void getInputStream_emptyStringEntry_shouldFail() throws Exception { - ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", - ".zip", "application/zip"); - - ArchiveEntry archiveEntry = mock(ArchiveEntry.class); - when(archiveEntry.isDirectory()).thenReturn(false); - when(archiveEntry.getSize()).thenReturn(14L); - when(archiveEntry.getName()).thenReturn(""); - - try { - archiveHandle.getInputStream(archiveEntry); - fail("It should not be here."); - } catch (IllegalArgumentException e) { - /* expected, do nothing */ + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", ".zip", + "application/zip")) { + ArchiveEntry archiveEntry = mock(ArchiveEntry.class); + when(archiveEntry.isDirectory()).thenReturn(false); + when(archiveEntry.getSize()).thenReturn(14L); + when(archiveEntry.getName()).thenReturn(""); + + try { + archiveHandle.getInputStream(archiveEntry); + fail("It should not be here."); + } catch (IllegalArgumentException e) { + /* expected, do nothing */ + } } } @Test public void getInputStream_sevenZFile_shouldHaveTheSameContent() throws Exception { - ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule - .openAssetFile("archives/7z/hello.7z", ".7z"); + ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule.openAssetFile( + "archives/7z/hello.7z", ".7z"); String expectedContent = mArchiveFileTestRule.getAssetText( "archives/original/hello/inside_folder/hello_insside.txt"); @@ -496,17 +441,16 @@ public class ArchiveHandleTest { "application/x-7z-compressed"); InputStream inputStream = archiveHandle.getInputStream( - getFileInArchive(archiveHandle.getEntries(), - "hello/inside_folder/hello_insside.txt")); + requireNonNull(getFileInArchive(archiveHandle.getEntries()))); - assertThat(ArchiveFileTestRule.getStringFromInputStream(inputStream)) - .isEqualTo(expectedContent); + assertThat(ArchiveFileTestRule.getStringFromInputStream(inputStream)).isEqualTo( + expectedContent); } @Test public void getInputStream_tarGzFile_shouldHaveTheSameContent() throws Exception { - ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule - .openAssetFile("archives/tar_gz/hello.tgz", ".tar.gz"); + ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule.openAssetFile( + "archives/tar_gz/hello.tgz", ".tar.gz"); String expectedContent = mArchiveFileTestRule.getAssetText( "archives/original/hello/inside_folder/hello_insside.txt"); @@ -515,40 +459,16 @@ public class ArchiveHandleTest { "application/x-compressed-tar"); InputStream inputStream = archiveHandle.getInputStream( - getFileInArchive(archiveHandle.getEntries(), - "hello/inside_folder/hello_insside.txt")); - - assertThat(ArchiveFileTestRule.getStringFromInputStream(inputStream)) - .isEqualTo(expectedContent); - } - - @Test - public void getInputStream_tarGzFileNullEntry_getNullInputStream() throws Exception { - ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule - .openAssetFile("archives/tar_gz/hello.tgz", ".tar.gz"); - - String expectedContent = mArchiveFileTestRule.getAssetText( - "archives/original/hello/inside_folder/hello_insside.txt"); + requireNonNull(getFileInArchive(archiveHandle.getEntries()))); - ArchiveHandle archiveHandle = ArchiveHandle.create(parcelFileDescriptor, - "application/x-compressed-tar"); - - try { - archiveHandle.getInputStream(null); - fail("It should not here"); - } catch (IllegalArgumentException | ArchiveException | CompressorException e) { - /* expected, do nothing */ - } + assertThat(ArchiveFileTestRule.getStringFromInputStream(inputStream)).isEqualTo( + expectedContent); } - @Test public void getInputStream_tarGzFileInvalidEntry_getNullInputStream() throws Exception { - ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule - .openAssetFile("archives/tar_gz/hello.tgz", ".tar.gz"); - - String expectedContent = mArchiveFileTestRule.getAssetText( - "archives/original/hello/inside_folder/hello_insside.txt"); + ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule.openAssetFile( + "archives/tar_gz/hello.tgz", ".tar.gz"); ArchiveHandle archiveHandle = ArchiveHandle.create(parcelFileDescriptor, "application/x-compressed-tar"); @@ -565,8 +485,8 @@ public class ArchiveHandleTest { @Test public void getInputStream_tarBrotliFile_shouldHaveTheSameContent() throws Exception { - ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule - .openAssetFile("archives/brotli/hello.tar.br", ".tar.br"); + ParcelFileDescriptor parcelFileDescriptor = mArchiveFileTestRule.openAssetFile( + "archives/brotli/hello.tar.br", ".tar.br"); String expectedContent = mArchiveFileTestRule.getAssetText( "archives/original/hello/inside_folder/hello_insside.txt"); @@ -575,70 +495,63 @@ public class ArchiveHandleTest { "application/x-brotli-compressed-tar"); InputStream inputStream = archiveHandle.getInputStream( - getFileInArchive(archiveHandle.getEntries(), - "hello/inside_folder/hello_insside.txt")); + requireNonNull(getFileInArchive(archiveHandle.getEntries()))); - assertThat(ArchiveFileTestRule.getStringFromInputStream(inputStream)) - .isEqualTo(expectedContent); + assertThat(ArchiveFileTestRule.getStringFromInputStream(inputStream)).isEqualTo( + expectedContent); } @Test public void getEntries_zipFile_shouldTheSameWithList() throws Exception { - ArchiveHandle archiveHandle = - prepareArchiveHandle("archives/zip/hello.zip", ".zip", - "application/zip"); - - assertThat(transformToIterable(archiveHandle.getEntries())) - .containsAtLeastElementsIn(sExpectEntries); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/zip/hello.zip", ".zip", + "application/zip")) { + assertThat(transformToIterable(archiveHandle.getEntries())).containsAtLeastElementsIn( + sExpectEntries); + } } @Test public void getEntries_tarFile_shouldTheSameWithList() throws Exception { - ArchiveHandle archiveHandle = - prepareArchiveHandle("archives/tar/hello.tar", ".tar", - "application/x-gtar"); - - assertThat(transformToIterable(archiveHandle.getEntries())) - .containsAtLeastElementsIn(sExpectEntries); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/tar/hello.tar", ".tar", + "application/x-gtar")) { + assertThat(transformToIterable(archiveHandle.getEntries())).containsAtLeastElementsIn( + sExpectEntries); + } } @Test public void getEntries_tgzFile_shouldTheSameWithList() throws Exception { - ArchiveHandle archiveHandle = - prepareArchiveHandle("archives/tar_gz/hello.tgz", ".tgz", - "application/x-compressed-tar"); - - assertThat(transformToIterable(archiveHandle.getEntries())) - .containsAtLeastElementsIn(sExpectEntries); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/tar_gz/hello.tgz", ".tgz", + "application/x-compressed-tar")) { + assertThat(transformToIterable(archiveHandle.getEntries())).containsAtLeastElementsIn( + sExpectEntries); + } } @Test public void getEntries_tarBzFile_shouldTheSameWithList() throws Exception { - ArchiveHandle archiveHandle = - prepareArchiveHandle("archives/tar_bz2/hello.tar.bz2", ".tar.bz2", - "application/x-bzip-compressed-tar"); - - assertThat(transformToIterable(archiveHandle.getEntries())) - .containsAtLeastElementsIn(sExpectEntries); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/tar_bz2/hello.tar.bz2", + ".tar.bz2", "application/x-bzip-compressed-tar")) { + assertThat(transformToIterable(archiveHandle.getEntries())).containsAtLeastElementsIn( + sExpectEntries); + } } @Test public void getEntries_tarBrotliFile_shouldTheSameWithList() throws Exception { - ArchiveHandle archiveHandle = - prepareArchiveHandle("archives/brotli/hello.tar.br", ".tar.br", - "application/x-brotli-compressed-tar"); - - assertThat(transformToIterable(archiveHandle.getEntries())) - .containsAtLeastElementsIn(sExpectEntries); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/brotli/hello.tar.br", + ".tar.br", "application/x-brotli-compressed-tar")) { + assertThat(transformToIterable(archiveHandle.getEntries())).containsAtLeastElementsIn( + sExpectEntries); + } } @Test public void getEntries_tarXzFile_shouldTheSameWithList() throws Exception { - ArchiveHandle archiveHandle = - prepareArchiveHandle("archives/xz/hello.tar.xz", ".tar.xz", - "application/x-xz-compressed-tar"); - - assertThat(transformToIterable(archiveHandle.getEntries())) - .containsAtLeastElementsIn(sExpectEntries); + try (ArchiveHandle archiveHandle = prepareArchiveHandle("archives/xz/hello.tar.xz", + ".tar.xz", "application/x-xz-compressed-tar")) { + assertThat(transformToIterable(archiveHandle.getEntries())).containsAtLeastElementsIn( + sExpectEntries); + } } } diff --git a/tests/unit/com/android/documentsui/DragAndDropManagerTests.java b/tests/unit/com/android/documentsui/DragAndDropManagerTests.java index d7a701f75..27b4074fd 100644 --- a/tests/unit/com/android/documentsui/DragAndDropManagerTests.java +++ b/tests/unit/com/android/documentsui/DragAndDropManagerTests.java @@ -26,17 +26,22 @@ import android.content.ClipData; import android.content.ClipDescription; import android.graphics.drawable.Drawable; import android.os.PersistableBundle; +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.util.Pair; import android.view.KeyEvent; import android.view.View; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.documentsui.DragAndDropManager.RuntimeDragAndDropManager; import com.android.documentsui.DragAndDropManager.State; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.base.RootInfo; +import com.android.documentsui.flags.Flags; import com.android.documentsui.services.FileOperationService; import com.android.documentsui.services.FileOperations; import com.android.documentsui.testing.ClipDatas; @@ -52,6 +57,7 @@ import com.android.documentsui.testing.TestSelectionDetails; import com.android.documentsui.testing.Views; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; @@ -93,6 +99,9 @@ public class DragAndDropManagerTests { private DragAndDropManager mManager; + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @Before public void setUp() { mEnv = TestEnv.create(); @@ -191,7 +200,8 @@ public class DragAndDropManagerTests { } @Test - public void testStartDrag_BuildsCorrectShadow_MultipleDocs() { + @RequiresFlagsDisabled({Flags.FLAG_USE_MATERIAL3}) + public void testStartDrag_BuildsCorrectShadow_MultipleDocs_M3Disabled() { mManager.startDrag( mStartDragView, Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG), @@ -208,6 +218,24 @@ public class DragAndDropManagerTests { } @Test + @RequiresFlagsEnabled({Flags.FLAG_USE_MATERIAL3}) + public void testStartDrag_BuildsCorrectShadow_MultipleDocs() { + mManager.startDrag( + mStartDragView, + Arrays.asList(TestEnv.FILE_APK, TestEnv.FILE_JPG), + TestProvidersAccess.HOME, + Arrays.asList(TestEnv.FOLDER_0.derivedUri, TestEnv.FILE_APK.derivedUri, + TestEnv.FILE_JPG.derivedUri), + mDetails, + mIconHelper, + TestEnv.FOLDER_0); + + mShadowBuilder.title.assertLastArgument(TestEnv.FILE_APK.displayName); + mShadowBuilder.icon.assertLastArgument(mIconHelper.nextDocumentIcon); + mShadowBuilder.count.assertLastArgument(2); + } + + @Test public void testCanSpringOpen_ReturnsFalse_RootNotSupportCreate() { mManager.startDrag( mStartDragView, @@ -860,6 +888,7 @@ public class DragAndDropManagerTests { public TestEventListener<String> title; public TestEventListener<Drawable> icon; public TestEventListener<Integer> state; + public TestEventListener<Integer> count; private TestDragShadowBuilder() { super(null); @@ -880,6 +909,11 @@ public class DragAndDropManagerTests { this.state.accept(state); } + @Override + void updateDragFileCount(int count) { + this.count.accept(count); + } + public static TestDragShadowBuilder create() { TestDragShadowBuilder builder = Mockito.mock(TestDragShadowBuilder.class, Mockito.CALLS_REAL_METHODS); @@ -887,6 +921,7 @@ public class DragAndDropManagerTests { builder.title = new TestEventListener<>(); builder.icon = new TestEventListener<>(); builder.state = new TestEventListener<>(); + builder.count = new TestEventListener<>(); return builder; } diff --git a/tests/unit/com/android/documentsui/JobPanelControllerTest.kt b/tests/unit/com/android/documentsui/JobPanelControllerTest.kt new file mode 100644 index 000000000..3e510edd9 --- /dev/null +++ b/tests/unit/com/android/documentsui/JobPanelControllerTest.kt @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.documentsui + +import android.content.Intent +import android.platform.test.annotations.RequiresFlagsEnabled +import android.platform.test.flag.junit.CheckFlagsRule +import android.platform.test.flag.junit.DeviceFlagsValueProvider +import android.widget.ActionMenuView +import android.widget.ProgressBar +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry +import com.android.documentsui.flags.Flags.FLAG_USE_MATERIAL3 +import com.android.documentsui.flags.Flags.FLAG_VISUAL_SIGNALS_RO +import com.android.documentsui.services.FileOperationService.ACTION_PROGRESS +import com.android.documentsui.services.FileOperationService.EXTRA_PROGRESS +import com.android.documentsui.services.Job +import com.android.documentsui.services.JobProgress +import com.android.documentsui.testing.MutableJobProgress +import junit.framework.Assert.assertEquals +import junit.framework.Assert.assertFalse +import junit.framework.Assert.assertTrue +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RequiresFlagsEnabled(FLAG_USE_MATERIAL3, FLAG_VISUAL_SIGNALS_RO) +@RunWith(AndroidJUnit4::class) +class JobPanelControllerTest { + @get:Rule + val mCheckFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + + private val mContext = InstrumentationRegistry.getInstrumentation().targetContext + + // The default progress bar only has an indeterminate state, so we need to style it to allow + // determinate progress. + private val mProgressBar = ProgressBar( + mContext, + null, + android.R.attr.progressBarStyleHorizontal + ) + private val mMenuItem = ActionMenuView(mContext).menu.add("job_panel").apply { + actionView = mProgressBar + } + private lateinit var mController: JobPanelController + private var mLastId = 0L + + private fun sendProgress(progress: ArrayList<JobProgress>, id: Long = mLastId++) { + var intent = Intent(ACTION_PROGRESS).apply { + `package` = mContext.packageName + putExtra("id", id) + putParcelableArrayListExtra(EXTRA_PROGRESS, progress) + } + mController.onReceive(mContext, intent) + } + + @Before + fun setUp() { + mController = JobPanelController(mContext) + mController.setMenuItem(mMenuItem) + } + + @Test + fun testSingleJob() { + assertFalse(mMenuItem.isVisible()) + assertFalse(mMenuItem.isEnabled()) + + val progress = MutableJobProgress( + id = "jobId1", + state = Job.STATE_STARTED, + msg = "Job started", + hasFailures = false, + currentBytes = 0, + requiredBytes = 10, + msRemaining = -1 + ) + sendProgress(arrayListOf(progress.toJobProgress())) + + assertTrue(mMenuItem.isVisible()) + assertTrue(mMenuItem.isEnabled()) + assertEquals(0, mProgressBar.progress) + + progress.apply { + state = Job.STATE_SET_UP + msg = "Job in progress" + currentBytes = 4 + } + sendProgress(arrayListOf(progress.toJobProgress())) + + assertTrue(mMenuItem.isVisible()) + assertTrue(mMenuItem.isEnabled()) + assertEquals(40, mProgressBar.progress) + + progress.apply { + state = Job.STATE_COMPLETED + msg = "Job completed" + currentBytes = 10 + } + sendProgress(arrayListOf(progress.toJobProgress())) + + assertTrue(mMenuItem.isVisible()) + assertTrue(mMenuItem.isEnabled()) + assertEquals(100, mProgressBar.progress) + } + + @Test + fun testMultipleJobs() { + assertFalse(mMenuItem.isVisible()) + assertFalse(mMenuItem.isEnabled()) + + val progress1 = MutableJobProgress( + id = "jobId1", + state = Job.STATE_STARTED, + msg = "Job started", + hasFailures = false, + currentBytes = 0, + requiredBytes = 10, + msRemaining = -1 + ) + val progress2 = MutableJobProgress( + id = "jobId2", + state = Job.STATE_STARTED, + msg = "Job started", + hasFailures = false, + currentBytes = 0, + requiredBytes = 40, + msRemaining = -1 + ) + sendProgress(arrayListOf(progress1.toJobProgress(), progress2.toJobProgress())) + + assertTrue(mMenuItem.isVisible()) + assertTrue(mMenuItem.isEnabled()) + assertEquals(0, mProgressBar.progress) + + progress1.apply { + state = Job.STATE_SET_UP + msg = "Job in progress" + currentBytes = 4 + } + sendProgress(arrayListOf(progress1.toJobProgress(), progress2.toJobProgress())) + + assertTrue(mMenuItem.isVisible()) + assertTrue(mMenuItem.isEnabled()) + assertEquals(8, mProgressBar.progress) + + progress1.apply { + state = Job.STATE_COMPLETED + msg = "Job completed" + currentBytes = 10 + } + sendProgress(arrayListOf(progress1.toJobProgress(), progress2.toJobProgress())) + + assertTrue(mMenuItem.isVisible()) + assertTrue(mMenuItem.isEnabled()) + assertEquals(20, mProgressBar.progress) + + progress2.apply { + state = Job.STATE_SET_UP + msg = "Job in progress" + currentBytes = 30 + } + sendProgress(arrayListOf(progress1.toJobProgress(), progress2.toJobProgress())) + + assertTrue(mMenuItem.isVisible()) + assertTrue(mMenuItem.isEnabled()) + assertEquals(80, mProgressBar.progress) + + progress2.apply { + state = Job.STATE_COMPLETED + msg = "Job completed" + currentBytes = 40 + } + sendProgress(arrayListOf(progress1.toJobProgress(), progress2.toJobProgress())) + + assertTrue(mMenuItem.isVisible()) + assertTrue(mMenuItem.isEnabled()) + assertEquals(100, mProgressBar.progress) + } +} diff --git a/tests/unit/com/android/documentsui/UserManagerStateTest.java b/tests/unit/com/android/documentsui/UserManagerStateTest.java index 9d629c574..04102a429 100644 --- a/tests/unit/com/android/documentsui/UserManagerStateTest.java +++ b/tests/unit/com/android/documentsui/UserManagerStateTest.java @@ -23,6 +23,7 @@ import static com.android.documentsui.DevicePolicyResources.Strings.WORK_TAB; import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -225,7 +226,7 @@ public class UserManagerStateTest { @Test public void testGetUserIds_allProfilesCurrentUserSystem_allShowInSharingSurfacesSeparate() { - if (!SdkLevel.isAtLeastV()) return; + assumeTrue(SdkLevel.isAtLeastV()); UserId currentUser = UserId.of(mSystemUser); initializeUserManagerState( currentUser, @@ -240,7 +241,7 @@ public class UserManagerStateTest { @Test public void testGetUserIds_allProfilesCurrentUserManaged_allShowInSharingSurfacesSeparate() { - if (!SdkLevel.isAtLeastV()) return; + assumeTrue(SdkLevel.isAtLeastV()); UserId currentUser = UserId.of(mManagedUser); initializeUserManagerState( currentUser, @@ -255,7 +256,7 @@ public class UserManagerStateTest { @Test public void testGetUserIds_allProfilesCurrentUserPrivate_allShowInSharingSurfacesSeparate() { - if (!SdkLevel.isAtLeastV()) return; + assumeTrue(SdkLevel.isAtLeastV()); UserId currentUser = UserId.of(mPrivateUser); initializeUserManagerState( currentUser, @@ -289,7 +290,7 @@ public class UserManagerStateTest { @Test public void testGetUserIds_systemAndPrivateUserCurrentUserSystem_returnsBoth() { - if (!SdkLevel.isAtLeastV()) return; + assumeTrue(SdkLevel.isAtLeastV()); UserId currentUser = UserId.of(mSystemUser); initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mPrivateUser)); @@ -300,7 +301,7 @@ public class UserManagerStateTest { @Test public void testGetUserIds_systemAndPrivateUserCurrentUserPrivate_returnsBoth() { - if (!SdkLevel.isAtLeastV()) return; + assumeTrue(SdkLevel.isAtLeastV()); UserId currentUser = UserId.of(mPrivateUser); initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mPrivateUser)); @@ -310,116 +311,6 @@ public class UserManagerStateTest { } @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. @@ -457,7 +348,8 @@ public class UserManagerStateTest { initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mManagedUser)); final List<ResolveInfo> mMockResolveInfoList = Lists.newArrayList(mMockInfoManagedUser); - when(mMockPackageManager.queryIntentActivities(any(Intent.class), anyInt())) + when(mMockPackageManager.queryIntentActivitiesAsUser( + any(Intent.class), anyInt(), eq(mSystemUser))) .thenReturn(mMockResolveInfoList); Map<UserId, Boolean> expectedCanForwardToProfileIdMap = new HashMap<>(); @@ -471,7 +363,7 @@ public class UserManagerStateTest { @Test public void testGetCanForwardToProfileIdMap_systemUserCanAlwaysForwardToPrivate() { - if (!SdkLevel.isAtLeastV()) return; + assumeTrue(SdkLevel.isAtLeastV()); UserId currentUser = UserId.of(mSystemUser); initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mPrivateUser)); @@ -497,8 +389,8 @@ public class UserManagerStateTest { .thenReturn(mMockResolveInfoList); } else { initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mManagedUser)); - when(mMockPackageManager.queryIntentActivities( - mMockIntent, PackageManager.MATCH_DEFAULT_ONLY)) + when(mMockPackageManager.queryIntentActivitiesAsUser( + mMockIntent, PackageManager.MATCH_DEFAULT_ONLY, mSystemUser)) .thenReturn(mMockResolveInfoList); } @@ -515,10 +407,13 @@ public class UserManagerStateTest { } @Test - public void testGetCanForwardToProfileIdMap_managedCanForwardToAll() { + public void testGetCanForwardToProfileIdMap_managedCanForwardToAllVPlus() { + assumeTrue(SdkLevel.isAtLeastV()); + UserId currentUser = UserId.of(mManagedUser); final List<ResolveInfo> mMockResolveInfoList = Lists.newArrayList(mMockInfoPrimaryUser); - when(mMockPackageManager.queryIntentActivities(any(Intent.class), anyInt())) + when(mMockPackageManager.queryIntentActivitiesAsUser( + any(Intent.class), anyInt(), eq(mManagedUser))) .thenReturn(mMockResolveInfoList); initializeUserManagerState( @@ -535,10 +430,31 @@ public class UserManagerStateTest { } @Test + public void testGetCanForwardToProfileIdMap_managedCanForwardToAllUMinus() { + assumeFalse(SdkLevel.isAtLeastV()); + + UserId currentUser = UserId.of(mManagedUser); + final List<ResolveInfo> mMockResolveInfoList = Lists.newArrayList(mMockInfoPrimaryUser); + when(mMockPackageManager.queryIntentActivitiesAsUser( + any(Intent.class), anyInt(), eq(mManagedUser))) + .thenReturn(mMockResolveInfoList); + + initializeUserManagerState( + currentUser, Lists.newArrayList(mSystemUser, mManagedUser)); + + 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_managedCanNotForwardToAll() { UserId currentUser = UserId.of(mManagedUser); - final List<ResolveInfo> mMockResolveInfoList = - Lists.newArrayList(mMockInfoPrivateUser, mMockInfoPrimaryUser); + final List<ResolveInfo> mMockResolveInfoList = Lists.newArrayList(mMockInfoPrimaryUser); if (SdkLevel.isAtLeastV()) { initializeUserManagerState( @@ -567,12 +483,14 @@ public class UserManagerStateTest { @Test public void testGetCanForwardToProfileIdMap_privateCanForwardToAll() { + assumeTrue(SdkLevel.isAtLeastV()); UserId currentUser = UserId.of(mPrivateUser); initializeUserManagerState( currentUser, Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser)); final List<ResolveInfo> mMockResolveInfoList = Lists.newArrayList(mMockInfoPrimaryUser, mMockInfoManagedUser); - when(mMockPackageManager.queryIntentActivities(any(Intent.class), anyInt())) + when(mMockPackageManager.queryIntentActivitiesAsUser( + any(Intent.class), anyInt(), eq(mSystemUser))) .thenReturn(mMockResolveInfoList); Map<UserId, Boolean> expectedCanForwardToProfileIdMap = new HashMap<>(); @@ -587,6 +505,7 @@ public class UserManagerStateTest { @Test public void testGetCanForwardToProfileIdMap_privateCanNotForwardToManagedUser() { + assumeTrue(SdkLevel.isAtLeastV()); UserId currentUser = UserId.of(mPrivateUser); initializeUserManagerState( currentUser, Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser)); @@ -607,7 +526,7 @@ public class UserManagerStateTest { @Test public void testGetCanForwardToProfileIdMap_privateCanAlwaysForwardToSystemUser() { - if (!SdkLevel.isAtLeastV()) return; + assumeTrue(SdkLevel.isAtLeastV()); UserId currentUser = UserId.of(mPrivateUser); initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mPrivateUser)); @@ -626,7 +545,7 @@ public class UserManagerStateTest { @Test public void testOnProfileStatusChange_anyIntentActionForManagedProfile() { - if (!SdkLevel.isAtLeastV()) return; + assumeTrue(SdkLevel.isAtLeastV()); UserId currentUser = UserId.of(mSystemUser); initializeUserManagerState( currentUser, Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser)); @@ -653,7 +572,7 @@ public class UserManagerStateTest { @Test public void testOnProfileStatusChange_actionProfileUnavailableForPrivateProfile() { - if (!SdkLevel.isAtLeastV()) return; + assumeTrue(SdkLevel.isAtLeastV()); UserId currentUser = UserId.of(mSystemUser); UserId managedUser = UserId.of(mManagedUser); UserId privateUser = UserId.of(mPrivateUser); @@ -666,8 +585,7 @@ public class UserManagerStateTest { 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 + // 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)); @@ -694,12 +612,12 @@ public class UserManagerStateTest { @Test public void testOnProfileStatusChange_actionProfileAvailable_profileInitialised() { - if (!SdkLevel.isAtLeastV()) return; + assumeTrue(SdkLevel.isAtLeastV()); UserId currentUser = UserId.of(mSystemUser); UserId managedUser = UserId.of(mManagedUser); UserId privateUser = UserId.of(mPrivateUser); final List<ResolveInfo> mMockResolveInfoList = - Lists.newArrayList(mMockInfoManagedUser, mMockInfoPrivateUser); + Lists.newArrayList(mMockInfoManagedUser); when(mMockPackageManager.queryIntentActivitiesAsUser( mMockIntent, PackageManager.MATCH_DEFAULT_ONLY, mSystemUser)) .thenReturn(mMockResolveInfoList); @@ -748,7 +666,8 @@ public class UserManagerStateTest { final List<ResolveInfo> mMockResolveInfoList = Lists.newArrayList(mMockInfoManagedUser); - when(mMockPackageManager.queryIntentActivities(any(Intent.class), anyInt())) + when(mMockPackageManager.queryIntentActivitiesAsUser( + any(Intent.class), anyInt(), eq(mSystemUser))) .thenReturn(mMockResolveInfoList); initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mManagedUser)); @@ -780,13 +699,14 @@ public class UserManagerStateTest { @Test public void testOnProfileStatusChange_actionProfileAvailable_profileNotInitialised() { - if (!SdkLevel.isAtLeastV()) return; + assumeTrue(SdkLevel.isAtLeastV()); UserId currentUser = UserId.of(mSystemUser); UserId managedUser = UserId.of(mManagedUser); UserId privateUser = UserId.of(mPrivateUser); final List<ResolveInfo> mMockResolveInfoList = Lists.newArrayList(mMockInfoManagedUser, mMockInfoPrivateUser); - when(mMockPackageManager.queryIntentActivities(any(Intent.class), anyInt())) + when(mMockPackageManager.queryIntentActivitiesAsUser( + any(Intent.class), anyInt(), eq(mSystemUser))) .thenReturn(mMockResolveInfoList); when(mMockUserManager.getProfileParent(UserHandle.of(privateUser.getIdentifier()))) @@ -836,7 +756,7 @@ public class UserManagerStateTest { @Test public void testGetUserIdToLabelMap_systemUserAndManagedUser_PreV() { - if (SdkLevel.isAtLeastV()) return; + assumeFalse(SdkLevel.isAtLeastV()); UserId currentUser = UserId.of(mSystemUser); initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mManagedUser)); if (SdkLevel.isAtLeastT()) { @@ -860,7 +780,7 @@ public class UserManagerStateTest { @Test public void testGetUserIdToLabelMap_systemUserManagedUserPrivateUser_PostV() { - if (!SdkLevel.isAtLeastV()) return; + assumeTrue(SdkLevel.isAtLeastV()); UserId currentUser = UserId.of(mSystemUser); initializeUserManagerState( currentUser, Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser)); @@ -891,7 +811,7 @@ public class UserManagerStateTest { @Test public void testGetUserIdToBadgeMap_systemUserManagedUser_PreV() { - if (SdkLevel.isAtLeastV()) return; + assumeFalse(SdkLevel.isAtLeastV()); UserId currentUser = UserId.of(mSystemUser); initializeUserManagerState(currentUser, Lists.newArrayList(mSystemUser, mManagedUser)); Drawable workBadge = mock(Drawable.class); @@ -919,7 +839,7 @@ public class UserManagerStateTest { @Test public void testGetUserIdToBadgeMap_systemUserManagedUserPrivateUser_PostV() { - if (!SdkLevel.isAtLeastV()) return; + assumeTrue(SdkLevel.isAtLeastV()); UserId currentUser = UserId.of(mSystemUser); initializeUserManagerState( currentUser, Lists.newArrayList(mSystemUser, mManagedUser, mPrivateUser)); diff --git a/tests/unit/com/android/documentsui/files/MenuManagerTest.java b/tests/unit/com/android/documentsui/files/MenuManagerTest.java index ac7b1c4f7..8bc5ad707 100644 --- a/tests/unit/com/android/documentsui/files/MenuManagerTest.java +++ b/tests/unit/com/android/documentsui/files/MenuManagerTest.java @@ -22,6 +22,7 @@ import static junit.framework.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import android.annotation.SuppressLint; import android.net.Uri; import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; @@ -79,6 +80,8 @@ public final class MenuManagerTest { private TestMenuItem dirPasteIntoFolder; private TestMenuItem dirInspect; private TestMenuItem dirOpenInNewWindow; + private TestMenuItem mDirExtractHere; + private TestMenuItem mDirBrowse; /* Root List Context Menu items */ private TestMenuItem rootEjectRoot; @@ -156,6 +159,8 @@ public final class MenuManagerTest { dirPasteIntoFolder = testMenu.findItem(R.id.dir_menu_paste_into_folder); dirInspect = testMenu.findItem(R.id.dir_menu_inspect); dirOpenInNewWindow = testMenu.findItem(R.id.dir_menu_open_in_new_window); + mDirExtractHere = testMenu.findItem(R.id.dir_menu_extract_here); + mDirBrowse = testMenu.findItem(R.id.dir_menu_browse); rootEjectRoot = testMenu.findItem(R.id.root_menu_eject_root); rootOpenInNewWindow = testMenu.findItem(R.id.root_menu_open_in_new_window); @@ -537,6 +542,7 @@ public final class MenuManagerTest { assertEquals(R.menu.mixed_context_menu, inflater.lastInflatedMenuId); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_EmptyArea() { mgr.updateContextMenuForContainer(testMenu, selectionDetails); @@ -545,8 +551,11 @@ public final class MenuManagerTest { mDirDeselectAll.assertDisabledAndInvisible(); dirPasteFromClipboard.assertDisabledAndInvisible(); dirCreateDir.assertDisabledAndInvisible(); + mDirExtractHere.assertDisabledAndInvisible(); + mDirBrowse.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_EmptyArea_CanDeselectAll() { selectionDetails.size = 1; @@ -558,6 +567,7 @@ public final class MenuManagerTest { mDirDeselectAll.assertEnabledAndVisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_EmptyArea_NoItemToPaste() { dirDetails.hasItemsToPaste = false; @@ -570,6 +580,7 @@ public final class MenuManagerTest { dirCreateDir.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_EmptyArea_CantCreateDoc() { dirDetails.hasItemsToPaste = true; @@ -582,6 +593,7 @@ public final class MenuManagerTest { dirCreateDir.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_EmptyArea_CanPaste() { dirDetails.hasItemsToPaste = true; @@ -594,6 +606,7 @@ public final class MenuManagerTest { dirCreateDir.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_EmptyArea_CanCreateDirectory() { dirDetails.canCreateDirectory = true; @@ -605,6 +618,7 @@ public final class MenuManagerTest { dirCreateDir.assertEnabledAndVisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_OnFile() { selectionDetails.size = 1; @@ -616,8 +630,11 @@ public final class MenuManagerTest { dirRename.assertDisabledAndInvisible(); dirCreateDir.assertEnabledAndVisible(); dirDelete.assertDisabledAndInvisible(); + mDirExtractHere.assertDisabledAndInvisible(); + mDirBrowse.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test @RequiresFlagsDisabled({Flags.FLAG_DESKTOP_FILE_HANDLING_RO}) public void testContextMenu_OnFile_CanOpen() { @@ -627,6 +644,7 @@ public final class MenuManagerTest { dirOpenWith.assertEnabledAndVisible(); } + @SuppressLint("VisibleForTests") @Test @RequiresFlagsEnabled({Flags.FLAG_DESKTOP_FILE_HANDLING_RO}) public void testContextMenu_OnFile_CanOpenDesktop() { @@ -636,6 +654,7 @@ public final class MenuManagerTest { dirOpenWith.assertEnabledAndVisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_OnFile_NoOpen() { selectionDetails.canOpen = false; @@ -644,6 +663,7 @@ public final class MenuManagerTest { dirOpenWith.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_OnMultipleFiles() { selectionDetails.size = 3; @@ -652,6 +672,7 @@ public final class MenuManagerTest { mDirCompress.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_OnWritableDirectory() { selectionDetails.size = 1; @@ -665,8 +686,11 @@ public final class MenuManagerTest { dirPasteIntoFolder.assertEnabledAndVisible(); dirRename.assertDisabledAndInvisible(); dirDelete.assertDisabledAndInvisible(); + mDirExtractHere.assertDisabledAndInvisible(); + mDirBrowse.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_OnNonWritableDirectory() { selectionDetails.size = 1; @@ -679,8 +703,11 @@ public final class MenuManagerTest { dirPasteIntoFolder.assertDisabledAndInvisible(); dirRename.assertDisabledAndInvisible(); dirDelete.assertDisabledAndInvisible(); + mDirExtractHere.assertDisabledAndInvisible(); + mDirBrowse.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_CanInspectContainer() { features.inspector = true; @@ -689,6 +716,7 @@ public final class MenuManagerTest { dirInspect.assertEnabledAndVisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_OnWritableDirectory_NothingToPaste() { selectionDetails.canPasteInto = true; @@ -698,6 +726,7 @@ public final class MenuManagerTest { dirPasteIntoFolder.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_OnMultipleDirectories() { selectionDetails.size = 3; @@ -706,6 +735,7 @@ public final class MenuManagerTest { mDirCompress.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_OnMixedDocs() { selectionDetails.containDirectories = true; @@ -717,8 +747,11 @@ public final class MenuManagerTest { dirCopyToClipboard.assertEnabledAndVisible(); mDirCompress.assertDisabledAndInvisible(); dirDelete.assertEnabledAndVisible(); + mDirExtractHere.assertDisabledAndInvisible(); + mDirBrowse.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_OnMixedDocs_hasPartialFile() { selectionDetails.containDirectories = true; @@ -733,6 +766,7 @@ public final class MenuManagerTest { dirDelete.assertEnabledAndVisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_OnMixedDocs_hasUndeletableFile() { selectionDetails.containDirectories = true; @@ -746,6 +780,7 @@ public final class MenuManagerTest { dirDelete.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_CanInspectSingleSelection() { selectionDetails.size = 1; @@ -753,6 +788,22 @@ public final class MenuManagerTest { dirInspect.assertEnabledAndVisible(); } + @SuppressLint("VisibleForTests") + @Test + public void testContextMenu_OnArchive() { + selectionDetails.size = 1; + selectionDetails.containFiles = true; + selectionDetails.isArchive = true; + mgr.updateContextMenuForFiles(testMenu, selectionDetails); + if (isZipNgFlagEnabled()) { + mDirExtractHere.assertEnabledAndVisible(); + mDirBrowse.assertEnabledAndVisible(); + } else { + mDirExtractHere.assertDisabledAndInvisible(); + mDirBrowse.assertDisabledAndInvisible(); + } + } + @Test public void testRootContextMenu() { testRootInfo.flags = Root.FLAG_SUPPORTS_CREATE; diff --git a/tests/unit/com/android/documentsui/loaders/FolderLoaderTest.kt b/tests/unit/com/android/documentsui/loaders/FolderLoaderTest.kt index 44c410eff..0193ea77d 100644 --- a/tests/unit/com/android/documentsui/loaders/FolderLoaderTest.kt +++ b/tests/unit/com/android/documentsui/loaders/FolderLoaderTest.kt @@ -22,7 +22,7 @@ import android.platform.test.flag.junit.DeviceFlagsValueProvider import androidx.test.filters.SmallTest import com.android.documentsui.ContentLock import com.android.documentsui.base.DocumentInfo -import com.android.documentsui.flags.Flags.FLAG_USE_SEARCH_V2_RW +import com.android.documentsui.flags.Flags.FLAG_USE_SEARCH_V2_READ_ONLY import com.android.documentsui.testing.TestFileTypeLookup import com.android.documentsui.testing.TestProvidersAccess import java.time.Duration @@ -59,7 +59,7 @@ class FolderLoaderTest(private val testParams: LoaderTestParams) : BaseLoaderTes val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() @Test - @RequiresFlagsEnabled(FLAG_USE_SEARCH_V2_RW) + @RequiresFlagsEnabled(FLAG_USE_SEARCH_V2_READ_ONLY) fun testLoadInBackground() { val mockProvider = mEnv.mockProviders[TestProvidersAccess.DOWNLOADS.authority] val docs = createDocuments(TOTAL_FILE_COUNT) diff --git a/tests/unit/com/android/documentsui/loaders/SearchLoaderTest.kt b/tests/unit/com/android/documentsui/loaders/SearchLoaderTest.kt index e480337ab..7265af34b 100644 --- a/tests/unit/com/android/documentsui/loaders/SearchLoaderTest.kt +++ b/tests/unit/com/android/documentsui/loaders/SearchLoaderTest.kt @@ -24,7 +24,7 @@ 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.flags.Flags.FLAG_USE_SEARCH_V2_RW +import com.android.documentsui.flags.Flags.FLAG_USE_SEARCH_V2_READ_ONLY import com.android.documentsui.testing.TestFileTypeLookup import com.android.documentsui.testing.TestProvidersAccess import java.time.Duration @@ -80,7 +80,7 @@ class SearchLoaderTest(private val testParams: LoaderTestParams) : BaseLoaderTes } @Test - @RequiresFlagsEnabled(FLAG_USE_SEARCH_V2_RW) + @RequiresFlagsEnabled(FLAG_USE_SEARCH_V2_READ_ONLY) fun testLoadInBackground() { val mockProvider = mEnv.mockProviders[TestProvidersAccess.DOWNLOADS.authority] val docs = createDocuments(TOTAL_FILE_COUNT) @@ -119,7 +119,7 @@ class SearchLoaderTest(private val testParams: LoaderTestParams) : BaseLoaderTes } @Test - @RequiresFlagsEnabled(FLAG_USE_SEARCH_V2_RW) + @RequiresFlagsEnabled(FLAG_USE_SEARCH_V2_READ_ONLY) @Ignore("b/397095797") fun testBlankQueryAndRecency() { val userIds = listOf(TestProvidersAccess.DOWNLOADS.userId) diff --git a/tests/unit/com/android/documentsui/picker/MenuManagerTest.java b/tests/unit/com/android/documentsui/picker/MenuManagerTest.java index 266489d61..27ffcbdaa 100644 --- a/tests/unit/com/android/documentsui/picker/MenuManagerTest.java +++ b/tests/unit/com/android/documentsui/picker/MenuManagerTest.java @@ -23,6 +23,7 @@ import static com.android.documentsui.base.State.ACTION_OPEN; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import android.annotation.SuppressLint; import android.database.MatrixCursor; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; @@ -70,6 +71,8 @@ public final class MenuManagerTest { private TestMenuItem dirViewInOwner; private TestMenuItem dirOpenInNewWindow; private TestMenuItem dirPasteIntoFolder; + private TestMenuItem mDirExtractHere; + private TestMenuItem mDirBrowse; /* Root List Context Menu items */ private TestMenuItem rootEjectRoot; @@ -136,6 +139,8 @@ public final class MenuManagerTest { dirViewInOwner = testMenu.findItem(R.id.dir_menu_view_in_owner); dirOpenInNewWindow = testMenu.findItem(R.id.dir_menu_open_in_new_window); dirPasteIntoFolder = testMenu.findItem(R.id.dir_menu_paste_into_folder); + mDirExtractHere = testMenu.findItem(R.id.dir_menu_extract_here); + mDirBrowse = testMenu.findItem(R.id.dir_menu_browse); rootEjectRoot = testMenu.findItem(R.id.root_menu_eject_root); rootOpenInNewWindow = testMenu.findItem(R.id.root_menu_open_in_new_window); @@ -339,6 +344,7 @@ public final class MenuManagerTest { optionSelectAll.assertEnabledAndVisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_EmptyArea() { dirDetails.hasItemsToPaste = false; @@ -351,8 +357,11 @@ public final class MenuManagerTest { mDirDeselectAll.assertDisabledAndInvisible(); dirPasteFromClipboard.assertDisabledAndInvisible(); dirCreateDir.assertDisabledAndInvisible(); + mDirExtractHere.assertDisabledAndInvisible(); + mDirBrowse.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_EmptyArea_NoItemToPaste() { dirDetails.hasItemsToPaste = false; @@ -363,8 +372,11 @@ public final class MenuManagerTest { dirSelectAll.assertEnabledAndVisible(); dirPasteFromClipboard.assertDisabledAndInvisible(); dirCreateDir.assertDisabledAndInvisible(); + mDirExtractHere.assertDisabledAndInvisible(); + mDirBrowse.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_EmptyArea_CantCreateDoc() { dirDetails.hasItemsToPaste = true; @@ -375,8 +387,11 @@ public final class MenuManagerTest { dirSelectAll.assertEnabledAndVisible(); dirPasteFromClipboard.assertDisabledAndInvisible(); dirCreateDir.assertDisabledAndInvisible(); + mDirExtractHere.assertDisabledAndInvisible(); + mDirBrowse.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_EmptyArea_canPaste() { dirDetails.hasItemsToPaste = true; @@ -387,8 +402,11 @@ public final class MenuManagerTest { dirSelectAll.assertEnabledAndVisible(); dirPasteFromClipboard.assertEnabledAndVisible(); dirCreateDir.assertDisabledAndInvisible(); + mDirExtractHere.assertDisabledAndInvisible(); + mDirBrowse.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_EmptyArea_CanCreateDirectory() { dirDetails.canCreateDirectory = true; @@ -398,8 +416,11 @@ public final class MenuManagerTest { dirSelectAll.assertEnabledAndVisible(); dirPasteFromClipboard.assertDisabledAndInvisible(); dirCreateDir.assertEnabledAndVisible(); + mDirExtractHere.assertDisabledAndInvisible(); + mDirBrowse.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_EmptyArea_CanDeselectAll() { selectionDetails.size = 1; @@ -411,6 +432,7 @@ public final class MenuManagerTest { mDirDeselectAll.assertEnabledAndVisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_OnFile() { mgr.updateContextMenuForFiles(testMenu, selectionDetails); @@ -423,8 +445,11 @@ public final class MenuManagerTest { mDirCompress.assertDisabledAndInvisible(); dirRename.assertDisabledAndInvisible(); dirDelete.assertDisabledAndInvisible(); + mDirExtractHere.assertDisabledAndInvisible(); + mDirBrowse.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_OnDirectory() { selectionDetails.canPasteInto = true; @@ -438,8 +463,11 @@ public final class MenuManagerTest { dirPasteIntoFolder.assertDisabledAndInvisible(); dirRename.assertDisabledAndInvisible(); dirDelete.assertDisabledAndInvisible(); + mDirExtractHere.assertDisabledAndInvisible(); + mDirBrowse.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_OnMixedDocs() { selectionDetails.containDirectories = true; @@ -451,8 +479,11 @@ public final class MenuManagerTest { dirCopyToClipboard.assertEnabledAndVisible(); mDirCompress.assertDisabledAndInvisible(); dirDelete.assertEnabledAndVisible(); + mDirExtractHere.assertDisabledAndInvisible(); + mDirBrowse.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_OnMixedDocs_hasPartialFile() { selectionDetails.containDirectories = true; @@ -465,8 +496,11 @@ public final class MenuManagerTest { dirCopyToClipboard.assertDisabledAndInvisible(); mDirCompress.assertDisabledAndInvisible(); dirDelete.assertEnabledAndVisible(); + mDirExtractHere.assertDisabledAndInvisible(); + mDirBrowse.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") @Test public void testContextMenu_OnMixedDocs_hasUndeletableFile() { selectionDetails.containDirectories = true; @@ -478,6 +512,19 @@ public final class MenuManagerTest { dirCopyToClipboard.assertEnabledAndVisible(); mDirCompress.assertDisabledAndInvisible(); dirDelete.assertDisabledAndInvisible(); + mDirExtractHere.assertDisabledAndInvisible(); + mDirBrowse.assertDisabledAndInvisible(); + } + + @SuppressLint("VisibleForTests") + @Test + public void testContextMenu_OnArchive() { + selectionDetails.size = 1; + selectionDetails.containFiles = true; + selectionDetails.isArchive = true; + mgr.updateContextMenuForFiles(testMenu, selectionDetails); + mDirExtractHere.assertDisabledAndInvisible(); + mDirBrowse.assertDisabledAndInvisible(); } @Test @@ -523,6 +570,7 @@ public final class MenuManagerTest { rootEjectRoot.assertDisabledAndInvisible(); } + @SuppressLint("VisibleForTests") private Model getTestModel(boolean onlyDirectory) { String[] COLUMNS = new String[]{ RootCursorWrapper.COLUMN_AUTHORITY, diff --git a/tests/unit/com/android/documentsui/queries/SearchChipViewManagerTest.java b/tests/unit/com/android/documentsui/queries/SearchChipViewManagerTest.java index 6d20447dd..02e24a329 100644 --- a/tests/unit/com/android/documentsui/queries/SearchChipViewManagerTest.java +++ b/tests/unit/com/android/documentsui/queries/SearchChipViewManagerTest.java @@ -18,6 +18,7 @@ package com.android.documentsui.queries; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.spy; @@ -35,6 +36,9 @@ import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.DocumentsContract; import android.view.View; import android.view.ViewGroup; +import android.view.ViewParent; +import android.widget.FrameLayout; +import android.widget.HorizontalScrollView; import android.widget.LinearLayout; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -235,6 +239,37 @@ public final class SearchChipViewManagerTest { assertThat(View.VISIBLE).isEqualTo(mirror.getVisibility()); } + @Test + public void testChipChecked_resetScroll() { + // Mock chip group's parent chain according to search_chip_row.xml. + FrameLayout parent = spy(new FrameLayout(mContext)); + HorizontalScrollView grandparent = spy(new HorizontalScrollView(mContext)); + parent.addView(mChipGroup); + grandparent.addView(parent); + // Verify that getParent().getParent() returns the HorizontalScrollView mock. + ViewParent result = mChipGroup.getParent().getParent(); + assertEquals(grandparent, result); + + mSearchChipViewManager.initChipSets( + new String[] {"image/*", "audio/*", "video/*", "text/*"}); + mSearchChipViewManager.updateChips(new String[] {"*/*"}); + + // Manually set HorizontalScrollView's scrollX to something larger than 0. + grandparent.scrollTo(100, 0); + assertTrue(grandparent.getScaleX() > 0); + + assertEquals(6, mChipGroup.getChildCount()); + Chip lastChip = (Chip) mChipGroup.getChildAt(5); + + // chip.setChecked will trigger reorder animation, which needs to be run inside + // the looper thread. + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + // Check last chip will move it to the first child and reset scroll view. + lastChip.setChecked(true); + assertEquals(0, grandparent.getScrollX()); + }); + } + private static Set<SearchChipData> getFakeSearchChipDataList() { final Set<SearchChipData> chipDataList = new HashSet<>(); chipDataList.add(new SearchChipData(CHIP_TYPE, 0 /* titleRes */, TEST_MIME_TYPES)); |