Switch to recyclerview in ManageApplications

- Replace ListView with RecyclerView in layout
- Replace ApplicationAdapter's superclass to be RecyclerView.Adapter
- Change adapter interfaces (where necessary) to work with RecyclerView
- Replace fast scroll with Recycler's mechanism (all in xml)
- Removed section indexer (text bubble when fast scroll) because
  recyclerview doesn't support it.

Bug: 64804294
Test: robotests
Change-Id: I55b221836ce6abdeddf4568c8a8a5632cbddbd3b
This commit is contained in:
Fan Zhang
2017-10-12 11:09:24 -07:00
parent 24ff765731
commit 78369d91bc
17 changed files with 534 additions and 448 deletions

View File

@@ -0,0 +1,95 @@
/*
* Copyright (C) 2017 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.settings.applications.manageapplications;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import com.android.settings.R;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.applications.ApplicationsState;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class ApplicationViewHolderTest {
private Context mContext;
private View mView;
private ApplicationViewHolder mHolder;
@Before
public void seUp() {
mContext = RuntimeEnvironment.application;
mView = ApplicationViewHolder.newView(LayoutInflater.from(mContext),
new FrameLayout(mContext));
mHolder = new ApplicationViewHolder(mView);
}
@Test
public void updateDisableView_appDisabledUntilUsed_shouldSetDisabled() {
final ApplicationInfo info = new ApplicationInfo();
info.flags = ApplicationInfo.FLAG_INSTALLED;
info.enabled = true;
info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
mHolder.updateDisableView(info);
assertThat(mHolder.mDisabled.getText()).isEqualTo(mContext.getText(R.string.disabled));
}
@Test
public void setSummaries() {
mHolder.setSummary("hello");
assertThat(mHolder.mSummary.getText()).isEqualTo("hello");
mHolder.setSummary(R.string.disabled);
assertThat(mHolder.mSummary.getText()).isEqualTo(mContext.getText(R.string.disabled));
}
@Test
public void updateSize() {
final String invalidStr = "invalid";
final ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class);
entry.internalSizeStr = "internal";
entry.externalSizeStr = "external";
entry.sizeStr = entry.internalSizeStr;
mHolder.updateSizeText(entry, invalidStr, ManageApplications.SIZE_INTERNAL);
assertThat(mHolder.mSummary.getText()).isEqualTo(entry.internalSizeStr);
mHolder.updateSizeText(entry, invalidStr, ManageApplications.SIZE_EXTERNAL);
assertThat(mHolder.mSummary.getText()).isEqualTo(entry.externalSizeStr);
entry.sizeStr = null;
entry.size = ApplicationsState.SIZE_INVALID;
mHolder.updateSizeText(entry, invalidStr, ManageApplications.SIZE_EXTERNAL);
assertThat(mHolder.mSummary.getText()).isEqualTo(invalidStr);
}
}

View File

@@ -31,19 +31,16 @@ import static org.mockito.Mockito.when;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Bundle;
import android.os.Looper;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.android.settings.R;
import com.android.settings.Settings;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowResources;
@@ -102,30 +99,6 @@ public class ManageApplicationsTest {
ReflectionHelpers.setField(mFragment, "mLifecycle", new Lifecycle());
}
@Test
public void launchFragment() {
SettingsRobolectricTestRunner.startSettingsFragment(
mFragment, Settings.ManageApplicationsActivity.class);
}
@Test
public void updateDisableView_appDisabledUntilUsed_shouldSetDisabled() {
final TextView view = mock(TextView.class);
final ApplicationInfo info = new ApplicationInfo();
info.flags = ApplicationInfo.FLAG_INSTALLED;
info.enabled = true;
info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
ManageApplications fragment = mock(ManageApplications.class);
when(fragment.getActivity()).thenReturn(mock(Activity.class));
final ManageApplications.ApplicationsAdapter adapter =
new ManageApplications.ApplicationsAdapter(mState, fragment,
AppFilterRegistry.getInstance().get(FILTER_APPS_ALL));
adapter.updateDisableView(view, info);
verify(view).setText(R.string.disabled);
}
@Test
public void updateMenu_mainListType_showAppReset() {
setUpOptionMenus();
@@ -170,14 +143,12 @@ public class ManageApplicationsTest {
ReflectionHelpers.setField(fragment, "mLoadingContainer", mock(View.class));
ReflectionHelpers.setField(fragment, "mListContainer", mock(View.class));
when(fragment.getActivity()).thenReturn(mock(Activity.class));
final Handler handler = mock(Handler.class);
final ManageApplications.ApplicationsAdapter adapter =
spy(new ManageApplications.ApplicationsAdapter(mState, fragment,
AppFilterRegistry.getInstance().get(FILTER_APPS_ALL)));
spy(new ManageApplications.ApplicationsAdapter(mState, fragment,
AppFilterRegistry.getInstance().get(FILTER_APPS_ALL), new Bundle()));
final LoadingViewController loadingViewController =
mock(LoadingViewController.class);
ReflectionHelpers.setField(adapter, "mLoadingViewController", loadingViewController);
ReflectionHelpers.setField(adapter, "mFgHandler", handler);
// app loading completed
ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", true);
@@ -196,15 +167,12 @@ public class ManageApplicationsTest {
ReflectionHelpers.setField(fragment, "mLoadingContainer", mock(View.class));
ReflectionHelpers.setField(fragment, "mListContainer", mock(View.class));
when(fragment.getActivity()).thenReturn(mock(Activity.class));
final Handler handler = mock(Handler.class);
final ManageApplications.ApplicationsAdapter adapter =
spy(new ManageApplications.ApplicationsAdapter(mState, fragment,
AppFilterRegistry.getInstance().get(FILTER_APPS_ALL)));
spy(new ManageApplications.ApplicationsAdapter(mState, fragment,
AppFilterRegistry.getInstance().get(FILTER_APPS_ALL), new Bundle()));
final LoadingViewController loadingViewController =
mock(LoadingViewController.class);
ReflectionHelpers.setField(adapter, "mLoadingViewController", loadingViewController);
ReflectionHelpers.setField(adapter, "mFgHandler", handler);
// app loading not yet completed
ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", false);
@@ -218,6 +186,10 @@ public class ManageApplicationsTest {
public void onRebuildComplete_shouldHideLoadingView() {
final Context context = RuntimeEnvironment.application;
final ManageApplications fragment = mock(ManageApplications.class);
final RecyclerView recyclerView = mock(RecyclerView.class);
final View emptyView = mock(View.class);
ReflectionHelpers.setField(fragment, "mRecyclerView", recyclerView);
ReflectionHelpers.setField(fragment, "mEmptyView", emptyView);
final View loadingContainer = mock(View.class);
when(loadingContainer.getContext()).thenReturn(context);
final View listContainer = mock(View.class);
@@ -226,14 +198,12 @@ public class ManageApplicationsTest {
ReflectionHelpers.setField(fragment, "mLoadingContainer", loadingContainer);
ReflectionHelpers.setField(fragment, "mListContainer", listContainer);
when(fragment.getActivity()).thenReturn(mock(Activity.class));
final Handler handler = mock(Handler.class);
final ManageApplications.ApplicationsAdapter adapter =
spy(new ManageApplications.ApplicationsAdapter(mState, fragment,
AppFilterRegistry.getInstance().get(FILTER_APPS_ALL)));
spy(new ManageApplications.ApplicationsAdapter(mState, fragment,
AppFilterRegistry.getInstance().get(FILTER_APPS_ALL), new Bundle()));
final LoadingViewController loadingViewController =
mock(LoadingViewController.class);
ReflectionHelpers.setField(adapter, "mLoadingViewController", loadingViewController);
ReflectionHelpers.setField(adapter, "mFgHandler", handler);
ReflectionHelpers.setField(adapter, "mAppFilter",
AppFilterRegistry.getInstance().get(FILTER_APPS_ALL));

View File

@@ -28,11 +28,12 @@ import android.os.UserHandle;
import android.os.storage.VolumeInfo;
import android.provider.DocumentsContract;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.applications.StorageStatsSource;
import com.android.settingslib.deviceinfo.StorageVolumeProvider;
import org.junit.Before;
import org.junit.Test;
@@ -51,14 +52,13 @@ public class MusicViewHolderControllerTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Fragment mFragment;
@Mock
private StorageVolumeProvider mSvp;
@Mock
private StorageStatsSource mSource;
private Context mContext;
private MusicViewHolderController mController;
private VolumeInfo mVolume;
private AppViewHolder mHolder;
private View mView;
private ApplicationViewHolder mHolder;
@Before
public void setUp() throws Exception {
@@ -69,25 +69,26 @@ public class MusicViewHolderControllerTest {
new UserHandle(0));
LayoutInflater inflater = LayoutInflater.from(mContext);
mHolder = AppViewHolder.createOrRecycle(inflater, null);
mView = ApplicationViewHolder.newView(inflater, new FrameLayout(mContext));
mHolder = new ApplicationViewHolder(mView);
}
@Test
public void storageShouldBeZeroBytesIfQueriedBeforeStorageQueryFinishes() {
mController.setupView(mHolder);
assertThat(mHolder.summary.getText().toString()).isEqualTo("0.00 B");
assertThat(mHolder.mSummary.getText().toString()).isEqualTo("0.00 B");
}
@Test
public void storageShouldRepresentStorageStatsQuery() throws Exception {
when(mSource.getExternalStorageStats(nullable(String.class), nullable(UserHandle.class))).thenReturn(
new StorageStatsSource.ExternalStorageStats(1, 1, 0, 0, 0));
when(mSource.getExternalStorageStats(nullable(String.class), nullable(UserHandle.class)))
.thenReturn(new StorageStatsSource.ExternalStorageStats(1, 1, 0, 0, 0));
mController.queryStats();
mController.setupView(mHolder);
assertThat(mHolder.summary.getText().toString()).isEqualTo("1.00 B");
assertThat(mHolder.mSummary.getText().toString()).isEqualTo("1.00 B");
}
@Test

View File

@@ -27,11 +27,12 @@ import android.content.Intent;
import android.os.UserHandle;
import android.os.storage.VolumeInfo;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.applications.StorageStatsSource;
import com.android.settingslib.deviceinfo.StorageVolumeProvider;
import org.junit.Before;
import org.junit.Test;
@@ -48,14 +49,14 @@ import org.robolectric.annotation.Config;
public class PhotosViewHolderControllerTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Fragment mFragment;
@Mock private StorageVolumeProvider mSvp;
@Mock private StorageStatsSource mSource;
private Context mContext;
private PhotosViewHolderController mController;
private VolumeInfo mVolume;
private AppViewHolder mHolder;
private View mView;
private ApplicationViewHolder mHolder;
@Before
public void setUp() throws Exception {
@@ -66,15 +67,16 @@ public class PhotosViewHolderControllerTest {
new PhotosViewHolderController(
mContext, mSource, mVolume.fsUuid, new UserHandle(0));
LayoutInflater inflater = LayoutInflater.from(mContext);
mHolder = AppViewHolder.createOrRecycle(inflater, null);
final LayoutInflater inflater = LayoutInflater.from(mContext);
mView = ApplicationViewHolder.newView(inflater, new FrameLayout(mContext));
mHolder = new ApplicationViewHolder(mView);
}
@Test
public void storageShouldBeZeroBytesIfQueriedBeforeStorageQueryFinishes() {
mController.setupView(mHolder);
assertThat(mHolder.summary.getText().toString()).isEqualTo("0.00 B");
assertThat(mHolder.mSummary.getText().toString()).isEqualTo("0.00 B");
}
@Test
@@ -85,7 +87,7 @@ public class PhotosViewHolderControllerTest {
mController.queryStats();
mController.setupView(mHolder);
assertThat(mHolder.summary.getText().toString()).isEqualTo("11.00 B");
assertThat(mHolder.mSummary.getText().toString()).isEqualTo("11.00 B");
}
@Test