summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Kelvin Kwan <kelvinkwan@google.com> 2020-02-15 18:43:15 +0000
committer Kelvin Kwan <kelvinkwan@google.com> 2020-02-15 19:20:21 +0000
commitcf0bd74651b98c8822ff87b6469dc9e9d1f3c1fb (patch)
tree5b98eb48ad504e869819a0431391c5903956cf55
parent28fb87ee2f4b71e3bab308d37d9975630f60263b (diff)
Grey out and disable tabs when selecting files.
Bug: 149614174 Test: manual Test: atest DocumentsUIGoogleTests:com.android.documentsui.ProfileTabsControllerTest Change-Id: I205c13b314a5ea196b00e5fd32525237653af09b
-rw-r--r--src/com/android/documentsui/BaseActivity.java4
-rw-r--r--src/com/android/documentsui/DummyProfileTabsAddons.java28
-rw-r--r--src/com/android/documentsui/Injector.java5
-rw-r--r--src/com/android/documentsui/NavigationViewManager.java4
-rw-r--r--src/com/android/documentsui/ProfileTabs.java20
-rw-r--r--src/com/android/documentsui/ProfileTabsAddons.java26
-rw-r--r--src/com/android/documentsui/ProfileTabsController.java48
-rw-r--r--src/com/android/documentsui/dirlist/DirectoryFragment.java8
-rw-r--r--src/com/android/documentsui/files/FilesActivity.java10
-rw-r--r--src/com/android/documentsui/picker/PickActivity.java5
-rw-r--r--tests/unit/com/android/documentsui/ProfileTabsControllerTest.java83
11 files changed, 239 insertions, 2 deletions
diff --git a/src/com/android/documentsui/BaseActivity.java b/src/com/android/documentsui/BaseActivity.java
index c5726d9eb..079f33244 100644
--- a/src/com/android/documentsui/BaseActivity.java
+++ b/src/com/android/documentsui/BaseActivity.java
@@ -434,6 +434,10 @@ public abstract class BaseActivity
updateHeaderTitle();
}
+ protected ProfileTabsAddons getProfileTabsAddon() {
+ return mNavigator.getProfileTabsAddons();
+ }
+
@Override
public boolean onOptionsItemSelected(MenuItem item) {
diff --git a/src/com/android/documentsui/DummyProfileTabsAddons.java b/src/com/android/documentsui/DummyProfileTabsAddons.java
new file mode 100644
index 000000000..697025e23
--- /dev/null
+++ b/src/com/android/documentsui/DummyProfileTabsAddons.java
@@ -0,0 +1,28 @@
+/*
+ * 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;
+
+/**
+ * A dummy {@ProfileTabsAddons} implementation.
+ */
+public class DummyProfileTabsAddons implements ProfileTabsAddons {
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ // Do nothing.
+ }
+}
diff --git a/src/com/android/documentsui/Injector.java b/src/com/android/documentsui/Injector.java
index d6c631247..5761566c1 100644
--- a/src/com/android/documentsui/Injector.java
+++ b/src/com/android/documentsui/Injector.java
@@ -21,6 +21,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.view.MenuItem;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.selection.SelectionTracker;
import androidx.recyclerview.widget.RecyclerView;
@@ -36,7 +37,6 @@ import com.android.documentsui.prefs.ScopedPreferences;
import com.android.documentsui.queries.SearchViewManager;
import com.android.documentsui.ui.DialogController;
import com.android.documentsui.ui.MessageBuilder;
-import androidx.annotation.VisibleForTesting;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@@ -68,6 +68,9 @@ public class Injector<T extends ActionHandler> {
public ActionModeController actionModeController;
@ContentScoped
+ public ProfileTabsController profileTabsController;
+
+ @ContentScoped
public T actions;
@ContentScoped
diff --git a/src/com/android/documentsui/NavigationViewManager.java b/src/com/android/documentsui/NavigationViewManager.java
index aca8c31b5..ed4acf6aa 100644
--- a/src/com/android/documentsui/NavigationViewManager.java
+++ b/src/com/android/documentsui/NavigationViewManager.java
@@ -106,6 +106,10 @@ public class NavigationViewManager {
mSearchBarView.setOnClickListener(listener);
}
+ public ProfileTabsAddons getProfileTabsAddons() {
+ return mProfileTabs;
+ }
+
private void onNavigationIconClicked() {
if (mDrawer.isPresent()) {
mDrawer.setOpen(true);
diff --git a/src/com/android/documentsui/ProfileTabs.java b/src/com/android/documentsui/ProfileTabs.java
index 24a36b2b7..f9e195ba5 100644
--- a/src/com/android/documentsui/ProfileTabs.java
+++ b/src/com/android/documentsui/ProfileTabs.java
@@ -19,6 +19,7 @@ package com.android.documentsui;
import static androidx.core.util.Preconditions.checkNotNull;
import android.view.View;
+import android.view.ViewGroup;
import androidx.annotation.VisibleForTesting;
@@ -33,7 +34,8 @@ import java.util.List;
/**
* A manager class to control UI on a {@link TabLayout} for cross-profile purpose.
*/
-public class ProfileTabs {
+public class ProfileTabs implements ProfileTabsAddons {
+ private static final float DISABLED_TAB_OPACITY = 0.38f;
private final TabLayout mTabs;
private final State mState;
@@ -103,4 +105,20 @@ public class ProfileTabs {
private TabLayout.Tab createTab(int resId, UserId userId) {
return mTabs.newTab().setText(resId).setTag(userId);
}
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ if (mTabs.getChildCount() > 0) {
+ View view = mTabs.getChildAt(0);
+ if (view instanceof ViewGroup) {
+ ViewGroup tabs = (ViewGroup) view;
+ for (int i = 0; i < tabs.getChildCount(); i++) {
+ View tabView = tabs.getChildAt(i);
+ tabView.setEnabled(enabled);
+ tabView.setAlpha((enabled || mTabs.getSelectedTabPosition() == i) ? 1f
+ : DISABLED_TAB_OPACITY);
+ }
+ }
+ }
+ }
}
diff --git a/src/com/android/documentsui/ProfileTabsAddons.java b/src/com/android/documentsui/ProfileTabsAddons.java
new file mode 100644
index 000000000..885d29828
--- /dev/null
+++ b/src/com/android/documentsui/ProfileTabsAddons.java
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+/**
+ * Provides methods to control a {@link ProfileTabs}.
+ */
+public interface ProfileTabsAddons {
+ /**
+ * Enables/Disables the profile tabs.
+ */
+ void setEnabled(boolean enabled);
+}
diff --git a/src/com/android/documentsui/ProfileTabsController.java b/src/com/android/documentsui/ProfileTabsController.java
new file mode 100644
index 000000000..d10806b4f
--- /dev/null
+++ b/src/com/android/documentsui/ProfileTabsController.java
@@ -0,0 +1,48 @@
+/*
+ * 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 androidx.recyclerview.selection.SelectionTracker;
+import androidx.recyclerview.selection.SelectionTracker.SelectionObserver;
+
+/**
+ * A controller that listens to selection changes and control profile tabs behavior.
+ */
+public class ProfileTabsController extends SelectionObserver<String> {
+
+ private static final String TAG = "ProfileTabsController";
+
+ private final SelectionTracker<String> mSelectionMgr;
+ private final ProfileTabsAddons mProfileTabsAddons;
+
+ public ProfileTabsController(
+ SelectionTracker<String> selectionMgr,
+ ProfileTabsAddons profileTabsAddons) {
+ mSelectionMgr = selectionMgr;
+ mProfileTabsAddons = profileTabsAddons;
+ }
+
+ @Override
+ public void onSelectionChanged() {
+ mProfileTabsAddons.setEnabled(mSelectionMgr.getSelection().isEmpty());
+ }
+
+ @Override
+ public void onSelectionRestored() {
+ onSelectionChanged();
+ }
+}
diff --git a/src/com/android/documentsui/dirlist/DirectoryFragment.java b/src/com/android/documentsui/dirlist/DirectoryFragment.java
index d82fdeb52..dcd2edd19 100644
--- a/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -79,6 +79,7 @@ import com.android.documentsui.Injector.Injected;
import com.android.documentsui.MetricConsts;
import com.android.documentsui.Metrics;
import com.android.documentsui.Model;
+import com.android.documentsui.ProfileTabsController;
import com.android.documentsui.R;
import com.android.documentsui.ThumbnailCache;
import com.android.documentsui.base.DocumentFilters;
@@ -155,6 +156,10 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
@ContentScoped
private ActionModeController mActionModeController;
+ @Injected
+ @ContentScoped
+ private ProfileTabsController mProfileTabsController;
+
private DocDetailsLookup mDetailsLookup;
private SelectionMetadata mSelectionMetadata;
private KeyInputHandler mKeyListener;
@@ -402,6 +407,9 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
mSelectionMgr.addObserver(mActionModeController);
+ mProfileTabsController = mInjector.profileTabsController;
+ mSelectionMgr.addObserver(mProfileTabsController);
+
final ActivityManager am = (ActivityManager) mActivity.getSystemService(
Context.ACTIVITY_SERVICE);
boolean svelte = am.isLowRamDevice() && (mState.stack.isRecents());
diff --git a/src/com/android/documentsui/files/FilesActivity.java b/src/com/android/documentsui/files/FilesActivity.java
index 81ff61ff7..1d8909fbd 100644
--- a/src/com/android/documentsui/files/FilesActivity.java
+++ b/src/com/android/documentsui/files/FilesActivity.java
@@ -37,11 +37,14 @@ import com.android.documentsui.ActionModeController;
import com.android.documentsui.BaseActivity;
import com.android.documentsui.DocsSelectionHelper;
import com.android.documentsui.DocumentsApplication;
+import com.android.documentsui.DummyProfileTabsAddons;
import com.android.documentsui.FocusManager;
import com.android.documentsui.Injector;
import com.android.documentsui.MenuManager.DirectoryDetails;
import com.android.documentsui.OperationDialogFragment;
import com.android.documentsui.OperationDialogFragment.DialogType;
+import com.android.documentsui.ProfileTabsAddons;
+import com.android.documentsui.ProfileTabsController;
import com.android.documentsui.ProviderExecutor;
import com.android.documentsui.R;
import com.android.documentsui.SharedInputHandler;
@@ -74,6 +77,7 @@ public class FilesActivity extends BaseActivity implements AbstractActionHandler
private Injector<ActionHandler<FilesActivity>> mInjector;
private ActivityInputHandler mActivityInputHandler;
private SharedInputHandler mSharedInputHandler;
+ private final ProfileTabsAddons mProfileTabsAddonsStub = new DummyProfileTabsAddons();
public FilesActivity() {
super(R.layout.files_activity, TAG);
@@ -148,6 +152,12 @@ public class FilesActivity extends BaseActivity implements AbstractActionHandler
mInjector.searchManager = mSearchManager;
+ // No profile tabs will be shown on FilesActivity. Use a dummy to avoid unnecessary
+ // operations.
+ mInjector.profileTabsController = new ProfileTabsController(
+ mInjector.selectionMgr,
+ mProfileTabsAddonsStub);
+
mAppsRowManager = new AppsRowManager(mInjector.actions);
mInjector.appsRowManager = mAppsRowManager;
diff --git a/src/com/android/documentsui/picker/PickActivity.java b/src/com/android/documentsui/picker/PickActivity.java
index f7f2ebe80..f1a33098f 100644
--- a/src/com/android/documentsui/picker/PickActivity.java
+++ b/src/com/android/documentsui/picker/PickActivity.java
@@ -46,6 +46,7 @@ import com.android.documentsui.FocusManager;
import com.android.documentsui.Injector;
import com.android.documentsui.MenuManager.DirectoryDetails;
import com.android.documentsui.Metrics;
+import com.android.documentsui.ProfileTabsController;
import com.android.documentsui.ProviderExecutor;
import com.android.documentsui.R;
import com.android.documentsui.SharedInputHandler;
@@ -121,6 +122,10 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons {
mInjector.menuManager,
mInjector.messages);
+ mInjector.profileTabsController = new ProfileTabsController(
+ mInjector.selectionMgr,
+ getProfileTabsAddon());
+
mInjector.pickResult = getPickResult(icicle);
mInjector.actions = new ActionHandler<>(
this,
diff --git a/tests/unit/com/android/documentsui/ProfileTabsControllerTest.java b/tests/unit/com/android/documentsui/ProfileTabsControllerTest.java
new file mode 100644
index 000000000..2c6b2f90e
--- /dev/null
+++ b/tests/unit/com/android/documentsui/ProfileTabsControllerTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.recyclerview.selection.SelectionTracker;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+@SmallTest
+public class ProfileTabsControllerTest {
+
+ private SelectionTracker<String> mSelectionMgr = SelectionHelpers.createTestInstance();
+ private Boolean testEnabledValue = null;
+ private ProfileTabsController mController = new ProfileTabsController(mSelectionMgr,
+ enabled -> testEnabledValue = enabled);
+
+ @Before
+ public void setUp() throws Exception {
+ mSelectionMgr.addObserver(mController);
+ }
+
+ @Test
+ public void testNoSelection_enable() {
+ mController.onSelectionRestored();
+ assertThat(testEnabledValue).isTrue();
+ }
+
+ @Test
+ public void testClearSelection_enable() {
+ mSelectionMgr.select("foo");
+ mSelectionMgr.clearSelection();
+ assertThat(testEnabledValue).isTrue();
+ }
+
+ @Test
+ public void testDeselectAll_enable() {
+ mSelectionMgr.select("foo");
+ mSelectionMgr.select("bar");
+ mSelectionMgr.deselect("foo");
+ mSelectionMgr.deselect("bar");
+ assertThat(testEnabledValue).isTrue();
+ }
+
+ @Test
+ public void testSelection_disable() {
+ mSelectionMgr.select("foo");
+ assertThat(testEnabledValue).isFalse();
+ }
+
+ @Test
+ public void testMultipleSelection_disable() {
+ mSelectionMgr.select("foo");
+ mSelectionMgr.select("bar");
+ mSelectionMgr.select("apple");
+ assertThat(testEnabledValue).isFalse();
+ }
+
+ @Test
+ public void testDeselectSome_Disable() {
+ mSelectionMgr.select("foo");
+ mSelectionMgr.select("bar");
+ mSelectionMgr.deselect("bar");
+ assertThat(testEnabledValue).isFalse();
+ }
+}