Loading res/layout/directory_header.xml +6 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,12 @@ <!-- used for search chip. --> <include layout="@layout/search_chip_row"/> <com.google.android.material.tabs.TabLayout android:id="@+id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" android:visibility="gone"/> <!-- used for apps row. --> <include layout="@layout/apps_row"/> Loading res/values/strings.xml +6 −0 Original line number Diff line number Diff line Loading @@ -483,4 +483,10 @@ <!-- Content description for deleting search history. [CHAR_LIMIT=60] --> <string name="delete_search_history">Delete search history <xliff:g id="text" example="image">%1$s</xliff:g></string> <!-- Label of tab to indicate personal directory [CHAR LIMIT=40] --> <string name="personal_tab">Personal</string> <!-- Label of tab to indicate work directory [CHAR LIMIT=40] --> <string name="work_tab">Work</string> </resources> src/com/android/documentsui/BaseActivity.java +10 −3 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ import com.android.documentsui.sorting.SortController; import com.android.documentsui.sorting.SortModel; import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.tabs.TabLayout; import java.util.ArrayList; import java.util.Date; Loading @@ -95,7 +96,6 @@ public abstract class BaseActivity protected Injector<?> mInjector; protected ProvidersCache mProviders; protected UserIdManager mUserIdManager; protected DocumentsAccess mDocs; protected DrawerController mDrawer; Loading Loading @@ -153,7 +153,6 @@ public abstract class BaseActivity mDrawer = DrawerController.create(this, mInjector.config); Metrics.logActivityLaunch(mState, intent); mUserIdManager = DocumentsApplication.getUserIdManager(this); mProviders = DocumentsApplication.getProvidersCache(this); mDocs = DocumentsAccess.create(this); Loading @@ -162,8 +161,11 @@ public abstract class BaseActivity Breadcrumb breadcrumb = findViewById(R.id.horizontal_breadcrumb); assert(breadcrumb != null); TabLayout profileTabs = findViewById(R.id.tabs); assert (profileTabs != null); mNavigator = new NavigationViewManager(this, mDrawer, mState, this, breadcrumb); mNavigator = new NavigationViewManager(this, mDrawer, mState, this, breadcrumb, profileTabs, DocumentsApplication.getUserIdManager(this)); SearchManagerListener searchListener = new SearchManagerListener() { /** * Called when search results changed. Refreshes the content of the directory. It Loading Loading @@ -738,6 +740,11 @@ public abstract class BaseActivity return mSearchManager.isExpanded(); } @Override public boolean isSearching() { return mSearchManager.isSearching(); } @Override public RootInfo getCurrentRoot() { RootInfo root = mState.stack.getRoot(); Loading src/com/android/documentsui/NavigationViewManager.java +8 −2 Original line number Diff line number Diff line Loading @@ -29,13 +29,13 @@ import android.view.ViewOutlineProvider; import androidx.annotation.Nullable; import androidx.appcompat.widget.Toolbar; import com.android.documentsui.R; import com.android.documentsui.base.RootInfo; import com.android.documentsui.base.State; import com.android.documentsui.dirlist.AnimationView; import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.appbar.CollapsingToolbarLayout; import com.google.android.material.tabs.TabLayout; import java.util.function.IntConsumer; Loading @@ -51,6 +51,7 @@ public class NavigationViewManager { private final State mState; private final NavigationViewManager.Environment mEnv; private final Breadcrumb mBreadcrumb; private final ProfileTabs mProfileTabs; private final View mSearchBarView; private final CollapsingToolbarLayout mCollapsingBarLayout; private final Drawable mDefaultActionBarBackground; Loading @@ -62,7 +63,9 @@ public class NavigationViewManager { DrawerController drawer, State state, NavigationViewManager.Environment env, Breadcrumb breadcrumb) { Breadcrumb breadcrumb, TabLayout tabLayout, UserIdManager userIdManager) { mToolbar = activity.findViewById(R.id.toolbar); mDrawer = drawer; Loading @@ -70,6 +73,7 @@ public class NavigationViewManager { mEnv = env; mBreadcrumb = breadcrumb; mBreadcrumb.setup(env, state, this::onNavigationItemSelected); mProfileTabs = new ProfileTabs(tabLayout, mState, userIdManager, mEnv); mToolbar.setNavigationOnClickListener( new View.OnClickListener() { Loading Loading @@ -122,6 +126,7 @@ public class NavigationViewManager { public void update() { updateScrollFlag(); updateToolbar(); mProfileTabs.updateView(); // TODO: Looks to me like this block is never getting hit. if (mEnv.isSearchExpanded()) { Loading Loading @@ -214,5 +219,6 @@ public class NavigationViewManager { @Deprecated // Use CommonAddones#refreshCurrentRootAndDirectory void refreshCurrentRootAndDirectory(int animation); boolean isSearchExpanded(); boolean isSearching(); } } src/com/android/documentsui/ProfileTabs.java 0 → 100644 +106 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.documentsui; import static androidx.core.util.Preconditions.checkNotNull; import android.view.View; import androidx.annotation.VisibleForTesting; import com.android.documentsui.base.State; import com.android.documentsui.base.UserId; import com.google.android.material.tabs.TabLayout; import java.util.Collections; import java.util.List; /** * A manager class to control UI on a {@link TabLayout} for cross-profile purpose. */ public class ProfileTabs { private final TabLayout mTabs; private final State mState; private final NavigationViewManager.Environment mEnv; private final UserIdManager mUserIdManager; private List<UserId> mUserIds; public ProfileTabs(TabLayout tabLayout, State state, UserIdManager userIdManager, NavigationViewManager.Environment env) { mTabs = checkNotNull(tabLayout); mState = checkNotNull(state); mEnv = checkNotNull(env); mUserIdManager = checkNotNull(userIdManager); mTabs.removeAllTabs(); mUserIds = Collections.singletonList(UserId.CURRENT_USER); } /** * Update the tab layout based on conditions. */ public void updateView() { updateTabsIfNeeded(); mTabs.setVisibility(shouldShow() ? View.VISIBLE : View.GONE); } private void updateTabsIfNeeded() { List<UserId> userIds = mUserIdManager.getUserIds(); // Add tabs if the userIds is not equals to cached mUserIds. // Given that mUserIds was initialized with only the current user, if getUserIds() // returns just the current user, we don't need to do anything on the tab layout. if (!userIds.equals(mUserIds)) { mUserIds = userIds; mTabs.removeAllTabs(); if (mUserIds.size() > 1) { mTabs.addTab(createTab(R.string.personal_tab, mUserIdManager.getSystemUser())); mTabs.addTab(createTab(R.string.work_tab, mUserIdManager.getManagedUser())); } } } /** * Returns the user represented by the selected tab. If there is no tab, return the * current user. */ @VisibleForTesting public UserId getSelectedUser() { if (mTabs.getTabCount() > 1 && mTabs.getSelectedTabPosition() >= 0) { return (UserId) mTabs.getTabAt(mTabs.getSelectedTabPosition()).getTag(); } return UserId.CURRENT_USER; } private boolean shouldShow() { // Only show tabs when: // 1. state supports cross profile, and // 2. more than one tab, and // 3. not in search mode, and // 4. not in sub-folder, and // 5. the root supports cross profile. return mState.supportsCrossProfile() && mTabs.getTabCount() > 1 && !mEnv.isSearching() && mState.stack.size() <= 1 && mState.stack.getRoot() != null && mState.stack.getRoot().supportsCrossProfile(); } private TabLayout.Tab createTab(int resId, UserId userId) { return mTabs.newTab().setText(resId).setTag(userId); } } Loading
res/layout/directory_header.xml +6 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,12 @@ <!-- used for search chip. --> <include layout="@layout/search_chip_row"/> <com.google.android.material.tabs.TabLayout android:id="@+id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" android:visibility="gone"/> <!-- used for apps row. --> <include layout="@layout/apps_row"/> Loading
res/values/strings.xml +6 −0 Original line number Diff line number Diff line Loading @@ -483,4 +483,10 @@ <!-- Content description for deleting search history. [CHAR_LIMIT=60] --> <string name="delete_search_history">Delete search history <xliff:g id="text" example="image">%1$s</xliff:g></string> <!-- Label of tab to indicate personal directory [CHAR LIMIT=40] --> <string name="personal_tab">Personal</string> <!-- Label of tab to indicate work directory [CHAR LIMIT=40] --> <string name="work_tab">Work</string> </resources>
src/com/android/documentsui/BaseActivity.java +10 −3 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ import com.android.documentsui.sorting.SortController; import com.android.documentsui.sorting.SortModel; import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.tabs.TabLayout; import java.util.ArrayList; import java.util.Date; Loading @@ -95,7 +96,6 @@ public abstract class BaseActivity protected Injector<?> mInjector; protected ProvidersCache mProviders; protected UserIdManager mUserIdManager; protected DocumentsAccess mDocs; protected DrawerController mDrawer; Loading Loading @@ -153,7 +153,6 @@ public abstract class BaseActivity mDrawer = DrawerController.create(this, mInjector.config); Metrics.logActivityLaunch(mState, intent); mUserIdManager = DocumentsApplication.getUserIdManager(this); mProviders = DocumentsApplication.getProvidersCache(this); mDocs = DocumentsAccess.create(this); Loading @@ -162,8 +161,11 @@ public abstract class BaseActivity Breadcrumb breadcrumb = findViewById(R.id.horizontal_breadcrumb); assert(breadcrumb != null); TabLayout profileTabs = findViewById(R.id.tabs); assert (profileTabs != null); mNavigator = new NavigationViewManager(this, mDrawer, mState, this, breadcrumb); mNavigator = new NavigationViewManager(this, mDrawer, mState, this, breadcrumb, profileTabs, DocumentsApplication.getUserIdManager(this)); SearchManagerListener searchListener = new SearchManagerListener() { /** * Called when search results changed. Refreshes the content of the directory. It Loading Loading @@ -738,6 +740,11 @@ public abstract class BaseActivity return mSearchManager.isExpanded(); } @Override public boolean isSearching() { return mSearchManager.isSearching(); } @Override public RootInfo getCurrentRoot() { RootInfo root = mState.stack.getRoot(); Loading
src/com/android/documentsui/NavigationViewManager.java +8 −2 Original line number Diff line number Diff line Loading @@ -29,13 +29,13 @@ import android.view.ViewOutlineProvider; import androidx.annotation.Nullable; import androidx.appcompat.widget.Toolbar; import com.android.documentsui.R; import com.android.documentsui.base.RootInfo; import com.android.documentsui.base.State; import com.android.documentsui.dirlist.AnimationView; import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.appbar.CollapsingToolbarLayout; import com.google.android.material.tabs.TabLayout; import java.util.function.IntConsumer; Loading @@ -51,6 +51,7 @@ public class NavigationViewManager { private final State mState; private final NavigationViewManager.Environment mEnv; private final Breadcrumb mBreadcrumb; private final ProfileTabs mProfileTabs; private final View mSearchBarView; private final CollapsingToolbarLayout mCollapsingBarLayout; private final Drawable mDefaultActionBarBackground; Loading @@ -62,7 +63,9 @@ public class NavigationViewManager { DrawerController drawer, State state, NavigationViewManager.Environment env, Breadcrumb breadcrumb) { Breadcrumb breadcrumb, TabLayout tabLayout, UserIdManager userIdManager) { mToolbar = activity.findViewById(R.id.toolbar); mDrawer = drawer; Loading @@ -70,6 +73,7 @@ public class NavigationViewManager { mEnv = env; mBreadcrumb = breadcrumb; mBreadcrumb.setup(env, state, this::onNavigationItemSelected); mProfileTabs = new ProfileTabs(tabLayout, mState, userIdManager, mEnv); mToolbar.setNavigationOnClickListener( new View.OnClickListener() { Loading Loading @@ -122,6 +126,7 @@ public class NavigationViewManager { public void update() { updateScrollFlag(); updateToolbar(); mProfileTabs.updateView(); // TODO: Looks to me like this block is never getting hit. if (mEnv.isSearchExpanded()) { Loading Loading @@ -214,5 +219,6 @@ public class NavigationViewManager { @Deprecated // Use CommonAddones#refreshCurrentRootAndDirectory void refreshCurrentRootAndDirectory(int animation); boolean isSearchExpanded(); boolean isSearching(); } }
src/com/android/documentsui/ProfileTabs.java 0 → 100644 +106 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.documentsui; import static androidx.core.util.Preconditions.checkNotNull; import android.view.View; import androidx.annotation.VisibleForTesting; import com.android.documentsui.base.State; import com.android.documentsui.base.UserId; import com.google.android.material.tabs.TabLayout; import java.util.Collections; import java.util.List; /** * A manager class to control UI on a {@link TabLayout} for cross-profile purpose. */ public class ProfileTabs { private final TabLayout mTabs; private final State mState; private final NavigationViewManager.Environment mEnv; private final UserIdManager mUserIdManager; private List<UserId> mUserIds; public ProfileTabs(TabLayout tabLayout, State state, UserIdManager userIdManager, NavigationViewManager.Environment env) { mTabs = checkNotNull(tabLayout); mState = checkNotNull(state); mEnv = checkNotNull(env); mUserIdManager = checkNotNull(userIdManager); mTabs.removeAllTabs(); mUserIds = Collections.singletonList(UserId.CURRENT_USER); } /** * Update the tab layout based on conditions. */ public void updateView() { updateTabsIfNeeded(); mTabs.setVisibility(shouldShow() ? View.VISIBLE : View.GONE); } private void updateTabsIfNeeded() { List<UserId> userIds = mUserIdManager.getUserIds(); // Add tabs if the userIds is not equals to cached mUserIds. // Given that mUserIds was initialized with only the current user, if getUserIds() // returns just the current user, we don't need to do anything on the tab layout. if (!userIds.equals(mUserIds)) { mUserIds = userIds; mTabs.removeAllTabs(); if (mUserIds.size() > 1) { mTabs.addTab(createTab(R.string.personal_tab, mUserIdManager.getSystemUser())); mTabs.addTab(createTab(R.string.work_tab, mUserIdManager.getManagedUser())); } } } /** * Returns the user represented by the selected tab. If there is no tab, return the * current user. */ @VisibleForTesting public UserId getSelectedUser() { if (mTabs.getTabCount() > 1 && mTabs.getSelectedTabPosition() >= 0) { return (UserId) mTabs.getTabAt(mTabs.getSelectedTabPosition()).getTag(); } return UserId.CURRENT_USER; } private boolean shouldShow() { // Only show tabs when: // 1. state supports cross profile, and // 2. more than one tab, and // 3. not in search mode, and // 4. not in sub-folder, and // 5. the root supports cross profile. return mState.supportsCrossProfile() && mTabs.getTabCount() > 1 && !mEnv.isSearching() && mState.stack.size() <= 1 && mState.stack.getRoot() != null && mState.stack.getRoot().supportsCrossProfile(); } private TabLayout.Tab createTab(int resId, UserId userId) { return mTabs.newTab().setText(resId).setTag(userId); } }