Merge "Use storage fast track to query packages in app info."

This commit is contained in:
Daniel Nishi
2017-03-01 20:54:55 +00:00
committed by Android (Google) Code Review
3 changed files with 222 additions and 74 deletions

View File

@@ -19,9 +19,11 @@ package com.android.settings.applications;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.AppGlobals; import android.app.AppGlobals;
import android.app.LoaderManager;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.Loader;
import android.content.UriPermission; import android.content.UriPermission;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageDataObserver;
@@ -52,8 +54,9 @@ import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry; import com.android.settingslib.applications.ApplicationsState.AppEntry;
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.AppStorageStats;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -64,7 +67,8 @@ import static android.content.pm.ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM; 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> {
private static final String TAG = AppStorageSettings.class.getSimpleName(); private static final String TAG = AppStorageSettings.class.getSimpleName();
//internal constants used in Handler //internal constants used in Handler
@@ -123,6 +127,7 @@ public class AppStorageSettings extends AppInfoWithHeader
private boolean mCanClearData = true; private boolean mCanClearData = true;
private boolean mHaveSizes = false; private boolean mHaveSizes = false;
private AppStorageStats mLastResult;
private long mLastCodeSize = -1; private long mLastCodeSize = -1;
private long mLastDataSize = -1; private long mLastDataSize = -1;
private long mLastExternalCodeSize = -1; private long mLastExternalCodeSize = -1;
@@ -139,6 +144,7 @@ public class AppStorageSettings extends AppInfoWithHeader
private VolumeInfo[] mCandidates; private VolumeInfo[] mCandidates;
private AlertDialog.Builder mDialogBuilder; private AlertDialog.Builder mDialogBuilder;
private ApplicationInfo mInfo;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@@ -152,7 +158,7 @@ public class AppStorageSettings extends AppInfoWithHeader
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
mState.requestSize(mPackageName, mUserId); updateSize();
} }
private void setupViews() { private void setupViews() {
@@ -266,79 +272,13 @@ public class AppStorageSettings extends AppInfoWithHeader
return Formatter.formatFileSize(getActivity(), size); return Formatter.formatFileSize(getActivity(), size);
} }
private void refreshSizeInfo() {
if (mAppEntry.size == ApplicationsState.SIZE_INVALID
|| mAppEntry.size == ApplicationsState.SIZE_UNKNOWN) {
mLastCodeSize = mLastDataSize = mLastCacheSize = mLastTotalSize = -1;
if (!mHaveSizes) {
mAppSize.setSummary(mComputingStr);
mDataSize.setSummary(mComputingStr);
mCacheSize.setSummary(mComputingStr);
mTotalSize.setSummary(mComputingStr);
}
mClearDataButton.setEnabled(false);
mClearCacheButton.setEnabled(false);
} else {
mHaveSizes = true;
long codeSize = mAppEntry.codeSize;
long dataSize = mAppEntry.dataSize;
if (Environment.isExternalStorageEmulated()) {
codeSize += mAppEntry.externalCodeSize;
dataSize += mAppEntry.externalDataSize;
} else {
if (mLastExternalCodeSize != mAppEntry.externalCodeSize) {
mLastExternalCodeSize = mAppEntry.externalCodeSize;
mExternalCodeSize.setSummary(getSizeStr(mAppEntry.externalCodeSize));
}
if (mLastExternalDataSize != mAppEntry.externalDataSize) {
mLastExternalDataSize = mAppEntry.externalDataSize;
mExternalDataSize.setSummary(getSizeStr( mAppEntry.externalDataSize));
}
}
if (mLastCodeSize != codeSize) {
mLastCodeSize = codeSize;
mAppSize.setSummary(getSizeStr(codeSize));
}
if (mLastDataSize != dataSize) {
mLastDataSize = dataSize;
mDataSize.setSummary(getSizeStr(dataSize));
}
long cacheSize = mAppEntry.cacheSize + mAppEntry.externalCacheSize;
if (mLastCacheSize != cacheSize) {
mLastCacheSize = cacheSize;
mCacheSize.setSummary(getSizeStr(cacheSize));
}
if (mLastTotalSize != mAppEntry.size) {
mLastTotalSize = mAppEntry.size;
mTotalSize.setSummary(getSizeStr(mAppEntry.size));
}
if ((mAppEntry.dataSize+ mAppEntry.externalDataSize) <= 0 || !mCanClearData) {
mClearDataButton.setEnabled(false);
} else {
mClearDataButton.setEnabled(true);
mClearDataButton.setOnClickListener(this);
}
if (cacheSize <= 0) {
mClearCacheButton.setEnabled(false);
} else {
mClearCacheButton.setEnabled(true);
mClearCacheButton.setOnClickListener(this);
}
}
if (mAppsControlDisallowedBySystem) {
mClearCacheButton.setEnabled(false);
mClearDataButton.setEnabled(false);
}
}
@Override @Override
protected boolean refreshUi() { protected boolean refreshUi() {
retrieveAppEntry(); retrieveAppEntry();
if (mAppEntry == null) { if (mAppEntry == null) {
return false; return false;
} }
refreshSizeInfo(); updateUiWithSize(mLastResult);
refreshGrantedUriPermissions(); refreshGrantedUriPermissions();
final VolumeInfo currentVol = getActivity().getPackageManager() final VolumeInfo currentVol = getActivity().getPackageManager()
@@ -454,7 +394,7 @@ public class AppStorageSettings extends AppInfoWithHeader
mClearDataButton.setText(R.string.clear_user_data_text); mClearDataButton.setText(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);
mState.requestSize(mPackageName, mUserId); updateSize();
} else { } else {
mClearDataButton.setEnabled(true); mClearDataButton.setEnabled(true);
} }
@@ -570,8 +510,91 @@ public class AppStorageSettings extends AppInfoWithHeader
@Override @Override
public void onPackageSizeChanged(String packageName) { public void onPackageSizeChanged(String packageName) {
if (packageName.equals(mAppEntry.info.packageName)) { }
refreshSizeInfo();
@Override
public Loader<AppStorageStats> onCreateLoader(int id, Bundle args) {
Context context = getContext();
return new FetchPackageStorageAsyncLoader(
context, new StorageStatsSource(context), mInfo, UserHandle.of(mUserId));
}
@Override
public void onLoadFinished(Loader<AppStorageStats> loader, AppStorageStats result) {
mLastResult = result;
updateUiWithSize(result);
}
@Override
public void onLoaderReset(Loader<AppStorageStats> loader) {
}
private void updateSize() {
PackageManager packageManager = getPackageManager();
try {
mInfo = packageManager.getApplicationInfo(mPackageName, 0);
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Could not find package", e);
}
if (mInfo == null) {
return;
}
getLoaderManager().restartLoader(1, Bundle.EMPTY, this);
}
private void updateUiWithSize(AppStorageStats result) {
if (result == null) {
mLastCodeSize = mLastDataSize = mLastCacheSize = mLastTotalSize = -1;
if (!mHaveSizes) {
mAppSize.setSummary(mComputingStr);
mDataSize.setSummary(mComputingStr);
mCacheSize.setSummary(mComputingStr);
mTotalSize.setSummary(mComputingStr);
}
mClearDataButton.setEnabled(false);
mClearCacheButton.setEnabled(false);
} else {
mHaveSizes = true;
long codeSize = result.getCodeBytes();
long dataSize = result.getDataBytes();
if (mLastCodeSize != codeSize) {
mLastCodeSize = codeSize;
mAppSize.setSummary(getSizeStr(codeSize));
}
if (mLastDataSize != dataSize) {
mLastDataSize = dataSize;
mDataSize.setSummary(getSizeStr(dataSize));
}
long cacheSize = result.getCacheBytes();
if (mLastCacheSize != cacheSize) {
mLastCacheSize = cacheSize;
mCacheSize.setSummary(getSizeStr(cacheSize));
}
long totalSize = codeSize + dataSize + cacheSize;
if (mLastTotalSize != totalSize) {
mLastTotalSize = totalSize;
mTotalSize.setSummary(getSizeStr(totalSize));
}
if (dataSize <= 0 || !mCanClearData) {
mClearDataButton.setEnabled(false);
} else {
mClearDataButton.setEnabled(true);
mClearDataButton.setOnClickListener(this);
}
if (cacheSize <= 0) {
mClearCacheButton.setEnabled(false);
} else {
mClearCacheButton.setEnabled(true);
mClearCacheButton.setOnClickListener(this);
}
}
if (mAppsControlDisallowedBySystem) {
mClearCacheButton.setEnabled(false);
mClearDataButton.setEnabled(false);
} }
} }
@@ -586,7 +609,7 @@ public class AppStorageSettings extends AppInfoWithHeader
break; break;
case MSG_CLEAR_CACHE: case MSG_CLEAR_CACHE:
// Refresh size info // Refresh size info
mState.requestSize(mPackageName, mUserId); updateSize();
break; break;
} }
} }

View File

@@ -0,0 +1,53 @@
/*
* 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 android.annotation.NonNull;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.os.UserHandle;
import com.android.internal.util.Preconditions;
import com.android.settings.utils.AsyncLoader;
import com.android.settingslib.applications.StorageStatsSource;
import com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
/**
* Fetches the storage stats using the StorageStatsManager for a given package and user tuple.
*/
public class FetchPackageStorageAsyncLoader extends AsyncLoader<AppStorageStats> {
private final StorageStatsSource mSource;
private final ApplicationInfo mInfo;
private final UserHandle mUser;
public FetchPackageStorageAsyncLoader(Context context, @NonNull StorageStatsSource source,
@NonNull ApplicationInfo info, @NonNull UserHandle user) {
super(context);
mSource = Preconditions.checkNotNull(source);
mInfo = info;
mUser = user;
}
@Override
public AppStorageStats loadInBackground() {
return mSource.getStatsForPackage(mInfo.volumeUuid, mInfo.packageName, mUser);
}
@Override
protected void onDiscardResult(AppStorageStats result) {
}
}

View File

@@ -0,0 +1,72 @@
/*
* 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 com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.os.UserHandle;
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settingslib.applications.StorageStatsSource;
import com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class FetchPackageStorageAsyncLoaderTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
@Mock
private StorageStatsSource mSource;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void worksForValidPackageNameAndUid() {
AppStorageStats stats = mock(AppStorageStats.class);
when(stats.getCodeBytes()).thenReturn(1L);
when(stats.getDataBytes()).thenReturn(2L);
when(stats.getCacheBytes()).thenReturn(3L);
when(mSource.getStatsForPackage(anyString(), anyString(), any(UserHandle.class)))
.thenReturn(stats);
ApplicationInfo info = new ApplicationInfo();
info.packageName = "com.test.package";
FetchPackageStorageAsyncLoader task = new FetchPackageStorageAsyncLoader(
mContext, mSource, info, new UserHandle(0));
assertThat(task.loadInBackground()).isEqualTo(stats);
}
}