Merge "Convert app storage page to use generic ActionButtonPref"

This commit is contained in:
TreeHugger Robot
2017-08-02 23:29:13 +00:00
committed by Android (Google) Code Review
3 changed files with 188 additions and 73 deletions

View File

@@ -18,10 +18,8 @@
xmlns:settings="http://schemas.android.com/apk/res-auto" xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/application_info_label"> android:title="@string/application_info_label">
<com.android.settings.applications.LayoutPreference <com.android.settings.widget.ActionButtonPreference
android:key="header_view" android:key="header_view" />
android:layout="@layout/app_action_buttons"
android:selectable="false" />
<com.android.settings.applications.SpacePreference <com.android.settings.applications.SpacePreference
android:key="storage_space" android:key="storage_space"

View File

@@ -16,6 +16,9 @@
package com.android.settings.applications; package com.android.settings.applications;
import static android.content.pm.ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.AppGlobals; import android.app.AppGlobals;
@@ -36,6 +39,7 @@ import android.os.RemoteException;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.storage.StorageManager; import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo; import android.os.storage.VolumeInfo;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference; import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory; import android.support.v7.preference.PreferenceCategory;
import android.util.Log; import android.util.Log;
@@ -48,6 +52,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settings.deviceinfo.StorageWizardMoveConfirm; import com.android.settings.deviceinfo.StorageWizardMoveConfirm;
import com.android.settings.widget.ActionButtonPreference;
import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.applications.ApplicationsState.Callbacks; import com.android.settingslib.applications.ApplicationsState.Callbacks;
import com.android.settingslib.applications.StorageStatsSource; import com.android.settingslib.applications.StorageStatsSource;
@@ -59,9 +64,6 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.TreeMap; import java.util.TreeMap;
import static android.content.pm.ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
public class AppStorageSettings extends AppInfoWithHeader public class AppStorageSettings extends AppInfoWithHeader
implements OnClickListener, Callbacks, DialogInterface.OnClickListener, implements OnClickListener, Callbacks, DialogInterface.OnClickListener,
LoaderManager.LoaderCallbacks<AppStorageStats> { LoaderManager.LoaderCallbacks<AppStorageStats> {
@@ -102,9 +104,8 @@ public class AppStorageSettings extends AppInfoWithHeader
private static final String KEY_DATA_CLEARED = "data_cleared"; private static final String KEY_DATA_CLEARED = "data_cleared";
// Views related to cache info // Views related to cache info
private Preference mCacheSize; @VisibleForTesting
private Button mClearDataButton; ActionButtonPreference mButtonsPref;
private Button mClearCacheButton;
private Preference mStorageUsed; private Preference mStorageUsed;
private Button mChangeStorageButton; private Button mChangeStorageButton;
@@ -118,7 +119,8 @@ public class AppStorageSettings extends AppInfoWithHeader
private boolean mCacheCleared; private boolean mCacheCleared;
private boolean mDataCleared; private boolean mDataCleared;
private AppStorageSizesController mSizeController; @VisibleForTesting
AppStorageSizesController mSizeController;
private ClearCacheObserver mClearCacheObserver; private ClearCacheObserver mClearCacheObserver;
private ClearUserDataObserver mClearDataObserver; private ClearUserDataObserver mClearDataObserver;
@@ -164,9 +166,9 @@ public class AppStorageSettings extends AppInfoWithHeader
.setComputingString(R.string.computing_size) .setComputingString(R.string.computing_size)
.setErrorString(R.string.invalid_size_value) .setErrorString(R.string.invalid_size_value)
.build(); .build();
mButtonsPref = ((ActionButtonPreference) findPreference(KEY_HEADER_BUTTONS))
mClearDataButton = (Button) ((LayoutPreference) findPreference(KEY_HEADER_BUTTONS)) .setButton1Positive(false)
.findViewById(R.id.left_button); .setButton2Positive(false);
mStorageUsed = findPreference(KEY_STORAGE_USED); mStorageUsed = findPreference(KEY_STORAGE_USED);
mChangeStorageButton = (Button) ((LayoutPreference) findPreference(KEY_CHANGE_STORAGE)) mChangeStorageButton = (Button) ((LayoutPreference) findPreference(KEY_CHANGE_STORAGE))
@@ -175,10 +177,7 @@ public class AppStorageSettings extends AppInfoWithHeader
mChangeStorageButton.setOnClickListener(this); mChangeStorageButton.setOnClickListener(this);
// Cache section // Cache section
mCacheSize = findPreference(KEY_CACHE_SIZE); mButtonsPref.setButton2Text(R.string.clear_cache_btn_text);
mClearCacheButton = (Button) ((LayoutPreference) findPreference(KEY_HEADER_BUTTONS))
.findViewById(R.id.right_button);
mClearCacheButton.setText(R.string.clear_cache_btn_text);
// URI permissions section // URI permissions section
mUri = (PreferenceCategory) findPreference(KEY_URI_CATEGORY); mUri = (PreferenceCategory) findPreference(KEY_URI_CATEGORY);
@@ -188,9 +187,8 @@ public class AppStorageSettings extends AppInfoWithHeader
mClearUriButton.setOnClickListener(this); mClearUriButton.setOnClickListener(this);
} }
@Override @VisibleForTesting
public void onClick(View v) { void handleClearCacheClick() {
if (v == mClearCacheButton) {
if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) { if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) {
RestrictedLockUtils.sendShowAdminSupportDetailsIntent( RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
getActivity(), mAppsControlDisallowedAdmin); getActivity(), mAppsControlDisallowedAdmin);
@@ -201,7 +199,10 @@ public class AppStorageSettings extends AppInfoWithHeader
mMetricsFeatureProvider.action(getContext(), mMetricsFeatureProvider.action(getContext(),
MetricsEvent.ACTION_SETTINGS_CLEAR_APP_CACHE); MetricsEvent.ACTION_SETTINGS_CLEAR_APP_CACHE);
mPm.deleteApplicationCacheFiles(mPackageName, mClearCacheObserver); mPm.deleteApplicationCacheFiles(mPackageName, mClearCacheObserver);
} else if (v == mClearDataButton) { }
@VisibleForTesting
void handleClearDataClick() {
if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) { if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) {
RestrictedLockUtils.sendShowAdminSupportDetailsIntent( RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
getActivity(), mAppsControlDisallowedAdmin); getActivity(), mAppsControlDisallowedAdmin);
@@ -215,7 +216,11 @@ public class AppStorageSettings extends AppInfoWithHeader
} else { } else {
showDialogInner(DLG_CLEAR_DATA, 0); showDialogInner(DLG_CLEAR_DATA, 0);
} }
} else if (v == mChangeStorageButton && mDialogBuilder != null && !isMoveInProgress()) { }
@Override
public void onClick(View v) {
if (v == mChangeStorageButton && mDialogBuilder != null && !isMoveInProgress()) {
mDialogBuilder.show(); mDialogBuilder.show();
} else if (v == mClearUriButton) { } else if (v == mClearUriButton) {
if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) { if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) {
@@ -296,20 +301,23 @@ public class AppStorageSettings extends AppInfoWithHeader
if ((!appHasSpaceManagementUI && appRestrictsClearingData) if ((!appHasSpaceManagementUI && appRestrictsClearingData)
|| !isManageSpaceActivityAvailable) { || !isManageSpaceActivityAvailable) {
mClearDataButton.setText(R.string.clear_user_data_text); mButtonsPref
mClearDataButton.setEnabled(false); .setButton1Text(R.string.clear_user_data_text)
.setButton1Enabled(false);
mCanClearData = false; mCanClearData = false;
} else { } else {
if (appHasSpaceManagementUI) { if (appHasSpaceManagementUI) {
mClearDataButton.setText(R.string.manage_space_text); mButtonsPref.setButton1Text(R.string.manage_space_text);
} else { } else {
mClearDataButton.setText(R.string.clear_user_data_text); mButtonsPref.setButton1Text(R.string.clear_user_data_text);
} }
mClearDataButton.setOnClickListener(this); mButtonsPref
.setButton1Text(R.string.clear_user_data_text)
.setButton1OnClickListener(v -> handleClearDataClick());
} }
if (mAppsControlDisallowedBySystem) { if (mAppsControlDisallowedBySystem) {
mClearDataButton.setEnabled(false); mButtonsPref.setButton1Enabled(false);
} }
} }
@@ -349,7 +357,7 @@ public class AppStorageSettings extends AppInfoWithHeader
*/ */
private void initiateClearUserData() { private void initiateClearUserData() {
mMetricsFeatureProvider.action(getContext(), MetricsEvent.ACTION_SETTINGS_CLEAR_APP_DATA); mMetricsFeatureProvider.action(getContext(), MetricsEvent.ACTION_SETTINGS_CLEAR_APP_DATA);
mClearDataButton.setEnabled(false); mButtonsPref.setButton1Enabled(false);
// Invoke uninstall or clear user data based on sysPackage // Invoke uninstall or clear user data based on sysPackage
String packageName = mAppEntry.info.packageName; String packageName = mAppEntry.info.packageName;
Log.i(TAG, "Clearing user data for package : " + packageName); Log.i(TAG, "Clearing user data for package : " + packageName);
@@ -364,7 +372,7 @@ public class AppStorageSettings extends AppInfoWithHeader
Log.i(TAG, "Couldnt clear application user data for package:" + packageName); Log.i(TAG, "Couldnt clear application user data for package:" + packageName);
showDialogInner(DLG_CANNOT_CLEAR_DATA, 0); showDialogInner(DLG_CANNOT_CLEAR_DATA, 0);
} else { } else {
mClearDataButton.setText(R.string.recompute_size); mButtonsPref.setButton1Text(R.string.recompute_size);
} }
} }
@@ -375,12 +383,12 @@ public class AppStorageSettings extends AppInfoWithHeader
private void processClearMsg(Message msg) { private void processClearMsg(Message msg) {
int result = msg.arg1; int result = msg.arg1;
String packageName = mAppEntry.info.packageName; String packageName = mAppEntry.info.packageName;
mClearDataButton.setText(R.string.clear_user_data_text); mButtonsPref.setButton1Text(R.string.clear_user_data_text);
if (result == OP_SUCCESSFUL) { if (result == OP_SUCCESSFUL) {
Log.i(TAG, "Cleared user data for package : " + packageName); Log.i(TAG, "Cleared user data for package : " + packageName);
updateSize(); updateSize();
} else { } else {
mClearDataButton.setEnabled(true); mButtonsPref.setButton1Enabled(true);
} }
} }
@@ -482,7 +490,7 @@ public class AppStorageSettings extends AppInfoWithHeader
.setMessage(getActivity().getText(R.string.clear_failed_dlg_text)) .setMessage(getActivity().getText(R.string.clear_failed_dlg_text))
.setNeutralButton(R.string.dlg_ok, new DialogInterface.OnClickListener() { .setNeutralButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
mClearDataButton.setEnabled(false); mButtonsPref.setButton1Enabled(false);
//force to recompute changed value //force to recompute changed value
setIntentAndFinish(false, false); setIntentAndFinish(false, false);
} }
@@ -528,7 +536,8 @@ public class AppStorageSettings extends AppInfoWithHeader
getLoaderManager().restartLoader(1, Bundle.EMPTY, this); getLoaderManager().restartLoader(1, Bundle.EMPTY, this);
} }
private void updateUiWithSize(AppStorageStats result) { @VisibleForTesting
void updateUiWithSize(AppStorageStats result) {
if (mCacheCleared) { if (mCacheCleared) {
mSizeController.setCacheCleared(true); mSizeController.setCacheCleared(true);
} }
@@ -539,29 +548,26 @@ public class AppStorageSettings extends AppInfoWithHeader
mSizeController.updateUi(getContext()); mSizeController.updateUi(getContext());
if (result == null) { if (result == null) {
mClearDataButton.setEnabled(false); mButtonsPref.setButton1Enabled(false).setButton2Enabled(false);
mClearCacheButton.setEnabled(false);
} else { } else {
long codeSize = result.getCodeBytes();
long cacheSize = result.getCacheBytes(); long cacheSize = result.getCacheBytes();
long dataSize = result.getDataBytes() - cacheSize; long dataSize = result.getDataBytes() - cacheSize;
if (dataSize <= 0 || !mCanClearData || mDataCleared) { if (dataSize <= 0 || !mCanClearData || mDataCleared) {
mClearDataButton.setEnabled(false); mButtonsPref.setButton1Enabled(false);
} else { } else {
mClearDataButton.setEnabled(true); mButtonsPref.setButton1Enabled(true)
mClearDataButton.setOnClickListener(this); .setButton1OnClickListener(v -> handleClearDataClick());
} }
if (cacheSize <= 0 || mCacheCleared) { if (cacheSize <= 0 || mCacheCleared) {
mClearCacheButton.setEnabled(false); mButtonsPref.setButton2Enabled(false);
} else { } else {
mClearCacheButton.setEnabled(true); mButtonsPref.setButton2Enabled(true)
mClearCacheButton.setOnClickListener(this); .setButton2OnClickListener(v -> handleClearCacheClick());
} }
} }
if (mAppsControlDisallowedBySystem) { if (mAppsControlDisallowedBySystem) {
mClearCacheButton.setEnabled(false); mButtonsPref.setButton1Enabled(false).setButton2Enabled(false);
mClearDataButton.setEnabled(false);
} }
} }

View File

@@ -0,0 +1,111 @@
/*
* 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;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.view.View;
import android.widget.Button;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.ActionButtonPreference;
import com.android.settings.widget.ActionButtonPreferenceTest;
import com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class AppStorageSettingsTest {
@Mock
private AppStorageSizesController mSizesController;
private ActionButtonPreference mButtonsPref;
private AppStorageSettings mSettings;
private Button mLeftButton;
private Button mRightButton;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mLeftButton = new Button(RuntimeEnvironment.application);
mRightButton = new Button(RuntimeEnvironment.application);
mSettings = spy(new AppStorageSettings());
mSettings.mSizeController = mSizesController;
mButtonsPref = ActionButtonPreferenceTest.createMock();
mSettings.mButtonsPref = mButtonsPref;
when(mButtonsPref.setButton1OnClickListener(any(View.OnClickListener.class)))
.thenAnswer(invocation -> {
final Object[] args = invocation.getArguments();
mLeftButton.setOnClickListener((View.OnClickListener) args[0]);
return mButtonsPref;
});
when(mButtonsPref.setButton2OnClickListener(any(View.OnClickListener.class)))
.thenAnswer(invocation -> {
final Object[] args = invocation.getArguments();
mRightButton.setOnClickListener((View.OnClickListener) args[0]);
return mButtonsPref;
});
}
@Test
public void updateUiWithSize_noAppStats_shouldDisableClearButtons() {
mSettings.updateUiWithSize(null);
verify(mSizesController).updateUi(nullable(Context.class));
verify(mButtonsPref).setButton1Enabled(false);
verify(mButtonsPref).setButton2Enabled(false);
}
@Test
public void updateUiWithSize_hasDataAndCache_shouldEnableClearButtons() {
final AppStorageStats stats = mock(AppStorageStats.class);
when(stats.getCacheBytes()).thenReturn(5000L);
when(stats.getDataBytes()).thenReturn(10000L);
doNothing().when(mSettings).handleClearCacheClick();
doNothing().when(mSettings).handleClearDataClick();
mSettings.updateUiWithSize(stats);
verify(mButtonsPref).setButton1Enabled(true);
verify(mButtonsPref).setButton2Enabled(true);
mLeftButton.performClick();
verify(mSettings).handleClearDataClick();
verify(mSettings, never()).handleClearCacheClick();
mRightButton.performClick();
verify(mSettings).handleClearDataClick();
verify(mSettings).handleClearCacheClick();
}
}