From 3965e0207cef1200834911c4ab61c992e7c478a6 Mon Sep 17 00:00:00 2001 From: Salvador Martinez Date: Wed, 1 Feb 2017 17:17:49 -0800 Subject: [PATCH] moved shared classes from settings to settingslib These classes are needed in StorageManager but are used by settings so I moved them into settingsLib. Test: ?? Investigating Bug: 34768442 Change-Id: I59c2f6c714d8e282d4781899127c22f8537e81af --- .../applications/PackageManagerWrapper.java | 126 ++++++++++++++++++ .../PackageManagerWrapperImpl.java | 116 ++++++++++++++++ .../applications/StorageStatsSource.java | 117 ++++++++++++++++ 3 files changed, 359 insertions(+) create mode 100644 packages/SettingsLib/src/com/android/settingslib/applications/PackageManagerWrapper.java create mode 100644 packages/SettingsLib/src/com/android/settingslib/applications/PackageManagerWrapperImpl.java create mode 100644 packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/PackageManagerWrapper.java b/packages/SettingsLib/src/com/android/settingslib/applications/PackageManagerWrapper.java new file mode 100644 index 0000000000000..caa79297539d5 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/applications/PackageManagerWrapper.java @@ -0,0 +1,126 @@ +/* + * 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.settingslib.applications; + +import android.content.ComponentName; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ResolveInfo; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; + +import java.util.List; + +/** + * This interface replicates a subset of the android.content.pm.PackageManager (PM). The interface + * exists so that we can use a thin wrapper around the PM in production code and a mock in tests. + * We cannot directly mock or shadow the PM, because some of the methods we rely on are newer than + * the API version supported by Robolectric. + */ +public interface PackageManagerWrapper { + + /** + * Returns the real {@code PackageManager} object. + */ + PackageManager getPackageManager(); + + /** + * Calls {@code PackageManager.getInstalledApplicationsAsUser()}. + * + * @see android.content.pm.PackageManager#getInstalledApplicationsAsUser + */ + List getInstalledApplicationsAsUser(int flags, int userId); + + /** + * Calls {@code PackageManager.hasSystemFeature()}. + * + * @see android.content.pm.PackageManager#hasSystemFeature + */ + boolean hasSystemFeature(String name); + + /** + * Calls {@code PackageManager.queryIntentActivitiesAsUser()}. + * + * @see android.content.pm.PackageManager#queryIntentActivitiesAsUser + */ + List queryIntentActivitiesAsUser(Intent intent, int flags, int userId); + + /** + * Calls {@code PackageManager.getInstallReason()}. + * + * @see android.content.pm.PackageManager#getInstallReason + */ + int getInstallReason(String packageName, UserHandle user); + + /** + * Calls {@code PackageManager.getApplicationInfoAsUser} + */ + ApplicationInfo getApplicationInfoAsUser(String packageName, int i, int userId) + throws PackageManager.NameNotFoundException; + + /** + * Calls {@code PackageManager.setDefaultBrowserPackageNameAsUser} + */ + boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId); + + /** + * Calls {@code PackageManager.getDefaultBrowserPackageNameAsUser} + */ + String getDefaultBrowserPackageNameAsUser(int userId); + + /** + * Calls {@code PackageManager.getHomeActivities} + */ + ComponentName getHomeActivities(List homeActivities); + + /** + * Calls {@code PackageManager.queryIntentServicesAsUser} + */ + List queryIntentServicesAsUser(Intent intent, int i, int user); + + /** + * Calls {@code PackageManager.replacePreferredActivity} + */ + void replacePreferredActivity(IntentFilter homeFilter, int matchCategoryEmpty, + ComponentName[] componentNames, ComponentName component); + + /** + * Gets information about a particular package from the package manager. + * @param packageName The name of the package we would like information about. + * @param i additional options flags. see javadoc for {@link PackageManager#getPackageInfo(String, int)} + * @return The PackageInfo for the requested package + * @throws NameNotFoundException + */ + PackageInfo getPackageInfo(String packageName, int i) throws NameNotFoundException; + + /** + * Retrieves the icon associated with this particular set of ApplicationInfo + * @param info The ApplicationInfo to retrieve the icon for + * @return The icon as a drawable. + */ + Drawable getUserBadgedIcon(ApplicationInfo info); + + /** + * Retrieves the label associated with the particular set of ApplicationInfo + * @param app The ApplicationInfo to retrieve the label for + * @return the label as a CharSequence + */ + CharSequence loadLabel(ApplicationInfo app); +} diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/PackageManagerWrapperImpl.java b/packages/SettingsLib/src/com/android/settingslib/applications/PackageManagerWrapperImpl.java new file mode 100644 index 0000000000000..9b2cd7cb6b28e --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/applications/PackageManagerWrapperImpl.java @@ -0,0 +1,116 @@ +/* + * 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.settingslib.applications; + +import android.content.ComponentName; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ResolveInfo; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; + +import java.util.List; + +/** + * A thin wrapper class that simplifies testing by putting a mockable layer between the application + * and the PackageManager. This class only provides access to the minimum number of functions from + * the PackageManager needed for DeletionHelper to work. + */ +public class PackageManagerWrapperImpl implements PackageManagerWrapper { + + private final PackageManager mPm; + + public PackageManagerWrapperImpl(PackageManager pm) { + mPm = pm; + } + + @Override + public PackageManager getPackageManager() { + return mPm; + } + + @Override + public List getInstalledApplicationsAsUser(int flags, int userId) { + return mPm.getInstalledApplicationsAsUser(flags, userId); + } + + @Override + public boolean hasSystemFeature(String name) { + return mPm.hasSystemFeature(name); + } + + @Override + public List queryIntentActivitiesAsUser(Intent intent, int flags, int userId) { + return mPm.queryIntentActivitiesAsUser(intent, flags, userId); + } + + @Override + public int getInstallReason(String packageName, UserHandle user) { + return mPm.getInstallReason(packageName, user); + } + + @Override + public ApplicationInfo getApplicationInfoAsUser(String packageName, int i, int userId) + throws PackageManager.NameNotFoundException { + return mPm.getApplicationInfoAsUser(packageName, i, userId); + } + + @Override + public boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) { + return mPm.setDefaultBrowserPackageNameAsUser(packageName, userId); + } + + @Override + public String getDefaultBrowserPackageNameAsUser(int userId) { + return mPm.getDefaultBrowserPackageNameAsUser(userId); + } + + @Override + public ComponentName getHomeActivities(List homeActivities) { + return mPm.getHomeActivities(homeActivities); + } + + @Override + public List queryIntentServicesAsUser(Intent intent, int i, int user) { + return mPm.queryIntentServicesAsUser(intent, i, user); + } + + @Override + public void replacePreferredActivity(IntentFilter homeFilter, int matchCategoryEmpty, + ComponentName[] componentNames, ComponentName component) { + mPm.replacePreferredActivity(homeFilter, matchCategoryEmpty, componentNames, component); + } + + @Override + public PackageInfo getPackageInfo(String packageName, int i) throws NameNotFoundException { + return mPm.getPackageInfo(packageName, i); + } + + @Override + public Drawable getUserBadgedIcon(ApplicationInfo info) { + return mPm.getUserBadgedIcon(mPm.loadUnbadgedItemIcon(info, info), + new UserHandle(UserHandle.getUserId(info.uid))); + } + + @Override + public CharSequence loadLabel(ApplicationInfo app) { + return app.loadLabel(mPm); + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java new file mode 100644 index 0000000000000..acb0650ff71e7 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java @@ -0,0 +1,117 @@ +/* + * 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.settingslib.applications; + +import android.app.usage.StorageStats; +import android.app.usage.StorageStatsManager; +import android.content.Context; +import android.os.UserHandle; + +/** + * StorageStatsSource wraps the StorageStatsManager for testability purposes. + */ +public class StorageStatsSource { + private StorageStatsManager mStorageStatsManager; + + public StorageStatsSource(Context context) { + mStorageStatsManager = context.getSystemService(StorageStatsManager.class); + } + + public StorageStatsSource.ExternalStorageStats getExternalStorageStats(String volumeUuid, UserHandle user) { + return new StorageStatsSource.ExternalStorageStats( + mStorageStatsManager.queryExternalStatsForUser(volumeUuid, user)); + } + + public StorageStatsSource.AppStorageStats getStatsForUid(String volumeUuid, int uid) { + return new StorageStatsSource.AppStorageStatsImpl(mStorageStatsManager.queryStatsForUid(volumeUuid, uid)); + } + + /** + * Static class that provides methods for querying the amount of external storage available as + * well as breaking it up into several media types. + */ + public static class ExternalStorageStats { + public long totalBytes; + public long audioBytes; + public long videoBytes; + public long imageBytes; + + /** + * Convenience method for testing. + */ + public ExternalStorageStats(long totalBytes, long audioBytes, long videoBytes, + long imageBytes) { + this.totalBytes = totalBytes; + this.audioBytes = audioBytes; + this.videoBytes = videoBytes; + this.imageBytes = imageBytes; + } + + /** + * Creates an ExternalStorageStats from the system version of ExternalStorageStats. They are + * identical other than the utility method created for test purposes. + * @param stats The stats to copy to wrap. + */ + public ExternalStorageStats(android.app.usage.ExternalStorageStats stats) { + totalBytes = stats.getTotalBytes(); + audioBytes = stats.getAudioBytes(); + videoBytes = stats.getVideoBytes(); + imageBytes = stats.getImageBytes(); + } + } + + /** + * Interface that exists to simplify testing. The platform {@link StorageStats} is too new and + * robolectric cannot see it. It simply wraps a StorageStats object and forwards method calls + * to the real object + */ + public interface AppStorageStats { + long getCodeBytes(); + long getDataBytes(); + long getCacheBytes(); + long getTotalBytes(); + } + + /** + * Simple implementation of AppStorageStats that will allow you to query the StorageStats object + * passed in for storage information about an app. + */ + public static class AppStorageStatsImpl implements + StorageStatsSource.AppStorageStats { + private StorageStats mStats; + + public AppStorageStatsImpl(StorageStats stats) { + mStats = stats; + } + + public long getCodeBytes() { + return mStats.getCodeBytes(); + } + + public long getDataBytes() { + return mStats.getDataBytes(); + } + + public long getCacheBytes() { + return mStats.getCacheBytes(); + } + + public long getTotalBytes() { + return mStats.getCacheBytes() + mStats.getCodeBytes() + mStats.getDataBytes(); + } + } +} \ No newline at end of file