diff options
54 files changed, 1245 insertions, 206 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index d948b605c..6b4bed88f 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -52,6 +52,7 @@ android:allowBackup="true" android:backupAgent=".prefs.BackupAgent" android:fullBackupOnly="false" + android:enableOnBackInvokedCallback="false" android:crossProfile="true"> <meta-data @@ -3,4 +3,4 @@ include platform/frameworks/base:/core/java/android/os/storage/OWNERS benreich@google.com -wenbojie@google.com +alexbn@google.com diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_badge_icon_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_badge_icon_color.xml new file mode 100644 index 000000000..de2849840 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_badge_icon_color.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_selected="true" android:color="?attr/colorOnPrimary" /> + <item android:color="?attr/colorSecondary" /> +</selector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_label_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_label_color.xml new file mode 100644 index 000000000..2b8f2726b --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_label_color.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_selected="true" android:color="?attr/colorOnPrimary" /> + <item android:color="?attr/colorOnSurface" /> +</selector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_subtitle_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_subtitle_color.xml index d9f27e60a..d3d48f152 100644 --- a/res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_subtitle_color.xml +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_subtitle_color.xml @@ -16,7 +16,6 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_enabled="false" - android:color="@color/doc_list_item_subtitle_disabled" /> - <item android:color="@color/doc_list_item_subtitle_enabled" /> + <item android:state_selected="true" android:color="?attr/colorOnPrimary" /> + <item android:color="?attr/colorOnSurfaceVariant" /> </selector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/color/nav_rail_item_text_color.xml b/res/flag(com.android.documentsui.flags.use_material3)/color/nav_rail_item_text_color.xml new file mode 100644 index 000000000..ec5aecb33 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/color/nav_rail_item_text_color.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_activated="true" android:color="?attr/colorSecondary" /> + <item android:color="?attr/colorOnSurfaceVariant" /> +</selector> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_check_circle.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_check_circle.xml index 88b784183..71ad135b1 100644 --- a/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_check_circle.xml +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_check_circle.xml @@ -14,11 +14,12 @@ Copyright (C) 2024 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:width="20dp" + android:height="20dp" + android:viewportWidth="960" + android:viewportHeight="960"> <path - android:fillColor="?android:attr/colorAccent" - android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10,-4.48 10,-10S17.52 2 12 2zm-2 15l-5,-5 1.41,-1.41L10 14.17l7.59,-7.59L19 8l-9 9z"/> + android:fillColor="?attr/colorOnPrimaryContainer" + android:pathData="M428.28,628.78L669.87,388.2L612.41,330.5L428.28,513.63L346.15,432.5L288.7,490.2L428.28,628.78ZM480,872.13Q399.09,872.13 327.66,841.51Q256.22,810.89 202.66,757.34Q149.11,703.78 118.49,632.34Q87.87,560.91 87.87,480Q87.87,398.09 118.49,327.16Q149.11,256.22 202.66,202.66Q256.22,149.11 327.66,118.49Q399.09,87.87 480,87.87Q561.91,87.87 632.84,118.49Q703.78,149.11 757.34,202.66Q810.89,256.22 841.51,327.16Q872.13,398.09 872.13,480Q872.13,560.91 841.51,632.34Q810.89,703.78 757.34,757.34Q703.78,810.89 632.84,841.51Q561.91,872.13 480,872.13Z"/> </vector> + diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/list_item_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/list_item_background.xml index 126788c6d..797685ce6 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 @@ -14,18 +14,80 @@ limitations under the License. --> +<!-- Use @color/list_item_selected_background_color instead of the "?attr/colorPrimary" + because the variable is exposed in overlayable.xml. --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_focused="true" > - <color android:color="@color/list_item_selected_background_color"/> + <!-- selected --> + <item android:state_selected="true" android:state_drag_hovered="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/list_item_height" /> + <solid android:color="@color/list_item_selected_background_color" /> + </shape> + </item> + <item> + <shape android:tint="?attr/colorOnPrimary"> + <corners android:radius="@dimen/list_item_height" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + </layer-list> + </item> + <item android:state_selected="true" android:state_focused="true"> + <layer-list> + <item + android:bottom="@dimen/focus_ring_gap" + android:left="@dimen/focus_ring_gap" + android:right="@dimen/focus_ring_gap" + android:top="@dimen/focus_ring_gap"> + <shape> + <corners android:radius="@dimen/list_item_height" /> + <solid android:color="@color/list_item_selected_background_color" /> + </shape> + </item> + <item> + <shape> + <corners android:radius="@dimen/list_item_height" /> + <stroke + android:width="@dimen/focus_ring_width" + android:color="?attr/colorSecondary" /> + </shape> + </item> + </layer-list> + </item> + <item android:state_selected="true" android:state_hovered="true"> + <shape> + <corners android:radius="@dimen/list_item_height" /> + <solid android:color="@color/list_item_selected_background_color" /> + </shape> </item> <item android:state_selected="true"> - <color android:color="@color/list_item_selected_background_color"/> + <shape> + <corners android:radius="@dimen/list_item_height" /> + <solid android:color="@color/list_item_selected_background_color" /> + </shape> </item> + + <!-- unselected --> <item android:state_drag_hovered="true"> - <color android:color="?android:strokeColor"/> + <shape android:tint="?attr/colorOnSurface"> + <corners android:radius="@dimen/list_item_height" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + <item android:state_focused="true"> + <shape> + <corners android:radius="@dimen/list_item_height" /> + <stroke + android:width="@dimen/focus_ring_width" + android:color="?attr/colorSecondary" /> + </shape> + </item> + <item android:state_hovered="true"> + <color android:color="@android:color/transparent"/> </item> - <item android:state_selected="false" - android:state_focused="false"> - <color android:color="?android:attr/colorBackground"/> + <item> + <color android:color="?attr/colorSurfaceBright"/> </item> </selector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_background.xml new file mode 100644 index 000000000..7809766cd --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_background.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- By default the nav rail item has a grey background when it's focused, but we need the + background to be put on the icon inside, so we override the focus background color to be + transparent here. + --> + <item android:state_focused="true" android:drawable="@android:color/transparent" /> +</selector>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_icon_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_icon_background.xml new file mode 100644 index 000000000..1c7bc8c0b --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_icon_background.xml @@ -0,0 +1,145 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<ripple + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:color="@color/item_root_ripple_color"> + + <!-- The mask below only works for the ripple itself, doesn't work for other <item>s, we + need to explicitly apply the drawable if the other items also need this mask. --> + <item + android:id="@android:id/mask" + android:drawable="@drawable/nav_rail_item_icon_mask"/> + + <item> + <selector> + <!-- Selected (activated). --> + <!-- Highlight: when dragging files over the item. --> + <item + android:state_activated="true" + app:state_highlighted="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="?attr/colorSecondaryContainer" /> + </shape> + </item> + <item> + <shape android:tint="?attr/colorOnSecondaryContainer"> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + </layer-list> + </item> + <item + android:state_activated="true" + android:state_pressed="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="?attr/colorSecondaryContainer" /> + </shape> + </item> + <item> + <shape android:tint="?attr/colorOnSecondaryContainer"> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + </layer-list> + </item> + <item + android:state_activated="true" + android:state_focused="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="?attr/colorSecondaryContainer" /> + </shape> + </item> + <item> + <shape> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <stroke + android:width="@dimen/focus_ring_width" + android:color="?attr/colorSecondary" /> + </shape> + </item> + </layer-list> + </item> + <item + android:state_activated="true" + android:state_hovered="true"> + <layer-list> + <item> + <shape> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="?attr/colorSecondaryContainer" /> + </shape> + </item> + <item> + <shape android:tint="?attr/colorOnSecondaryContainer"> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + </layer-list> + </item> + <item android:state_activated="true"> + <shape> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="?attr/colorSecondaryContainer" /> + </shape> + </item> + + <!-- Unselected. --> + <item app:state_highlighted="true"> + <shape android:tint="?attr/colorOnSurface"> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + <item android:state_pressed="true"> + <shape android:tint="?attr/colorOnSurface"> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + <item android:state_focused="true"> + <shape> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <stroke + android:width="@dimen/focus_ring_width" + android:color="?attr/colorSecondary" /> + </shape> + </item> + <item android:state_hovered="true"> + <shape android:tint="?attr/colorOnSurface"> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius" /> + <solid android:color="@color/overlay_hover_color_percentage" /> + </shape> + </item> + + <!-- Default: use the container background. --> + <item android:drawable="@android:color/transparent" /> + </selector> + </item> +</ripple>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_icon_mask.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_icon_mask.xml new file mode 100644 index 000000000..fd2a14b8d --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_icon_mask.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <corners android:radius="@dimen/nav_rail_item_icon_bg_radius"/> + <!-- The color here doesn't matter, it's just being used as a mask. --> + <solid android:color="@android:color/white" /> +</shape>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/progress_indeterminate_horizontal_material_trimmed.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/progress_indeterminate_horizontal_material_trimmed.xml index 1200ab00b..68782024b 100644 --- a/res/flag(com.android.documentsui.flags.use_material3)/drawable/progress_indeterminate_horizontal_material_trimmed.xml +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/progress_indeterminate_horizontal_material_trimmed.xml @@ -14,6 +14,7 @@ limitations under the License. --> +<!-- TODO(b/379776735): remove this file after M3 uplift --> <!-- Variant of progress_indeterminate_horizontal_material in frameworks/base/core/res, which draws the whole height of the progress bar instead having blank space above and below the bar. --> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/root_item_background.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/root_item_background.xml index eea916ce2..236b92179 100644 --- a/res/flag(com.android.documentsui.flags.use_material3)/drawable/root_item_background.xml +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/root_item_background.xml @@ -40,7 +40,7 @@ <item> <shape android:tint="?attr/colorOnSecondaryContainer"> <corners android:radius="@dimen/drawer_item_height"/> - <solid android:color="@color/overlay_color_percentage_10"/> + <solid android:color="@color/overlay_hover_color_percentage"/> </shape> </item> </layer-list> @@ -56,7 +56,7 @@ <item> <shape android:tint="?attr/colorOnSecondaryContainer"> <corners android:radius="@dimen/drawer_item_height"/> - <solid android:color="@color/overlay_color_percentage_10"/> + <solid android:color="@color/overlay_hover_color_percentage"/> </shape> </item> </layer-list> @@ -88,7 +88,7 @@ <item> <shape android:tint="?attr/colorOnSecondaryContainer"> <corners android:radius="@dimen/drawer_item_height"/> - <solid android:color="@color/overlay_color_percentage_10"/> + <solid android:color="@color/overlay_hover_color_percentage"/> </shape> </item> </layer-list> @@ -99,13 +99,13 @@ <item app:state_highlighted="true"> <shape android:tint="?attr/colorOnSurface"> <corners android:radius="@dimen/drawer_item_height"/> - <solid android:color="@color/overlay_color_percentage_10"/> + <solid android:color="@color/overlay_hover_color_percentage"/> </shape> </item> <item android:state_pressed="true"> <shape android:tint="?attr/colorOnSurface"> <corners android:radius="@dimen/drawer_item_height"/> - <solid android:color="@color/overlay_color_percentage_10"/> + <solid android:color="@color/overlay_hover_color_percentage"/> </shape> </item> <item android:state_focused="true"> @@ -117,7 +117,7 @@ <item android:state_hovered="true"> <shape android:tint="?attr/colorOnSurface"> <corners android:radius="@dimen/drawer_item_height"/> - <solid android:color="@color/overlay_color_percentage_10"/> + <solid android:color="@color/overlay_hover_color_percentage"/> </shape> </item> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/drawable/tab_border_rounded.xml b/res/flag(com.android.documentsui.flags.use_material3)/drawable/tab_border_rounded.xml index b50587c01..08d515301 100644 --- a/res/flag(com.android.documentsui.flags.use_material3)/drawable/tab_border_rounded.xml +++ b/res/flag(com.android.documentsui.flags.use_material3)/drawable/tab_border_rounded.xml @@ -38,7 +38,7 @@ <item> <shape android:tint="?attr/colorOnPrimaryContainer"> <corners android:radius="@dimen/profile_tab_radius" /> - <solid android:color="@color/overlay_color_percentage_10" /> + <solid android:color="@color/overlay_hover_color_percentage" /> </shape> </item> </layer-list> @@ -72,7 +72,7 @@ <item> <shape android:tint="?attr/colorOnPrimaryContainer"> <corners android:radius="@dimen/profile_tab_radius" /> - <solid android:color="@color/overlay_color_percentage_10" /> + <solid android:color="@color/overlay_hover_color_percentage" /> </shape> </item> </layer-list> @@ -96,7 +96,7 @@ <item> <shape android:tint="?attr/colorOnSurface"> <corners android:radius="@dimen/profile_tab_radius" /> - <solid android:color="@color/overlay_color_percentage_10" /> + <solid android:color="@color/overlay_hover_color_percentage" /> </shape> </item> </layer-list> @@ -130,7 +130,7 @@ <item> <shape android:tint="?attr/colorOnSurface"> <corners android:radius="@dimen/profile_tab_radius" /> - <solid android:color="@color/overlay_color_percentage_10" /> + <solid android:color="@color/overlay_hover_color_percentage" /> </shape> </item> </layer-list> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout-w900dp/item_doc_list.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout-w900dp/item_doc_list.xml index d9b0ab6f4..b0db7ec38 100644 --- a/res/flag(com.android.documentsui.flags.use_material3)/layout-w900dp/item_doc_list.xml +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout-w900dp/item_doc_list.xml @@ -20,7 +20,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/list_item_background" - android:foreground="?android:attr/selectableItemBackground" android:clickable="true" android:focusable="true" android:orientation="horizontal" > @@ -31,23 +30,24 @@ android:baselineAligned="false" android:gravity="center_vertical" android:minHeight="@dimen/list_item_height" - android:orientation="horizontal" > + android:orientation="horizontal" + android:paddingStart="@dimen/list_item_padding_start" + android:paddingEnd="@dimen/list_item_padding_end" + android:paddingVertical="@dimen/list_item_padding_vertical"> <FrameLayout android:id="@+id/icon" android:pointerIcon="hand" - android:layout_width="@dimen/list_item_width" - android:layout_height="@dimen/list_item_height" - android:paddingBottom="@dimen/list_item_icon_padding" - android:paddingTop="@dimen/list_item_icon_padding" - android:paddingEnd="16dp" - android:paddingStart="@dimen/list_item_padding" > + android:layout_width="@dimen/list_item_icon_size" + android:layout_height="@dimen/list_item_icon_size" + android:layout_marginEnd="@dimen/list_item_icon_margin_end"> <com.google.android.material.card.MaterialCardView app:cardElevation="0dp" app:cardBackgroundColor="@android:color/transparent" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + app:strokeWidth="0dp"> <ImageView android:id="@+id/icon_mime" @@ -101,83 +101,55 @@ android:layout_marginEnd="@dimen/briefcase_icon_margin" android:layout_gravity="center_vertical" android:src="@drawable/ic_briefcase" - android:tint="?android:attr/colorAccent" + android:tint="@color/doc_list_item_badge_icon_color" android:contentDescription="@string/a11y_work"/> <TextView android:id="@android:id/title" android:layout_width="match_parent" android:layout_height="wrap_content" - android:ellipsize="middle" + android:ellipsize="end" android:singleLine="true" android:textAlignment="viewStart" - android:textAppearance="@style/Subhead" - android:textColor="?android:attr/textColorPrimary"/> + android:textAppearance="@style/FileItemLabelText"/> </LinearLayout> <TextView android:id="@+id/file_type" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginEnd="12dp" android:layout_weight="0.2" - android:ellipsize="end" - android:singleLine="true" - android:textAlignment="viewStart" - android:textAppearance="@style/Body1" - android:textColor="?android:attr/textColorSecondary" /> + style="@style/FileItemLabelStyle"/> <TextView android:id="@+id/size" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginEnd="12dp" android:layout_weight="0.2" - android:ellipsize="end" - android:minWidth="70dp" - android:singleLine="true" - android:textAlignment="viewEnd" - android:textAppearance="@style/Body1" - android:textColor="?android:attr/textColorSecondary" /> + style="@style/FileItemLabelStyle"/> <TextView android:id="@+id/date" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginEnd="12dp" android:layout_weight="0.2" - android:ellipsize="end" - android:minWidth="70dp" - android:singleLine="true" - android:textAlignment="viewEnd" - android:textAppearance="@style/Body1" - android:textColor="?android:attr/textColorSecondary" /> + style="@style/FileItemLabelStyle"/> </LinearLayout> <FrameLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content"> - - <FrameLayout - android:id="@+id/preview_icon" - android:layout_width="@dimen/list_item_width" - android:layout_height="@dimen/list_item_height" - android:padding="@dimen/list_item_icon_padding" - android:focusable="true"> - - <ImageView - android:layout_width="@dimen/check_icon_size" - android:layout_height="@dimen/check_icon_size" - android:layout_gravity="center" - android:scaleType="fitCenter" - android:tint="?android:attr/textColorPrimary" - android:src="@drawable/ic_zoom_out"/> - - </FrameLayout> - - <android.widget.Space - android:layout_width="@dimen/list_item_width" - android:layout_height="@dimen/list_item_height"/> + android:id="@+id/preview_icon" + android:layout_width="@dimen/list_item_icon_size" + android:layout_height="@dimen/list_item_icon_size" + android:layout_marginEnd="@dimen/list_item_icon_margin_end" + android:focusable="true"> + + <ImageView + android:layout_width="@dimen/check_icon_size" + android:layout_height="@dimen/check_icon_size" + android:layout_gravity="center" + android:scaleType="fitCenter" + android:tint="@color/doc_list_item_badge_icon_color" + android:src="@drawable/ic_zoom_out"/> </FrameLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_directory.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_directory.xml index f424e407d..a7ee033f1 100644 --- a/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_directory.xml +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_directory.xml @@ -21,13 +21,13 @@ android:layout_height="match_parent" android:orientation="vertical"> - <ProgressBar + <com.google.android.material.progressindicator.LinearProgressIndicator android:id="@+id/progressbar" android:layout_width="match_parent" - android:layout_height="@dimen/progress_bar_height" + android:layout_height="wrap_content" android:indeterminate="true" - style="@style/TrimmedHorizontalProgressBar" - android:visibility="gone"/> + app:trackColor="?attr/colorSecondaryContainer" + android:visibility="gone" /> <com.android.documentsui.dirlist.DocumentsSwipeRefreshLayout android:id="@+id/refresh_layout" diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_nav_rail_roots.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_nav_rail_roots.xml new file mode 100644 index 000000000..7848dea0b --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_nav_rail_roots.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<com.android.documentsui.sidebar.RootsList xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/roots_list" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:keyboardNavigationCluster="true" + android:divider="@null" + android:focusable="false" + android:descendantFocusability="afterDescendants" + style="@style/NavRailStyle"/> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_list.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_list.xml index 055c1b203..63b792c59 100644 --- a/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_list.xml +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_list.xml @@ -20,7 +20,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/list_item_background" - android:foreground="?android:attr/selectableItemBackground" android:clickable="true" android:focusable="true" android:orientation="vertical"> @@ -31,23 +30,24 @@ android:baselineAligned="false" android:gravity="center_vertical" android:minHeight="@dimen/list_item_height" - android:orientation="horizontal"> + android:orientation="horizontal" + android:paddingStart="@dimen/list_item_padding_start" + android:paddingEnd="@dimen/list_item_padding_end" + android:paddingVertical="@dimen/list_item_padding_vertical"> <FrameLayout android:id="@+id/icon" android:pointerIcon="hand" - android:layout_width="@dimen/list_item_width" - android:layout_height="@dimen/list_item_height" - android:paddingBottom="@dimen/list_item_icon_padding" - android:paddingTop="@dimen/list_item_icon_padding" - android:paddingEnd="16dp" - android:paddingStart="@dimen/list_item_padding"> + android:layout_width="@dimen/list_item_icon_size" + android:layout_height="@dimen/list_item_icon_size" + android:layout_marginEnd="@dimen/list_item_icon_margin_end"> <com.google.android.material.card.MaterialCardView android:layout_width="match_parent" android:layout_height="match_parent" app:cardBackgroundColor="@android:color/transparent" - app:cardElevation="0dp"> + app:cardElevation="0dp" + app:strokeWidth="0dp"> <ImageView android:id="@+id/icon_mime" @@ -84,7 +84,7 @@ android:layout_weight="1" android:orientation="vertical" android:layout_gravity="center_vertical" - android:layout_marginEnd="@dimen/list_item_padding"> + android:layout_marginEnd="@dimen/list_item_icon_size"> <LinearLayout android:layout_width="wrap_content" @@ -98,7 +98,7 @@ android:layout_marginEnd="@dimen/briefcase_icon_margin" android:layout_gravity="center_vertical" android:src="@drawable/ic_briefcase" - android:tint="?android:attr/colorAccent" + android:tint="@color/doc_list_item_badge_icon_color" android:contentDescription="@string/a11y_work" /> <TextView @@ -108,7 +108,7 @@ android:ellipsize="end" android:singleLine="true" android:textAlignment="viewStart" - android:textAppearance="?android:attr/textAppearanceListItem" /> + android:textAppearance="@style/FileItemLabelText" /> </LinearLayout> @@ -117,7 +117,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:baselineAligned="false" - android:layout_marginTop="4dp" android:gravity="center_vertical" android:orientation="horizontal"> @@ -135,9 +134,8 @@ <FrameLayout android:id="@+id/preview_icon" - android:layout_width="@dimen/list_item_width" - android:layout_height="@dimen/list_item_height" - android:padding="@dimen/list_item_icon_padding" + android:layout_width="@dimen/list_item_icon_size" + android:layout_height="@dimen/list_item_icon_size" android:focusable="true" android:clickable="true"> @@ -146,18 +144,11 @@ android:layout_height="@dimen/check_icon_size" android:layout_gravity="center" android:scaleType="fitCenter" - android:tint="?android:attr/colorControlNormal" + android:tint="@color/doc_list_item_badge_icon_color" android:src="@drawable/ic_zoom_out" /> </FrameLayout> </LinearLayout> - <View - android:layout_width="match_parent" - android:layout_height="1dp" - android:layout_marginStart="72dp" - android:layout_marginEnd="8dp" - android:background="?android:strokeColor" /> - </LinearLayout>
\ No newline at end of file diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/nav_rail_item_root.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/nav_rail_item_root.xml new file mode 100644 index 000000000..461027c73 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/nav_rail_item_root.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<com.android.documentsui.sidebar.RootItemView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="@dimen/nav_rail_item_height" + android:gravity="center_horizontal" + android:orientation="vertical" + android:baselineAligned="false" + android:clickable="true" + android:focusable="true" + style="@style/NavRailItemStyle"> + + <LinearLayout + android:layout_width="@dimen/nav_rail_item_icon_bg_width" + android:layout_height="@dimen/nav_rail_item_icon_bg_height" + android:gravity="center" + android:duplicateParentState="true" + android:background="@drawable/nav_rail_item_icon_background"> + + <ImageView + android:id="@android:id/icon" + android:layout_width="@dimen/root_icon_size" + android:layout_height="@dimen/root_icon_size" + android:scaleType="centerInside" + android:contentDescription="@null" /> + + </LinearLayout> + + <TextView + android:id="@android:id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:singleLine="true" + android:ellipsize="end" + android:textAlignment="center" + android:duplicateParentState="true" + style="@style/NavRailItemTextStyle" /> + +</com.android.documentsui.sidebar.RootItemView> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/layout/nav_rail_layout.xml b/res/flag(com.android.documentsui.flags.use_material3)/layout/nav_rail_layout.xml new file mode 100644 index 000000000..5d753f336 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/layout/nav_rail_layout.xml @@ -0,0 +1,129 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- CoordinatorLayout is necessary for various components (e.g. Snackbars, and + floating action buttons) to operate correctly. --> +<androidx.coordinatorlayout.widget.CoordinatorLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:id="@+id/coordinator_layout"> + + <androidx.drawerlayout.widget.DrawerLayout + android:id="@+id/drawer_layout" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <!-- Main section --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="horizontal" + android:baselineAligned="false" + android:paddingTop="@dimen/layout_padding_top" + android:paddingBottom="@dimen/layout_padding_bottom" + android:paddingEnd="@dimen/layout_padding_end" + android:background="?attr/colorSurfaceContainer"> + + <!-- Navigation rail: left hand side. --> + <FrameLayout + android:id="@+id/nav_rail_container_roots" + android:layout_width="144dp" + android:layout_height="match_parent" + /> + + <!-- Main container for the right hand side. --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:background="@drawable/main_container_background" + android:paddingTop="@dimen/main_container_padding_top"> + + <com.google.android.material.appbar.MaterialToolbar + android:id="@+id/toolbar" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + android:layout_marginTop="@dimen/action_bar_margin" + android:touchscreenBlocksFocus="false"> + + <TextView + android:id="@+id/searchbar_title" + android:layout_width="match_parent" + android:layout_height="?android:attr/actionBarSize" + android:gravity="center_vertical" + android:text="@string/search_bar_hint" + android:textAppearance="@style/SearchBarTitle" /> + + </com.google.android.material.appbar.MaterialToolbar> + + <include layout="@layout/directory_header" /> + + <!-- Main list area (file list/grid or search results). --> + <FrameLayout + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1"> + + <FrameLayout + android:id="@+id/container_directory" + android:clipToPadding="false" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + <FrameLayout + android:id="@+id/container_search_fragment" + android:clipToPadding="false" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + </FrameLayout> + + <!-- Footer of right hand side: Breadcrumbs and Picker footer. --> + <com.android.documentsui.HorizontalBreadcrumb + android:id="@+id/horizontal_breadcrumb" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + <androidx.coordinatorlayout.widget.CoordinatorLayout + android:id="@+id/container_save" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?android:attr/colorBackgroundFloating" + android:elevation="8dp" /> + + </LinearLayout> + + </LinearLayout> + + <!-- Drawer section --> + <LinearLayout + android:id="@+id/drawer_roots" + android:layout_width="256dp" + android:layout_height="match_parent" + android:layout_gravity="start" + android:orientation="vertical"> + + <FrameLayout + android:id="@+id/container_roots" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" /> + + </LinearLayout> + + </androidx.drawerlayout.widget.DrawerLayout> +</androidx.coordinatorlayout.widget.CoordinatorLayout> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values-night/colors.xml b/res/flag(com.android.documentsui.flags.use_material3)/values-night/colors.xml index 70c7cfd34..6ffe52622 100644 --- a/res/flag(com.android.documentsui.flags.use_material3)/values-night/colors.xml +++ b/res/flag(com.android.documentsui.flags.use_material3)/values-night/colors.xml @@ -18,7 +18,6 @@ <color name="background_floating">#3C4043</color> <color name="nav_bar_translucent">#52000000</color> - <color name="primary">#8AB4F8</color> <color name="secondary">#3D8AB4F8</color> <color name="hairline">#5F6368</color> @@ -27,12 +26,7 @@ <color name="edge_effect">@android:color/white</color> - <!-- AppCompat.textColorSecondary --> - <color name="doc_list_item_subtitle_enabled">#b3ffffff</color> - <color name="doc_list_item_subtitle_disabled">#36ffffff</color> - <color name="list_divider_color">#9aa0a6</color> - <color name="list_item_selected_background_color">?android:colorSecondary</color> <color name="color_surface_header">@color/m3_ref_palette_dynamic_neutral_variant17</color> 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 d3789a993..2781026e9 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 @@ -23,6 +23,8 @@ we zero here, to avoid pushing the title further. --> <dimen name="search_bar_text_margin_start">0dp</dimen> - <dimen name="toolbar_padding_start">@dimen/main_container_padding_start</dimen> + <dimen name="toolbar_padding_start">@dimen/space_small_3</dimen> + + <dimen name="list_container_padding">@dimen/space_extra_small_6</dimen> </resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values-w600dp/layouts.xml b/res/flag(com.android.documentsui.flags.use_material3)/values-w600dp/layouts.xml new file mode 100644 index 000000000..4b0634d54 --- /dev/null +++ b/res/flag(com.android.documentsui.flags.use_material3)/values-w600dp/layouts.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <item name="documents_activity" type="layout">@layout/nav_rail_layout</item> + <item name="files_activity" type="layout">@layout/nav_rail_layout</item> +</resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values-w900dp/dimens.xml b/res/flag(com.android.documentsui.flags.use_material3)/values-w900dp/dimens.xml index 6915dd955..d37f3af68 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 @@ -18,8 +18,10 @@ <dimen name="grid_padding_horiz">16dp</dimen> <dimen name="grid_padding_vert">16dp</dimen> - <dimen name="list_item_padding">24dp</dimen> - <dimen name="list_item_width">80dp</dimen> + <dimen name="list_item_height">48dp</dimen> + <dimen name="list_item_padding_start">20dp</dimen> + <dimen name="list_item_padding_end">0dp</dimen> + <dimen name="list_item_icon_margin_end">@dimen/space_extra_small_4</dimen> <dimen name="max_drawer_width">320dp</dimen> @@ -30,6 +32,7 @@ <dimen name="main_container_padding_top">@dimen/space_extra_small_6</dimen> + <dimen name="toolbar_padding_start">@dimen/main_container_padding_start</dimen> <dimen name="toolbar_padding_end">@dimen/space_small_3</dimen> <dimen name="drawer_padding_top">@dimen/space_small_1</dimen> 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 c3155d5ee..c7ac0124b 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 @@ -22,7 +22,7 @@ <color name="background_floating">@android:color/white</color> <color name="nav_bar_translucent">#99FFFFFF</color> - <color name="primary">#1E88E5</color> <!-- Blue 600 --> + <color name="primary">?attr/colorPrimary</color> <color name="secondary">#E3F2FD</color> <!-- Blue 50 --> <color name="hairline">#E0E0E0</color> <!-- Gray 300 --> @@ -49,13 +49,8 @@ <color name="edge_effect">@android:color/black</color> - <color name="doc_list_item_subtitle_enabled">#5F6368</color> <!-- Gray 700 --> - <color name="doc_list_item_subtitle_disabled">#613c4043 - </color> <!-- 38% Grey800 --> - <color name="list_divider_color">#1f000000</color> - <color name="list_item_selected_background_color">?android:colorSecondary - </color> + <color name="list_item_selected_background_color">?attr/colorPrimary</color> <!-- This is used when the app bar is in pinned mode inside the CollapsingToolbarLayout. The code in NavigationViewManager assume the value should be a plain color value so we can't use the theme attribute "?attr/colorSurfaceContainerHigh" (which is a reference) here, hence @@ -74,11 +69,11 @@ <color name="search_chip_text_selected_color">@android:color/white</color> <!-- Use this when we need to set alpha channel on top of a theme attribute color in the - color selector list, e.g. to set colorOnSecondaryContainer with 10% alpha channel, use: + color selector list, e.g. to set colorOnSecondaryContainer with a hover overlay alpha, use: <shape android:tint="?attr/colorOnSecondaryContainer"> - <solid android:color="@color/overlay_color_percentage_10"/> + <solid android:color="@color/overlay_hover_color_percentage"/> </shape> --> - <color name="overlay_color_percentage_10">#1A000000</color> + <color name="overlay_hover_color_percentage">#14000000</color> <!-- 8% --> </resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values/dimens.xml b/res/flag(com.android.documentsui.flags.use_material3)/values/dimens.xml index 8cefd0eab..7487421e5 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 @@ -22,7 +22,7 @@ <dimen name="tab_selector_indicator_height">2dp</dimen> <dimen name="profile_tab_padding">0dp</dimen> <dimen name="grid_container_padding">20dp</dimen> - <dimen name="list_container_padding">20dp</dimen> + <dimen name="list_container_padding">@dimen/space_extra_small_4</dimen> <dimen name="icon_size">40dp</dimen> <dimen name="button_touch_size">48dp</dimen> <dimen name="root_icon_size">24dp</dimen> @@ -33,10 +33,11 @@ <dimen name="root_action_icon_size">24dp</dimen> <!-- TODO(b/379776735): remove this after M3 uplift --> <dimen name="root_icon_disabled_alpha">?android:attr/disabledAlpha</dimen> - <dimen name="check_icon_size">30dp</dimen> + <dimen name="check_icon_size">20dp</dimen> <dimen name="zoom_icon_size">24dp</dimen> <dimen name="list_item_thumbnail_size">40dp</dimen> <dimen name="grid_item_icon_size">30dp</dimen> + <!-- TODO(b/379776735): remove this after M3 uplift --> <dimen name="progress_bar_height">4dp</dimen> <fraction name="grid_scale_min">85%</fraction> <fraction name="grid_scale_max">200%</fraction> @@ -45,13 +46,20 @@ <dimen name="grid_item_margin">6dp</dimen> <dimen name="grid_padding_horiz">4dp</dimen> <dimen name="grid_padding_vert">4dp</dimen> + <dimen name="list_item_height">56dp</dimen> + <dimen name="list_item_padding_start">16dp</dimen> + <dimen name="list_item_padding_end">8dp</dimen> + <dimen name="list_item_padding_vertical">4dp</dimen> + <dimen name="list_item_icon_margin_end">16dp</dimen> + <dimen name="list_item_icon_size">32dp</dimen> + <!-- TODO(b/379776735): remove this block after M3 uplift --> <dimen name="list_item_width">72dp</dimen> - <dimen name="list_item_height">72dp</dimen> <dimen name="list_item_padding">16dp</dimen> <dimen name="list_item_icon_padding">16dp</dimen> + <dimen name="list_divider_inset">72dp</dimen> + <!-- block end --> <dimen name="breadcrumb_item_padding">8dp</dimen> <dimen name="breadcrumb_item_height">36dp</dimen> - <dimen name="list_divider_inset">72dp</dimen> <dimen name="dir_elevation">8dp</dimen> <dimen name="drag_shadow_size">120dp</dimen> <dimen name="grid_item_elevation">2dp</dimen> @@ -73,6 +81,11 @@ <dimen name="drawer_item_text_margin_start">12dp</dimen> <dimen name="drawer_item_action_icon_margin_start">4dp</dimen> + <dimen name="nav_rail_item_height">64dp</dimen> + <dimen name="nav_rail_item_icon_bg_radius">16dp</dimen> + <dimen name="nav_rail_item_icon_bg_width">56dp</dimen> + <dimen name="nav_rail_item_icon_bg_height">32dp</dimen> + <dimen name="drag_shadow_width">176dp</dimen> <dimen name="drag_shadow_height">64dp</dimen> <dimen name="drag_shadow_radius">4dp</dimen> @@ -166,6 +179,7 @@ <dimen name="cross_profile_button_message_margin_top">4dp</dimen> <dimen name="focus_ring_width">3dp</dimen> - <dimen name="hover_overlay_alpha">0.10</dimen> - <dimen name="ripple_overlay_alpha">0.08</dimen> + <dimen name="focus_ring_gap">5dp</dimen> + <dimen name="hover_overlay_alpha">0.08</dimen> + <dimen name="ripple_overlay_alpha">0.10</dimen> </resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values/styles.xml b/res/flag(com.android.documentsui.flags.use_material3)/values/styles.xml index ffc83f6dc..5fde94ab8 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 @@ -55,12 +55,6 @@ <item name="cardElevation">@dimen/grid_item_elevation</item> </style> - <style name="TrimmedHorizontalProgressBar" parent="android:Widget.Material.ProgressBar.Horizontal"> - <item name="android:indeterminateDrawable">@drawable/progress_indeterminate_horizontal_material_trimmed</item> - <item name="android:minHeight">3dp</item> - <item name="android:maxHeight">3dp</item> - </style> - <style name="SnackbarButtonStyle" parent="@style/Widget.AppCompat.Button.Borderless"> <item name="android:textColor">?android:colorPrimary</item> </style> @@ -163,4 +157,33 @@ <item name="tabSelectedTextColor">?attr/colorOnPrimaryContainer</item> <item name="tabTextAppearance">@style/TabTextAppearance</item> </style> + + <style name="FileItemLabelStyle" parent=""> + <item name="android:layout_marginStart">32dp</item> + <item name="android:ellipsize">end</item> + <item name="android:minWidth">70dp</item> + <item name="android:singleLine">true</item> + <item name="android:textAlignment">viewStart</item> + <item name="android:textAppearance">@style/FileItemLabelText</item> + </style> + + <style name="NavRailStyle" parent=""> + <item name="android:background">?attr/colorSurfaceContainer</item> + <item name="android:paddingHorizontal">@dimen/space_small_3</item> + <item name="android:paddingTop">@dimen/space_extra_small_6</item> + <item name="android:paddingBottom">@dimen/space_small_1</item> + <item name="android:scrollbarStyle">outsideOverlay</item> + <item name="android:clipToPadding">false</item> + </style> + + <style name="NavRailItemStyle" parent=""> + <item name="android:background">@drawable/nav_rail_item_background</item> + <item name="android:paddingVertical">6dp</item> + </style> + + <style name="NavRailItemTextStyle" parent=""> + <item name="android:layout_marginTop">4dp</item> + <item name="android:textColor">@color/nav_rail_item_text_color</item> + <item name="android:textAppearance">@style/NavRailItemTextAppearance</item> + </style> </resources> diff --git a/res/flag(com.android.documentsui.flags.use_material3)/values/styles_text.xml b/res/flag(com.android.documentsui.flags.use_material3)/values/styles_text.xml index bbf25a469..717295315 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 @@ -123,7 +123,12 @@ <item name="fontFamily">@string/config_fontFamilyMedium</item> </style> - <style name="ItemCaptionText" parent="@style/TextAppearance.Material3.BodySmall"> + <style name="FileItemLabelText" parent="@style/TextAppearance.Material3.TitleSmall"> + <item name="android:textColor">@color/doc_list_item_label_color</item> + <item name="fontFamily">@string/config_fontFamily</item> + </style> + + <style name="ItemCaptionText" parent="@style/TextAppearance.Material3.LabelSmall"> <item name="android:textColor">@color/doc_list_item_subtitle_color</item> <item name="fontFamily">@string/config_fontFamily</item> </style> @@ -137,7 +142,7 @@ <item name="fontFamily">@string/config_fontFamily</item> </style> - <style name="Body1" parent="@style/TextAppearance.Material3.BodyMedium"> + <style name="NavRailItemTextAppearance" parent="@style/TextAppearance.Material3.LabelMedium"> <item name="fontFamily">@string/config_fontFamily</item> </style> diff --git a/src/com/android/documentsui/AbstractActionHandler.java b/src/com/android/documentsui/AbstractActionHandler.java index 5a8702366..8e1a51301 100644 --- a/src/com/android/documentsui/AbstractActionHandler.java +++ b/src/com/android/documentsui/AbstractActionHandler.java @@ -261,6 +261,11 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA } @Override + public void openDocumentViewOnly(DocumentInfo doc) { + throw new UnsupportedOperationException("Open doc not supported!"); + } + + @Override public void showInspector(DocumentInfo doc) { throw new UnsupportedOperationException("Can't open properties."); } diff --git a/src/com/android/documentsui/ActionHandler.java b/src/com/android/documentsui/ActionHandler.java index 15124eb33..c66a7e78c 100644 --- a/src/com/android/documentsui/ActionHandler.java +++ b/src/com/android/documentsui/ActionHandler.java @@ -129,6 +129,12 @@ public interface ActionHandler { boolean openItem(ItemDetails<String> doc, @ViewType int type, @ViewType int fallback); /** + * Similar to openItem but takes DocumentInfo instead of DocumentItemDetails and uses + * VIEW_TYPE_VIEW with no fallback. + */ + void openDocumentViewOnly(DocumentInfo doc); + + /** * This is called when user hovers over a doc for enough time during a drag n' drop, to open a * folder that accepts drop. We should only open a container that's not an archive, since archives * do not accept dropping. diff --git a/src/com/android/documentsui/BaseActivity.java b/src/com/android/documentsui/BaseActivity.java index fe81fbf16..4c25b3608 100644 --- a/src/com/android/documentsui/BaseActivity.java +++ b/src/com/android/documentsui/BaseActivity.java @@ -358,6 +358,14 @@ public abstract class BaseActivity if (roots != null) { roots.onSelectedUserChanged(); } + if (useMaterial3()) { + final RootsFragment navRailRoots = + RootsFragment.getNavRail(getSupportFragmentManager()); + if (navRailRoots != null) { + navRailRoots.onSelectedUserChanged(); + } + } + if (mState.stack.size() <= 1) { // We do not load cross-profile root if the stack contains two documents. The @@ -690,6 +698,13 @@ public abstract class BaseActivity if (roots != null) { roots.onCurrentRootChanged(); } + if (useMaterial3()) { + final RootsFragment navRailRoots = + RootsFragment.getNavRail(getSupportFragmentManager()); + if (navRailRoots != null) { + navRailRoots.onCurrentRootChanged(); + } + } String appName = getString(R.string.files_label); String currentTitle = getTitle() != null ? getTitle().toString() : ""; diff --git a/src/com/android/documentsui/DrawerController.java b/src/com/android/documentsui/DrawerController.java index a988635fd..88c41b3f2 100644 --- a/src/com/android/documentsui/DrawerController.java +++ b/src/com/android/documentsui/DrawerController.java @@ -127,7 +127,10 @@ public abstract class DrawerController implements DrawerListener { if (activityConfig.dragAndDropEnabled()) { View edge = layout.findViewById(R.id.drawer_edge); - edge.setOnDragListener(new ItemDragListener<>(this, SPRING_TIMEOUT)); + // nav_rail_layout also uses DrawerLayout, but it doesn't have drawer edge. + if (edge != null) { + edge.setOnDragListener(new ItemDragListener<>(this, SPRING_TIMEOUT)); + } } } diff --git a/src/com/android/documentsui/MenuManager.java b/src/com/android/documentsui/MenuManager.java index 78339862b..2d1e2a59a 100644 --- a/src/com/android/documentsui/MenuManager.java +++ b/src/com/android/documentsui/MenuManager.java @@ -427,7 +427,7 @@ public abstract class MenuManager { boolean canExtract(); - boolean canOpenWith(); + boolean canOpen(); boolean canViewInOwner(); } diff --git a/src/com/android/documentsui/dirlist/DirectoryFragment.java b/src/com/android/documentsui/dirlist/DirectoryFragment.java index 165599f71..43fc91e3a 100644 --- a/src/com/android/documentsui/dirlist/DirectoryFragment.java +++ b/src/com/android/documentsui/dirlist/DirectoryFragment.java @@ -21,6 +21,7 @@ import static com.android.documentsui.base.SharedMinimal.DEBUG; import static com.android.documentsui.base.SharedMinimal.VERBOSE; import static com.android.documentsui.base.State.MODE_GRID; import static com.android.documentsui.base.State.MODE_LIST; +import static com.android.documentsui.flags.Flags.desktopFileHandling; import android.app.ActivityManager; import android.content.BroadcastReceiver; @@ -924,7 +925,17 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On mSelectionMgr.copySelection(selection); final int id = item.getItemId(); - if (id == R.id.action_menu_select || id == R.id.dir_menu_open) { + if (desktopFileHandling() && id == R.id.dir_menu_open) { + // On desktop, "open" is displayed in file management mode (i.e. `files.MenuManager`). + // This menu item behaves the same as double click on the menu item which is handled by + // onItemActivated but since onItemActivated requires a RecylcerView ItemDetails, we're + // using viewDocument that takes a Selection. + viewDocument(selection); + return true; + } else if (id == R.id.action_menu_select || id == R.id.dir_menu_open) { + // Note: this code path is never executed for `dir_menu_open`. The menu item is always + // hidden unless the desktopFileHandling flag is enabled, in which case the menu item + // will be handled by the condition above. openDocuments(selection); mActionModeController.finishActionMode(); return true; @@ -1082,6 +1093,20 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On mActions.showChooserForDoc(doc); } + private void viewDocument(final Selection<String> selected) { + Metrics.logUserAction(MetricConsts.USER_ACTION_OPEN); + + if (selected.isEmpty()) { + return; + } + + assert selected.size() == 1; + DocumentInfo doc = + DocumentInfo.fromDirectoryCursor(mModel.getItem(selected.iterator().next())); + + mActions.openDocumentViewOnly(doc); + } + private void transferDocuments( final Selection<String> selected, @Nullable DocumentStack destination, final @OpType int mode) { diff --git a/src/com/android/documentsui/dirlist/DocumentHolder.java b/src/com/android/documentsui/dirlist/DocumentHolder.java index 26f527896..69058fb5a 100644 --- a/src/com/android/documentsui/dirlist/DocumentHolder.java +++ b/src/com/android/documentsui/dirlist/DocumentHolder.java @@ -18,6 +18,7 @@ package com.android.documentsui.dirlist; import static com.android.documentsui.DevicePolicyResources.Strings.PREVIEW_WORK_FILE_ACCESSIBILITY; import static com.android.documentsui.DevicePolicyResources.Strings.UNDEFINED; +import static com.android.documentsui.flags.Flags.useMaterial3; import android.app.admin.DevicePolicyManager; import android.content.Context; @@ -55,7 +56,7 @@ import javax.annotation.Nullable; public abstract class DocumentHolder extends RecyclerView.ViewHolder implements View.OnKeyListener { - static final float DISABLED_ALPHA = 0.3f; + static final float DISABLED_ALPHA = useMaterial3() ? 0.6f : 0.3f; protected final Context mContext; diff --git a/src/com/android/documentsui/dirlist/DocumentsSwipeRefreshLayout.java b/src/com/android/documentsui/dirlist/DocumentsSwipeRefreshLayout.java index 4b66b857f..92faee198 100644 --- a/src/com/android/documentsui/dirlist/DocumentsSwipeRefreshLayout.java +++ b/src/com/android/documentsui/dirlist/DocumentsSwipeRefreshLayout.java @@ -16,10 +16,13 @@ package com.android.documentsui.dirlist; +import static com.android.documentsui.flags.Flags.useMaterial3; + import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.util.Log; +import android.util.TypedValue; import android.view.MotionEvent; import androidx.annotation.ColorRes; @@ -42,20 +45,37 @@ public class DocumentsSwipeRefreshLayout extends SwipeRefreshLayout { public DocumentsSwipeRefreshLayout(Context context, AttributeSet attrs) { super(context, attrs); - final int[] styledAttrs = {android.R.attr.colorAccent}; + if (useMaterial3()) { + TypedValue spinnerColor = new TypedValue(); + context.getTheme() + .resolveAttribute( + com.google.android.material.R.attr.colorOnPrimaryContainer, + spinnerColor, + true); + setColorSchemeResources(spinnerColor.resourceId); + TypedValue spinnerBackgroundColor = new TypedValue(); + context.getTheme() + .resolveAttribute( + com.google.android.material.R.attr.colorPrimaryContainer, + spinnerBackgroundColor, + true); + setProgressBackgroundColorSchemeResource(spinnerBackgroundColor.resourceId); + } else { + final int[] styledAttrs = {android.R.attr.colorAccent}; - TypedArray a = context.obtainStyledAttributes(styledAttrs); - @ColorRes int colorId = a.getResourceId(0, -1); - if (colorId == -1) { - Log.w(TAG, "Retrieve colorAccent colorId from theme fail, assign R.color.primary"); - colorId = R.color.primary; + TypedArray a = context.obtainStyledAttributes(styledAttrs); + @ColorRes int colorId = a.getResourceId(0, -1); + if (colorId == -1) { + Log.w(TAG, "Retrieve colorAccent colorId from theme fail, assign R.color.primary"); + colorId = R.color.primary; + } + a.recycle(); + setColorSchemeResources(colorId); } - a.recycle(); - setColorSchemeResources(colorId); } @Override public boolean onInterceptTouchEvent(MotionEvent e) { return false; } -}
\ No newline at end of file +} diff --git a/src/com/android/documentsui/dirlist/ListDocumentHolder.java b/src/com/android/documentsui/dirlist/ListDocumentHolder.java index 2c09d3aec..849acb5c1 100644 --- a/src/com/android/documentsui/dirlist/ListDocumentHolder.java +++ b/src/com/android/documentsui/dirlist/ListDocumentHolder.java @@ -20,6 +20,7 @@ import static com.android.documentsui.DevicePolicyResources.Drawables.Style.SOLI import static com.android.documentsui.DevicePolicyResources.Drawables.WORK_PROFILE_ICON; import static com.android.documentsui.base.DocumentInfo.getCursorInt; import static com.android.documentsui.base.DocumentInfo.getCursorString; +import static com.android.documentsui.flags.Flags.useMaterial3; import android.app.admin.DevicePolicyManager; import android.content.Context; @@ -145,10 +146,14 @@ final class ListDocumentHolder extends DocumentHolder { public void setEnabled(boolean enabled) { super.setEnabled(enabled); - // Text colors enabled/disabled is handle via a color set. - final float imgAlpha = enabled ? 1f : DISABLED_ALPHA; - mIconMime.setAlpha(imgAlpha); - mIconThumb.setAlpha(imgAlpha); + if (useMaterial3()) { + itemView.setAlpha(enabled ? 1f : DISABLED_ALPHA); + } else { + // Text colors enabled/disabled is handle via a color set. + final float imgAlpha = enabled ? 1f : DISABLED_ALPHA; + mIconMime.setAlpha(imgAlpha); + mIconThumb.setAlpha(imgAlpha); + } } @Override diff --git a/src/com/android/documentsui/dirlist/SelectionMetadata.java b/src/com/android/documentsui/dirlist/SelectionMetadata.java index 3abc3e190..74b6061b3 100644 --- a/src/com/android/documentsui/dirlist/SelectionMetadata.java +++ b/src/com/android/documentsui/dirlist/SelectionMetadata.java @@ -168,7 +168,7 @@ public class SelectionMetadata extends SelectionObserver<String> } @Override - public boolean canOpenWith() { + public boolean canOpen() { return size() == 1 && mDirectoryCount == 0 && mInArchiveCount == 0 && mPartialCount == 0; } } diff --git a/src/com/android/documentsui/files/ActionHandler.java b/src/com/android/documentsui/files/ActionHandler.java index 20b831856..56eef8737 100644 --- a/src/com/android/documentsui/files/ActionHandler.java +++ b/src/com/android/documentsui/files/ActionHandler.java @@ -19,10 +19,12 @@ package com.android.documentsui.files; import static android.content.ContentResolver.wrap; import static com.android.documentsui.base.SharedMinimal.DEBUG; +import static com.android.documentsui.flags.Flags.desktopFileHandling; import android.app.DownloadManager; import android.content.ActivityNotFoundException; import android.content.ClipData; +import android.content.ComponentName; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.Intent; @@ -221,6 +223,12 @@ public class ActionHandler<T extends FragmentActivity & AbstractActionHandler.Co } @Override + public void openDocumentViewOnly(DocumentInfo doc) { + mInjector.searchManager.recordHistory(); + openDocument(doc, VIEW_TYPE_REGULAR, VIEW_TYPE_NONE); + } + + @Override public void springOpenDirectory(DocumentInfo doc) { assert(doc.isDirectory()); mActionModeAddons.finishActionMode(); @@ -543,12 +551,23 @@ public class ActionHandler<T extends FragmentActivity & AbstractActionHandler.Co return; } - Intent intent = Intent.createChooser(buildViewIntent(doc), null); - intent.putExtra(Intent.EXTRA_AUTO_LAUNCH_SINGLE_CHOICE, false); - try { - doc.userId.startActivityAsUser(mActivity, intent); - } catch (ActivityNotFoundException e) { - mDialogs.showNoApplicationFound(); + if (desktopFileHandling()) { + Intent intent = buildViewIntent(doc); + intent.setComponent( + new ComponentName("android", "com.android.internal.app.ResolverActivity")); + try { + doc.userId.startActivityAsUser(mActivity, intent); + } catch (ActivityNotFoundException e) { + mDialogs.showNoApplicationFound(); + } + } else { + Intent intent = Intent.createChooser(buildViewIntent(doc), null); + intent.putExtra(Intent.EXTRA_AUTO_LAUNCH_SINGLE_CHOICE, false); + try { + doc.userId.startActivityAsUser(mActivity, intent); + } catch (ActivityNotFoundException e) { + mDialogs.showNoApplicationFound(); + } } } diff --git a/src/com/android/documentsui/files/FilesActivity.java b/src/com/android/documentsui/files/FilesActivity.java index 1ebe2374f..1da0d8f2b 100644 --- a/src/com/android/documentsui/files/FilesActivity.java +++ b/src/com/android/documentsui/files/FilesActivity.java @@ -17,6 +17,7 @@ package com.android.documentsui.files; import static com.android.documentsui.OperationDialogFragment.DIALOG_TYPE_UNKNOWN; +import static com.android.documentsui.flags.Flags.useMaterial3; import android.app.ActivityManager.TaskDescription; import android.content.Intent; @@ -181,6 +182,14 @@ public class FilesActivity extends BaseActivity implements AbstractActionHandler RootsFragment.show(getSupportFragmentManager(), /* includeApps= */ false, /* intent= */ null); + if (useMaterial3()) { + View navRailRoots = findViewById(R.id.nav_rail_container_roots); + if (navRailRoots != null) { + // Medium layout, populate navigation rail layout. + RootsFragment.showNavRail(getSupportFragmentManager(), /* includeApps= */ false, + /* intent= */ null); + } + } final Intent intent = getIntent(); diff --git a/src/com/android/documentsui/files/MenuManager.java b/src/com/android/documentsui/files/MenuManager.java index 742bc9739..3e2e00feb 100644 --- a/src/com/android/documentsui/files/MenuManager.java +++ b/src/com/android/documentsui/files/MenuManager.java @@ -16,6 +16,8 @@ package com.android.documentsui.files; +import static com.android.documentsui.flags.Flags.desktopFileHandling; + import android.content.Context; import android.content.res.Resources; import android.net.Uri; @@ -161,7 +163,12 @@ public final class MenuManager extends com.android.documentsui.MenuManager { @Override protected void updateOpenWith(MenuItem openWith, SelectionDetails selectionDetails) { - Menus.setEnabledAndVisible(openWith, selectionDetails.canOpenWith()); + Menus.setEnabledAndVisible(openWith, selectionDetails.canOpen()); + } + + @Override + protected void updateOpenInContextMenu(MenuItem open, SelectionDetails selectionDetails) { + Menus.setEnabledAndVisible(open, desktopFileHandling() && selectionDetails.canOpen()); } @Override diff --git a/src/com/android/documentsui/picker/PickActivity.java b/src/com/android/documentsui/picker/PickActivity.java index e9b91b1a0..481b67e77 100644 --- a/src/com/android/documentsui/picker/PickActivity.java +++ b/src/com/android/documentsui/picker/PickActivity.java @@ -21,6 +21,7 @@ import static com.android.documentsui.base.State.ACTION_GET_CONTENT; import static com.android.documentsui.base.State.ACTION_OPEN; import static com.android.documentsui.base.State.ACTION_OPEN_TREE; import static com.android.documentsui.base.State.ACTION_PICK_COPY_DESTINATION; +import static com.android.documentsui.flags.Flags.useMaterial3; import android.content.Intent; import android.content.res.Resources; @@ -249,6 +250,15 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons { RootsFragment.show(getSupportFragmentManager(), /* includeApps= */ mState.action == ACTION_GET_CONTENT, /* intent= */ moreApps); + if (useMaterial3()) { + View navRailRoots = findViewById(R.id.nav_rail_container_roots); + if (navRailRoots != null) { + // Medium layout, populate navigation rail layout. + RootsFragment.showNavRail(getSupportFragmentManager(), + /* includeApps= */ mState.action == ACTION_GET_CONTENT, + /* intent= */ moreApps); + } + } } } diff --git a/src/com/android/documentsui/sidebar/AppItem.java b/src/com/android/documentsui/sidebar/AppItem.java index b8abf8be9..c719241d2 100644 --- a/src/com/android/documentsui/sidebar/AppItem.java +++ b/src/com/android/documentsui/sidebar/AppItem.java @@ -26,6 +26,8 @@ import android.view.View; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.LayoutRes; + import com.android.documentsui.ActionHandler; import com.android.documentsui.IconUtils; import com.android.documentsui.R; @@ -43,7 +45,16 @@ public class AppItem extends Item { private final ActionHandler mActionHandler; public AppItem(ResolveInfo info, String title, UserId userId, ActionHandler actionHandler) { - super(R.layout.item_root, title, getStringId(info), userId); + this(R.layout.item_root, info, title, userId, actionHandler); + } + + public AppItem( + @LayoutRes int layoutId, + ResolveInfo info, + String title, + UserId userId, + ActionHandler actionHandler) { + super(layoutId, title, getStringId(info), userId); this.info = info; mActionHandler = actionHandler; } diff --git a/src/com/android/documentsui/sidebar/NavRailAppItem.java b/src/com/android/documentsui/sidebar/NavRailAppItem.java new file mode 100644 index 000000000..befddf0aa --- /dev/null +++ b/src/com/android/documentsui/sidebar/NavRailAppItem.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.documentsui.sidebar; + +import android.content.pm.ResolveInfo; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.android.documentsui.ActionHandler; +import com.android.documentsui.R; +import com.android.documentsui.base.UserId; + +/** + * Similar to {@link AppItem} but only used in the navigation rail. + */ +public class NavRailAppItem extends AppItem { + + public NavRailAppItem( + ResolveInfo info, String title, UserId userId, ActionHandler actionHandler) { + super(R.layout.nav_rail_item_root, info, title, userId, actionHandler); + } + + @Override + public void bindView(View convertView) { + final ImageView icon = convertView.findViewById(android.R.id.icon); + final TextView titleView = convertView.findViewById(android.R.id.title); + + titleView.setText(title); + titleView.setContentDescription(userId.getUserBadgedLabel(convertView.getContext(), title)); + + bindIcon(icon); + } +} diff --git a/src/com/android/documentsui/sidebar/NavRailProfileItem.java b/src/com/android/documentsui/sidebar/NavRailProfileItem.java new file mode 100644 index 000000000..fe69c286f --- /dev/null +++ b/src/com/android/documentsui/sidebar/NavRailProfileItem.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.documentsui.sidebar; + +import android.content.pm.ResolveInfo; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.android.documentsui.ActionHandler; +import com.android.documentsui.R; + + +/** + * Similar to {@link ProfileItem} but only used in the navigation rail. + */ +public class NavRailProfileItem extends ProfileItem { + + public NavRailProfileItem(ResolveInfo info, String title, ActionHandler actionHandler) { + super(R.layout.nav_rail_item_root, info, title, actionHandler); + } + + @Override + public void bindView(View convertView) { + final ImageView icon = convertView.findViewById(android.R.id.icon); + final TextView titleView = convertView.findViewById(android.R.id.title); + + titleView.setText(title); + titleView.setContentDescription(userId.getUserBadgedLabel(convertView.getContext(), title)); + + bindIcon(icon); + } +} diff --git a/src/com/android/documentsui/sidebar/NavRailRootAndAppItem.java b/src/com/android/documentsui/sidebar/NavRailRootAndAppItem.java new file mode 100644 index 000000000..1bcc42f5c --- /dev/null +++ b/src/com/android/documentsui/sidebar/NavRailRootAndAppItem.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.documentsui.sidebar; + +import android.content.pm.ResolveInfo; +import android.view.View; + +import com.android.documentsui.ActionHandler; +import com.android.documentsui.R; +import com.android.documentsui.base.RootInfo; + +/** + * Similar to {@link RootAndAppItem} but only used in the navigation rail. + */ +public class NavRailRootAndAppItem extends RootAndAppItem { + + public NavRailRootAndAppItem( + RootInfo root, ResolveInfo info, ActionHandler actionHandler, boolean maybeShowBadge) { + super(R.layout.nav_rail_item_root, root, info, actionHandler, maybeShowBadge); + } + + @Override + public void bindView(View convertView) { + bindIconAndTitle(convertView); + } +} diff --git a/src/com/android/documentsui/sidebar/NavRailRootItem.java b/src/com/android/documentsui/sidebar/NavRailRootItem.java new file mode 100644 index 000000000..3d4042f22 --- /dev/null +++ b/src/com/android/documentsui/sidebar/NavRailRootItem.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.documentsui.sidebar; + + +import android.view.View; + +import com.android.documentsui.ActionHandler; +import com.android.documentsui.R; +import com.android.documentsui.base.RootInfo; + +/** + * Similar to {@link RootItem} but only used in the navigation rail. + */ +public class NavRailRootItem extends RootItem { + + public NavRailRootItem(RootInfo root, ActionHandler actionHandler, boolean maybeShowBadge) { + super( + R.layout.nav_rail_item_root, + root, + actionHandler, + "" /* packageName */, + maybeShowBadge); + } + + public NavRailRootItem( + RootInfo root, + ActionHandler actionHandler, + String packageName, + boolean maybeShowBadge) { + super(R.layout.nav_rail_item_root, root, actionHandler, packageName, maybeShowBadge); + } + + @Override + public void bindView(View convertView) { + bindIconAndTitle(convertView); + } +} diff --git a/src/com/android/documentsui/sidebar/ProfileItem.java b/src/com/android/documentsui/sidebar/ProfileItem.java index 15068ad4b..779f54445 100644 --- a/src/com/android/documentsui/sidebar/ProfileItem.java +++ b/src/com/android/documentsui/sidebar/ProfileItem.java @@ -20,6 +20,8 @@ import android.content.pm.ResolveInfo; import android.view.View; import android.widget.ImageView; +import androidx.annotation.LayoutRes; + import com.android.documentsui.ActionHandler; import com.android.documentsui.base.UserId; @@ -32,6 +34,11 @@ class ProfileItem extends AppItem { super(info, title, UserId.CURRENT_USER, actionHandler); } + ProfileItem( + @LayoutRes int layoutId, ResolveInfo info, String title, ActionHandler actionHandler) { + super(layoutId, info, title, UserId.CURRENT_USER, actionHandler); + } + @Override protected void bindIcon(ImageView icon) { icon.setImageResource(com.android.documentsui.R.drawable.ic_user_profile); diff --git a/src/com/android/documentsui/sidebar/RootAndAppItem.java b/src/com/android/documentsui/sidebar/RootAndAppItem.java index b893878f3..8861f6058 100644 --- a/src/com/android/documentsui/sidebar/RootAndAppItem.java +++ b/src/com/android/documentsui/sidebar/RootAndAppItem.java @@ -18,11 +18,11 @@ package com.android.documentsui.sidebar; import android.content.Context; import android.content.pm.ResolveInfo; -import android.os.UserManager; import android.provider.DocumentsProvider; -import android.text.TextUtils; import android.view.View; +import androidx.annotation.LayoutRes; + import com.android.documentsui.ActionHandler; import com.android.documentsui.R; import com.android.documentsui.base.RootInfo; @@ -36,9 +36,18 @@ class RootAndAppItem extends RootItem { public final ResolveInfo resolveInfo; - public RootAndAppItem(RootInfo root, ResolveInfo info, ActionHandler actionHandler, + RootAndAppItem( + RootInfo root, ResolveInfo info, ActionHandler actionHandler, boolean maybeShowBadge) { + this(R.layout.item_root, root, info, actionHandler, maybeShowBadge); + } + + RootAndAppItem( + @LayoutRes int layoutId, + RootInfo root, + ResolveInfo info, + ActionHandler actionHandler, boolean maybeShowBadge) { - super(root, actionHandler, info.activityInfo.packageName, maybeShowBadge); + super(layoutId, root, actionHandler, info.activityInfo.packageName, maybeShowBadge); this.resolveInfo = info; } diff --git a/src/com/android/documentsui/sidebar/RootItem.java b/src/com/android/documentsui/sidebar/RootItem.java index 4b40d91b3..326f086e1 100644 --- a/src/com/android/documentsui/sidebar/RootItem.java +++ b/src/com/android/documentsui/sidebar/RootItem.java @@ -30,6 +30,7 @@ import android.view.View; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.LayoutRes; import androidx.annotation.Nullable; import com.android.documentsui.ActionHandler; @@ -64,7 +65,16 @@ public class RootItem extends Item { public RootItem(RootInfo root, ActionHandler actionHandler, String packageName, boolean maybeShowBadge) { - super(R.layout.item_root, root.title, getStringId(root), root.userId); + this(R.layout.item_root, root, actionHandler, packageName, maybeShowBadge); + } + + public RootItem( + @LayoutRes int layoutId, + RootInfo root, + ActionHandler actionHandler, + String packageName, + boolean maybeShowBadge) { + super(layoutId, root.title, getStringId(root), root.userId); this.root = root; mActionHandler = actionHandler; mPackageName = packageName; diff --git a/src/com/android/documentsui/sidebar/RootsFragment.java b/src/com/android/documentsui/sidebar/RootsFragment.java index 76df696ab..2ec4c1728 100644 --- a/src/com/android/documentsui/sidebar/RootsFragment.java +++ b/src/com/android/documentsui/sidebar/RootsFragment.java @@ -19,6 +19,7 @@ package com.android.documentsui.sidebar; import static com.android.documentsui.base.Shared.compareToIgnoreCaseNullable; import static com.android.documentsui.base.SharedMinimal.DEBUG; import static com.android.documentsui.base.SharedMinimal.VERBOSE; +import static com.android.documentsui.flags.Flags.useMaterial3; import android.app.admin.DevicePolicyManager; import android.content.Context; @@ -49,6 +50,7 @@ import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.ListView; +import androidx.annotation.IdRes; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.annotation.VisibleForTesting; @@ -96,12 +98,23 @@ import java.util.stream.Collectors; /** * Display list of known storage backend roots. + * This fragment will be used in: + * * fixed_layout: as navigation tree (sidebar) + * * drawer_layout: as navigation drawer + * * nav_rail_layout: as navigation drawer and navigation rail. */ public class RootsFragment extends Fragment { private static final String TAG = "RootsFragment"; private static final String EXTRA_INCLUDE_APPS = "includeApps"; private static final String EXTRA_INCLUDE_APPS_INTENT = "includeAppsIntent"; + /** + * A key used to store the container id in the RootFragment. + * RootFragment is used in both navigation drawer and navigation rail, there are 2 instances + * of the fragment rendered on the page, we need to know which one is which to render different + * nav items inside. + */ + private static final String EXTRA_CONTAINER_ID = "containerId"; private static final int CONTEXT_MENU_ITEM_TIMEOUT = 500; private final OnItemClickListener mItemListener = new OnItemClickListener() { @@ -135,41 +148,88 @@ public class RootsFragment extends Fragment { private List<Item> mApplicationItemList; + // Weather the fragment is using nav_rail_container_roots as its container (in nav_rail_layout). + // This will always be false if useMaterial3() flag is off. + private boolean mUseRailAsContainer = false; + + /** + * Show the RootsFragment inside the navigation drawer container. + */ + public static RootsFragment show(FragmentManager fm, boolean includeApps, Intent intent) { + return showWithLayout(R.id.container_roots, fm, includeApps, intent); + } + + /** + * Show the RootsFragment inside the navigation rail container. + */ + public static RootsFragment showNavRail(FragmentManager fm, boolean includeApps, + Intent intent) { + return showWithLayout(R.id.nav_rail_container_roots, fm, includeApps, intent); + } + /** * Shows the {@link RootsFragment}. * + * @param containerId the container id where the {@link RootsFragment} will be rendered into * @param fm the FragmentManager for interacting with fragments associated with this * fragment's activity * @param includeApps if {@code true}, query the intent from the system and include apps in * the {@RootsFragment}. * @param intent the intent to query for package manager */ - public static RootsFragment show(FragmentManager fm, boolean includeApps, Intent intent) { + private static RootsFragment showWithLayout( + @IdRes int containerId, FragmentManager fm, boolean includeApps, Intent intent) { final Bundle args = new Bundle(); args.putBoolean(EXTRA_INCLUDE_APPS, includeApps); args.putParcelable(EXTRA_INCLUDE_APPS_INTENT, intent); + if (useMaterial3()) { + args.putInt(EXTRA_CONTAINER_ID, containerId); + } final RootsFragment fragment = new RootsFragment(); fragment.setArguments(args); final FragmentTransaction ft = fm.beginTransaction(); - ft.replace(R.id.container_roots, fragment); + ft.replace(containerId, fragment); ft.commitAllowingStateLoss(); return fragment; } + /** + * Get the RootsFragment instance for the navigation drawer. + */ public static RootsFragment get(FragmentManager fm) { return (RootsFragment) fm.findFragmentById(R.id.container_roots); } + /** + * Get the RootsFragment instance for the navigation drawer. + */ + public static RootsFragment getNavRail(FragmentManager fm) { + return (RootsFragment) fm.findFragmentById(R.id.nav_rail_container_roots); + } + @Override public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + if (useMaterial3()) { + mUseRailAsContainer = + getArguments() != null + && getArguments().getInt(EXTRA_CONTAINER_ID) + == R.id.nav_rail_container_roots; + } + mInjector = getBaseActivity().getInjector(); - final View view = inflater.inflate(R.layout.fragment_roots, container, false); + final View view = + inflater.inflate( + mUseRailAsContainer + ? R.layout.fragment_nav_rail_roots + : R.layout.fragment_roots, + container, + false); mList = (ListView) view.findViewById(R.id.roots_list); mList.setOnItemClickListener(mItemListener); // ListView does not have right-click specific listeners, so we will have a @@ -312,10 +372,17 @@ public class RootsFragment extends Fragment { if (crossProfileResolveInfo != null && !Features.CROSS_PROFILE_TABS) { // Add profile item if we don't support cross-profile tab. sortedItems.add(new SpacerItem()); - sortedItems.add(new ProfileItem(crossProfileResolveInfo, - crossProfileResolveInfo.loadLabel( - getContext().getPackageManager()).toString(), - mActionHandler)); + if (mUseRailAsContainer) { + sortedItems.add(new NavRailProfileItem(crossProfileResolveInfo, + crossProfileResolveInfo.loadLabel( + getContext().getPackageManager()).toString(), + mActionHandler)); + } else { + sortedItems.add(new ProfileItem(crossProfileResolveInfo, + crossProfileResolveInfo.loadLabel( + getContext().getPackageManager()).toString(), + mActionHandler)); + } } // Disable drawer if only one root @@ -414,15 +481,30 @@ public class RootsFragment extends Fragment { if (root.isExternalStorageHome()) { continue; } else if (root.isLibrary() || root.isDownloads()) { - item = new RootItem(root, mActionHandler, maybeShowBadge); + item = + mUseRailAsContainer + ? new NavRailRootItem(root, mActionHandler, maybeShowBadge) + : new RootItem(root, mActionHandler, maybeShowBadge); librariesBuilder.add(item); } else if (root.isStorage()) { - item = new RootItem(root, mActionHandler, maybeShowBadge); + item = + mUseRailAsContainer + ? new NavRailRootItem(root, mActionHandler, maybeShowBadge) + : new RootItem(root, mActionHandler, maybeShowBadge); storageProvidersBuilder.add(item); } else { - item = new RootItem(root, mActionHandler, - providersAccess.getPackageName(root.userId, root.authority), - maybeShowBadge); + item = + mUseRailAsContainer + ? new NavRailRootItem( + root, + mActionHandler, + providersAccess.getPackageName(root.userId, root.authority), + maybeShowBadge) + : new RootItem( + root, + mActionHandler, + providersAccess.getPackageName(root.userId, root.authority), + maybeShowBadge); otherProviders.add(item); } } @@ -566,8 +648,18 @@ public class RootsFragment extends Fragment { appsMapping.put(userPackage, info); if (!CrossProfileUtils.isCrossProfileIntentForwarderActivity(info)) { - final Item item = new AppItem(info, info.loadLabel(pm).toString(), userId, - mActionHandler); + final Item item = + mUseRailAsContainer + ? new NavRailAppItem( + info, + info.loadLabel(pm).toString(), + userId, + mActionHandler) + : new AppItem( + info, + info.loadLabel(pm).toString(), + userId, + mActionHandler); appItems.put(userPackage, item); if (VERBOSE) Log.v(TAG, "Adding handler app: " + item); } @@ -583,8 +675,12 @@ public class RootsFragment extends Fragment { final Item item; if (resolveInfo != null) { - item = new RootAndAppItem(rootItem.root, resolveInfo, mActionHandler, - maybeShowBadge); + item = + mUseRailAsContainer + ? new NavRailRootAndAppItem( + rootItem.root, resolveInfo, mActionHandler, maybeShowBadge) + : new RootAndAppItem( + rootItem.root, resolveInfo, mActionHandler, maybeShowBadge); appItems.remove(userPackage); } else { item = rootItem; diff --git a/tests/common/com/android/documentsui/testing/TestSelectionDetails.java b/tests/common/com/android/documentsui/testing/TestSelectionDetails.java index c63fdee59..e798174f8 100644 --- a/tests/common/com/android/documentsui/testing/TestSelectionDetails.java +++ b/tests/common/com/android/documentsui/testing/TestSelectionDetails.java @@ -32,7 +32,7 @@ public class TestSelectionDetails implements SelectionDetails { public boolean containFiles; public boolean canPasteInto; public boolean canExtract; - public boolean canOpenWith; + public boolean canOpen; public boolean canViewInOwner; @Override @@ -76,8 +76,8 @@ public class TestSelectionDetails implements SelectionDetails { } @Override - public boolean canOpenWith() { - return canOpenWith; + public boolean canOpen() { + return canOpen; } @Override diff --git a/tests/unit/com/android/documentsui/files/ActionHandlerTest.java b/tests/unit/com/android/documentsui/files/ActionHandlerTest.java index 6aaa3e5d2..8b03247b2 100644 --- a/tests/unit/com/android/documentsui/files/ActionHandlerTest.java +++ b/tests/unit/com/android/documentsui/files/ActionHandlerTest.java @@ -39,9 +39,10 @@ import android.content.ClipData; import android.content.Intent; import android.net.Uri; import android.os.Parcelable; -import android.platform.test.annotations.DisableFlags; -import android.platform.test.annotations.EnableFlags; -import android.platform.test.flag.junit.SetFlagsRule; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Path; import android.util.Pair; @@ -109,7 +110,7 @@ public class ActionHandlerTest { private boolean refreshAnswer = false; @Rule - public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); @Parameter(0) public boolean isPrivateSpaceEnabled; @@ -165,7 +166,7 @@ public class ActionHandlerTest { } @Test - @DisableFlags({Flags.FLAG_DESKTOP_FILE_HANDLING}) + @RequiresFlagsDisabled({Flags.FLAG_DESKTOP_FILE_HANDLING}) public void testOpenFileFlags() { mHandler.onDocumentOpened(TestEnv.FILE_GIF, com.android.documentsui.files.ActionHandler.VIEW_TYPE_PREVIEW, @@ -178,7 +179,7 @@ public class ActionHandlerTest { } @Test - @EnableFlags({Flags.FLAG_DESKTOP_FILE_HANDLING}) + @RequiresFlagsEnabled({Flags.FLAG_DESKTOP_FILE_HANDLING}) public void testOpenFileFlagsDesktop() { mHandler.onDocumentOpened(TestEnv.FILE_GIF, com.android.documentsui.files.ActionHandler.VIEW_TYPE_PREVIEW, @@ -460,6 +461,22 @@ public class ActionHandlerTest { } @Test + public void testDocumentContextMenuOpen() throws Exception { + mActivity.resources.setQuickViewerPackage("corptropolis.viewer"); + mActivity.currentRoot = TestProvidersAccess.HOME; + + // Test normal picking (i.e. double click) behaviour will quick view + mHandler.openDocument(TestEnv.FILE_GIF, ActionHandler.VIEW_TYPE_PREVIEW, + ActionHandler.VIEW_TYPE_REGULAR); + mActivity.assertActivityStarted(Intent.ACTION_QUICK_VIEW); + + // And verify open via context menu will view instead + mHandler.openDocumentViewOnly(TestEnv.FILE_GIF); + mActivity.assertActivityStarted(Intent.ACTION_VIEW); + } + + @Test + @RequiresFlagsDisabled({Flags.FLAG_DESKTOP_FILE_HANDLING}) public void testShowChooser() throws Exception { mActivity.currentRoot = TestProvidersAccess.DOWNLOADS; @@ -468,6 +485,18 @@ public class ActionHandlerTest { } @Test + @RequiresFlagsEnabled({Flags.FLAG_DESKTOP_FILE_HANDLING}) + public void testShowChooserDesktop() throws Exception { + mActivity.currentRoot = TestProvidersAccess.DOWNLOADS; + + mHandler.showChooserForDoc(TestEnv.FILE_PDF); + Intent actual = mActivity.startActivity.getLastValue(); + assertEquals(Intent.ACTION_VIEW, actual.getAction()); + assertEquals("ComponentInfo{android/com.android.internal.app.ResolverActivity}", + actual.getComponent().toString()); + } + + @Test public void testInitLocation_LaunchToStackLocation() { DocumentStack path = new DocumentStack(Roots.create("123"), mEnv.model.getDocument("1")); diff --git a/tests/unit/com/android/documentsui/files/MenuManagerTest.java b/tests/unit/com/android/documentsui/files/MenuManagerTest.java index 02988d62f..6f97de814 100644 --- a/tests/unit/com/android/documentsui/files/MenuManagerTest.java +++ b/tests/unit/com/android/documentsui/files/MenuManagerTest.java @@ -21,6 +21,10 @@ import static junit.framework.Assert.assertEquals; import static org.junit.Assert.assertTrue; import android.net.Uri; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; @@ -35,6 +39,7 @@ import com.android.documentsui.base.RootInfo; import com.android.documentsui.base.State; import com.android.documentsui.base.UserId; import com.android.documentsui.dirlist.TestData; +import com.android.documentsui.flags.Flags; import com.android.documentsui.testing.TestDirectoryDetails; import com.android.documentsui.testing.TestEnv; import com.android.documentsui.testing.TestFeatures; @@ -45,6 +50,7 @@ import com.android.documentsui.testing.TestSearchViewManager; import com.android.documentsui.testing.TestSelectionDetails; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -123,6 +129,9 @@ public final class MenuManagerTest { private int mFilesCount; + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @Before public void setUp() { testMenu = TestMenu.create(); @@ -388,7 +397,7 @@ public final class MenuManagerTest { @Test public void testActionMenu_CanOpenWith() { - selectionDetails.canOpenWith = true; + selectionDetails.canOpen = true; mgr.updateActionMenu(testMenu, selectionDetails); actionModeOpenWith.assertEnabledAndVisible(); @@ -396,7 +405,7 @@ public final class MenuManagerTest { @Test public void testActionMenu_NoOpenWith() { - selectionDetails.canOpenWith = false; + selectionDetails.canOpen = false; mgr.updateActionMenu(testMenu, selectionDetails); actionModeOpenWith.assertDisabledAndInvisible(); @@ -590,16 +599,28 @@ public final class MenuManagerTest { } @Test - public void testContextMenu_OnFile_CanOpenWith() { - selectionDetails.canOpenWith = true; + @RequiresFlagsDisabled({Flags.FLAG_DESKTOP_FILE_HANDLING}) + public void testContextMenu_OnFile_CanOpen() { + selectionDetails.canOpen = true; + mgr.updateContextMenuForFiles(testMenu, selectionDetails); + dirOpen.assertDisabledAndInvisible(); + dirOpenWith.assertEnabledAndVisible(); + } + + @Test + @RequiresFlagsEnabled({Flags.FLAG_DESKTOP_FILE_HANDLING}) + public void testContextMenu_OnFile_CanOpenDesktop() { + selectionDetails.canOpen = true; mgr.updateContextMenuForFiles(testMenu, selectionDetails); + dirOpen.assertEnabledAndVisible(); dirOpenWith.assertEnabledAndVisible(); } @Test - public void testContextMenu_OnFile_NoOpenWith() { - selectionDetails.canOpenWith = false; + public void testContextMenu_OnFile_NoOpen() { + selectionDetails.canOpen = false; mgr.updateContextMenuForFiles(testMenu, selectionDetails); + dirOpen.assertDisabledAndInvisible(); dirOpenWith.assertDisabledAndInvisible(); } |