summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AndroidManifest.xml1
-rw-r--r--OWNERS2
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_badge_icon_color.xml21
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_label_color.xml21
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/color/doc_list_item_subtitle_color.xml5
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/color/nav_rail_item_text_color.xml21
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/drawable/ic_check_circle.xml13
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/drawable/list_item_background.xml76
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_background.xml23
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_icon_background.xml145
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/drawable/nav_rail_item_icon_mask.xml21
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/drawable/progress_indeterminate_horizontal_material_trimmed.xml1
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/drawable/root_item_background.xml12
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/drawable/tab_border_rounded.xml8
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/layout-w900dp/item_doc_list.xml84
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_directory.xml8
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/layout/fragment_nav_rail_roots.xml25
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/layout/item_doc_list.xml39
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/layout/nav_rail_item_root.xml55
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/layout/nav_rail_layout.xml129
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/values-night/colors.xml6
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/values-w600dp/dimens.xml4
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/values-w600dp/layouts.xml20
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/values-w900dp/dimens.xml7
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/values/colors.xml15
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/values/dimens.xml26
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/values/styles.xml35
-rw-r--r--res/flag(com.android.documentsui.flags.use_material3)/values/styles_text.xml9
-rw-r--r--src/com/android/documentsui/AbstractActionHandler.java5
-rw-r--r--src/com/android/documentsui/ActionHandler.java6
-rw-r--r--src/com/android/documentsui/BaseActivity.java15
-rw-r--r--src/com/android/documentsui/DrawerController.java5
-rw-r--r--src/com/android/documentsui/MenuManager.java2
-rw-r--r--src/com/android/documentsui/dirlist/DirectoryFragment.java27
-rw-r--r--src/com/android/documentsui/dirlist/DocumentHolder.java3
-rw-r--r--src/com/android/documentsui/dirlist/DocumentsSwipeRefreshLayout.java38
-rw-r--r--src/com/android/documentsui/dirlist/ListDocumentHolder.java13
-rw-r--r--src/com/android/documentsui/dirlist/SelectionMetadata.java2
-rw-r--r--src/com/android/documentsui/files/ActionHandler.java31
-rw-r--r--src/com/android/documentsui/files/FilesActivity.java9
-rw-r--r--src/com/android/documentsui/files/MenuManager.java9
-rw-r--r--src/com/android/documentsui/picker/PickActivity.java10
-rw-r--r--src/com/android/documentsui/sidebar/AppItem.java13
-rw-r--r--src/com/android/documentsui/sidebar/NavRailAppItem.java48
-rw-r--r--src/com/android/documentsui/sidebar/NavRailProfileItem.java47
-rw-r--r--src/com/android/documentsui/sidebar/NavRailRootAndAppItem.java40
-rw-r--r--src/com/android/documentsui/sidebar/NavRailRootItem.java52
-rw-r--r--src/com/android/documentsui/sidebar/ProfileItem.java7
-rw-r--r--src/com/android/documentsui/sidebar/RootAndAppItem.java17
-rw-r--r--src/com/android/documentsui/sidebar/RootItem.java12
-rw-r--r--src/com/android/documentsui/sidebar/RootsFragment.java128
-rw-r--r--tests/common/com/android/documentsui/testing/TestSelectionDetails.java6
-rw-r--r--tests/unit/com/android/documentsui/files/ActionHandlerTest.java41
-rw-r--r--tests/unit/com/android/documentsui/files/MenuManagerTest.java33
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
diff --git a/OWNERS b/OWNERS
index 1b688b7c4..70a483639 100644
--- a/OWNERS
+++ b/OWNERS
@@ -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();
}