Merge "Add a music apps view to the Storage Settings."
This commit is contained in:
@@ -8165,6 +8165,11 @@
|
|||||||
<!-- Title of games app storage screen [CHAR LIMIT=30] -->
|
<!-- Title of games app storage screen [CHAR LIMIT=30] -->
|
||||||
<string name="game_storage_settings">Games</string>
|
<string name="game_storage_settings">Games</string>
|
||||||
|
|
||||||
|
<!-- Title for audio files preference. [CHAR LIMIT=50] -->
|
||||||
|
<string name="audio_files_title">Audio files</string>
|
||||||
|
<!-- Title for the Audio storage view. [CHAR LIMIT=50] -->
|
||||||
|
<string name="audio_storage_title">Music</string>
|
||||||
|
|
||||||
<!-- UI webview setting: WebView uninstalled-for-user explanatory text [CHAR LIMIT=30] -->
|
<!-- UI webview setting: WebView uninstalled-for-user explanatory text [CHAR LIMIT=30] -->
|
||||||
<string name="webview_uninstalled_for_user">Uninstalled for user <xliff:g id="user" example="John Doe">%s</xliff:g>\n</string>
|
<string name="webview_uninstalled_for_user">Uninstalled for user <xliff:g id="user" example="John Doe">%s</xliff:g>\n</string>
|
||||||
<!-- UI webview setting: WebView disabled-for-user explanatory text [CHAR LIMIT=30] -->
|
<!-- UI webview setting: WebView disabled-for-user explanatory text [CHAR LIMIT=30] -->
|
||||||
|
@@ -25,6 +25,7 @@ import android.app.Fragment;
|
|||||||
import android.app.IActivityManager;
|
import android.app.IActivityManager;
|
||||||
import android.app.KeyguardManager;
|
import android.app.KeyguardManager;
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -1224,4 +1225,24 @@ public final class Utils extends com.android.settingslib.Utils {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Launches an intent which may optionally have a user id defined.
|
||||||
|
* @param fragment Fragment to use to launch the activity.
|
||||||
|
* @param intent Intent to launch.
|
||||||
|
*/
|
||||||
|
public static void launchIntent(Fragment fragment, Intent intent) {
|
||||||
|
try {
|
||||||
|
final int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, -1);
|
||||||
|
|
||||||
|
if (userId == -1) {
|
||||||
|
fragment.startActivity(intent);
|
||||||
|
} else {
|
||||||
|
fragment.getActivity().startActivityAsUser(intent, new UserHandle(userId));
|
||||||
|
}
|
||||||
|
} catch (ActivityNotFoundException e) {
|
||||||
|
Log.w(TAG, "No activity found for " + intent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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.app.Fragment;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FileViewHolderController handles adapting the AppViewHolder to work as a general purpose
|
||||||
|
* storage categorization preference in the ManageApplications view.
|
||||||
|
*/
|
||||||
|
public interface FileViewHolderController {
|
||||||
|
/**
|
||||||
|
* Begins a synchronous query for statistics for the files.
|
||||||
|
*/
|
||||||
|
void queryStats();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the preference should be shown.
|
||||||
|
*/
|
||||||
|
boolean shouldShow();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the view within an AppViewHolder.
|
||||||
|
* @param holder The holder to use to initialize.
|
||||||
|
*/
|
||||||
|
void setupView(AppViewHolder holder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the behavior when the view is clicked.
|
||||||
|
* @param fragment Fragment where the click originated.
|
||||||
|
*/
|
||||||
|
void onClick(Fragment fragment);
|
||||||
|
}
|
@@ -17,6 +17,7 @@
|
|||||||
package com.android.settings.applications;
|
package com.android.settings.applications;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.usage.StorageStatsManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
@@ -32,6 +33,7 @@ import android.os.UserHandle;
|
|||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.preference.PreferenceFrameLayout;
|
import android.preference.PreferenceFrameLayout;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.text.format.Formatter;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@@ -71,6 +73,7 @@ import com.android.settings.applications.AppStateInstallAppsBridge.InstallAppsSt
|
|||||||
import com.android.settings.applications.AppStateUsageBridge.UsageState;
|
import com.android.settings.applications.AppStateUsageBridge.UsageState;
|
||||||
import com.android.settings.core.InstrumentedPreferenceFragment;
|
import com.android.settings.core.InstrumentedPreferenceFragment;
|
||||||
import com.android.settings.dashboard.SummaryLoader;
|
import com.android.settings.dashboard.SummaryLoader;
|
||||||
|
import com.android.settings.deviceinfo.storage.StorageStatsSource;
|
||||||
import com.android.settings.fuelgauge.HighPowerDetail;
|
import com.android.settings.fuelgauge.HighPowerDetail;
|
||||||
import com.android.settings.fuelgauge.PowerWhitelistBackend;
|
import com.android.settings.fuelgauge.PowerWhitelistBackend;
|
||||||
import com.android.settings.notification.AppNotificationSettings;
|
import com.android.settings.notification.AppNotificationSettings;
|
||||||
@@ -108,6 +111,7 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
// Used for storage only.
|
// Used for storage only.
|
||||||
public static final String EXTRA_VOLUME_UUID = "volumeUuid";
|
public static final String EXTRA_VOLUME_UUID = "volumeUuid";
|
||||||
public static final String EXTRA_VOLUME_NAME = "volumeName";
|
public static final String EXTRA_VOLUME_NAME = "volumeName";
|
||||||
|
public static final String EXTRA_STORAGE_TYPE = "storageType";
|
||||||
|
|
||||||
private static final String EXTRA_SORT_ORDER = "sortOrder";
|
private static final String EXTRA_SORT_ORDER = "sortOrder";
|
||||||
private static final String EXTRA_SHOW_SYSTEM = "showSystem";
|
private static final String EXTRA_SHOW_SYSTEM = "showSystem";
|
||||||
@@ -140,6 +144,10 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
public static final int FILTER_APPS_WRITE_SETTINGS = 10;
|
public static final int FILTER_APPS_WRITE_SETTINGS = 10;
|
||||||
public static final int FILTER_APPS_INSTALL_SOURCES = 12;
|
public static final int FILTER_APPS_INSTALL_SOURCES = 12;
|
||||||
|
|
||||||
|
// Storage types. Used to determine what the extra item in the list of preferences is.
|
||||||
|
public static final int STORAGE_TYPE_DEFAULT = 0;
|
||||||
|
public static final int STORAGE_TYPE_MUSIC = 1;
|
||||||
|
|
||||||
// This is the string labels for the filter modes above, the order must be kept in sync.
|
// This is the string labels for the filter modes above, the order must be kept in sync.
|
||||||
public static final int[] FILTER_LABELS = new int[]{
|
public static final int[] FILTER_LABELS = new int[]{
|
||||||
R.string.high_power_filter_on, // High power whitelist, on
|
R.string.high_power_filter_on, // High power whitelist, on
|
||||||
@@ -227,6 +235,7 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
private ResetAppsHelper mResetAppsHelper;
|
private ResetAppsHelper mResetAppsHelper;
|
||||||
private String mVolumeUuid;
|
private String mVolumeUuid;
|
||||||
private String mVolumeName;
|
private String mVolumeName;
|
||||||
|
private int mStorageType;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
@@ -250,6 +259,7 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
if (args != null && args.containsKey(EXTRA_VOLUME_UUID)) {
|
if (args != null && args.containsKey(EXTRA_VOLUME_UUID)) {
|
||||||
mVolumeUuid = args.getString(EXTRA_VOLUME_UUID);
|
mVolumeUuid = args.getString(EXTRA_VOLUME_UUID);
|
||||||
mVolumeName = args.getString(EXTRA_VOLUME_NAME);
|
mVolumeName = args.getString(EXTRA_VOLUME_NAME);
|
||||||
|
mStorageType = args.getInt(EXTRA_STORAGE_TYPE, STORAGE_TYPE_DEFAULT);
|
||||||
mListType = LIST_TYPE_STORAGE;
|
mListType = LIST_TYPE_STORAGE;
|
||||||
} else {
|
} else {
|
||||||
// No volume selected, display a normal list, sorted by size.
|
// No volume selected, display a normal list, sorted by size.
|
||||||
@@ -316,6 +326,13 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
mApplications.mHasReceivedBridgeCallback =
|
mApplications.mHasReceivedBridgeCallback =
|
||||||
savedInstanceState.getBoolean(EXTRA_HAS_BRIDGE, false);
|
savedInstanceState.getBoolean(EXTRA_HAS_BRIDGE, false);
|
||||||
}
|
}
|
||||||
|
if (mStorageType == STORAGE_TYPE_MUSIC) {
|
||||||
|
Context context = getContext();
|
||||||
|
mApplications.setExtraViewController(new MusicViewHolderController(
|
||||||
|
context,
|
||||||
|
new StorageStatsSource(context),
|
||||||
|
mVolumeUuid));
|
||||||
|
}
|
||||||
mListView.setAdapter(mApplications);
|
mListView.setAdapter(mApplications);
|
||||||
mListView.setRecyclerListener(mApplications);
|
mListView.setRecyclerListener(mApplications);
|
||||||
mListView.setFastScrollEnabled(isFastScrollEnabled());
|
mListView.setFastScrollEnabled(isFastScrollEnabled());
|
||||||
@@ -361,7 +378,11 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
mFilterAdapter.enableFilter(FILTER_APPS_POWER_WHITELIST_ALL);
|
mFilterAdapter.enableFilter(FILTER_APPS_POWER_WHITELIST_ALL);
|
||||||
}
|
}
|
||||||
if (mListType == LIST_TYPE_STORAGE) {
|
if (mListType == LIST_TYPE_STORAGE) {
|
||||||
mApplications.setOverrideFilter(new VolumeFilter(mVolumeUuid));
|
AppFilter filter = new VolumeFilter(mVolumeUuid);
|
||||||
|
if (mStorageType == STORAGE_TYPE_MUSIC) {
|
||||||
|
filter = new CompoundFilter(ApplicationsState.FILTER_AUDIO, filter);
|
||||||
|
}
|
||||||
|
mApplications.setOverrideFilter(filter);
|
||||||
}
|
}
|
||||||
if (mListType == LIST_TYPE_GAMES) {
|
if (mListType == LIST_TYPE_GAMES) {
|
||||||
mApplications.setOverrideFilter(ApplicationsState.FILTER_GAMES);
|
mApplications.setOverrideFilter(ApplicationsState.FILTER_GAMES);
|
||||||
@@ -626,11 +647,17 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
if (mApplications != null && mApplications.getCount() > position) {
|
if (mApplications == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mApplications.getApplicationCount() > position) {
|
||||||
ApplicationsState.AppEntry entry = mApplications.getAppEntry(position);
|
ApplicationsState.AppEntry entry = mApplications.getAppEntry(position);
|
||||||
mCurrentPkgName = entry.info.packageName;
|
mCurrentPkgName = entry.info.packageName;
|
||||||
mCurrentUid = entry.info.uid;
|
mCurrentUid = entry.info.uid;
|
||||||
startApplicationDetailsActivity();
|
startApplicationDetailsActivity();
|
||||||
|
} else {
|
||||||
|
mApplications.mExtraViewController.onClick(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -769,6 +796,7 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
private AppFilter mOverrideFilter;
|
private AppFilter mOverrideFilter;
|
||||||
private boolean mHasReceivedLoadEntries;
|
private boolean mHasReceivedLoadEntries;
|
||||||
private boolean mHasReceivedBridgeCallback;
|
private boolean mHasReceivedBridgeCallback;
|
||||||
|
private FileViewHolderController mExtraViewController;
|
||||||
|
|
||||||
// These two variables are used to remember and restore the last scroll position when this
|
// These two variables are used to remember and restore the last scroll position when this
|
||||||
// fragment is paused. We need this special handling because app entries are added gradually
|
// fragment is paused. We need this special handling because app entries are added gradually
|
||||||
@@ -839,6 +867,10 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
rebuild(true);
|
rebuild(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setExtraViewController(FileViewHolderController extraViewController) {
|
||||||
|
mExtraViewController = extraViewController;
|
||||||
|
}
|
||||||
|
|
||||||
public void resume(int sort) {
|
public void resume(int sort) {
|
||||||
if (DEBUG) Log.i(TAG, "Resume! mResumed=" + mResumed);
|
if (DEBUG) Log.i(TAG, "Resume! mResumed=" + mResumed);
|
||||||
if (!mResumed) {
|
if (!mResumed) {
|
||||||
@@ -889,7 +921,6 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
// Don't rebuild the list until all the app entries are loaded.
|
// Don't rebuild the list until all the app entries are loaded.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (DEBUG) Log.i(TAG, "Rebuilding app list...");
|
|
||||||
ApplicationsState.AppFilter filterObj;
|
ApplicationsState.AppFilter filterObj;
|
||||||
Comparator<AppEntry> comparatorObj;
|
Comparator<AppEntry> comparatorObj;
|
||||||
boolean emulated = Environment.isExternalStorageEmulated();
|
boolean emulated = Environment.isExternalStorageEmulated();
|
||||||
@@ -924,8 +955,12 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
comparatorObj = ApplicationsState.ALPHA_COMPARATOR;
|
comparatorObj = ApplicationsState.ALPHA_COMPARATOR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
filterObj = new CompoundFilter(filterObj, ApplicationsState.FILTER_NOT_HIDE);
|
|
||||||
|
|
||||||
|
if (mExtraViewController != null) {
|
||||||
|
mExtraViewController.queryStats();
|
||||||
|
}
|
||||||
|
|
||||||
|
filterObj = new CompoundFilter(filterObj, ApplicationsState.FILTER_NOT_HIDE);
|
||||||
AppFilter finalFilterObj = filterObj;
|
AppFilter finalFilterObj = filterObj;
|
||||||
mBgHandler.post(() -> {
|
mBgHandler.post(() -> {
|
||||||
final ArrayList<AppEntry> entries = mSession.rebuild(finalFilterObj,
|
final ArrayList<AppEntry> entries = mSession.rebuild(finalFilterObj,
|
||||||
@@ -1104,6 +1139,10 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
public void onPackageSizeChanged(String packageName) {
|
public void onPackageSizeChanged(String packageName) {
|
||||||
for (int i = 0; i < mActive.size(); i++) {
|
for (int i = 0; i < mActive.size(); i++) {
|
||||||
AppViewHolder holder = (AppViewHolder) mActive.get(i).getTag();
|
AppViewHolder holder = (AppViewHolder) mActive.get(i).getTag();
|
||||||
|
ApplicationInfo info = holder.entry.info;
|
||||||
|
if (info == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (holder.entry.info.packageName.equals(packageName)) {
|
if (holder.entry.info.packageName.equals(packageName)) {
|
||||||
synchronized (holder.entry) {
|
synchronized (holder.entry) {
|
||||||
updateSummary(holder);
|
updateSummary(holder);
|
||||||
@@ -1136,10 +1175,22 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
|
if (mEntries == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int extraViewAddition =
|
||||||
|
(mExtraViewController != null && mExtraViewController.shouldShow()) ? 1 : 0;
|
||||||
|
return mEntries.size() + extraViewAddition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getApplicationCount() {
|
||||||
return mEntries != null ? mEntries.size() : 0;
|
return mEntries != null ? mEntries.size() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getItem(int position) {
|
public Object getItem(int position) {
|
||||||
|
if (position == mEntries.size()) {
|
||||||
|
return mExtraViewController;
|
||||||
|
}
|
||||||
return mEntries.get(position);
|
return mEntries.get(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1148,6 +1199,9 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getItemId(int position) {
|
public long getItemId(int position) {
|
||||||
|
if (position == mEntries.size()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
return mEntries.get(position).id;
|
return mEntries.get(position).id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1158,6 +1212,11 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnabled(int position) {
|
public boolean isEnabled(int position) {
|
||||||
|
if (position == mEntries.size() && mExtraViewController != null &&
|
||||||
|
mExtraViewController.shouldShow()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (mManageApplications.mListType != LIST_TYPE_HIGH_POWER) {
|
if (mManageApplications.mListType != LIST_TYPE_HIGH_POWER) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1172,6 +1231,11 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
convertView);
|
convertView);
|
||||||
convertView = holder.rootView;
|
convertView = holder.rootView;
|
||||||
|
|
||||||
|
// Handle the extra view if it is the last entry.
|
||||||
|
if (mEntries != null && mExtraViewController != null && position == mEntries.size()) {
|
||||||
|
mExtraViewController.setupView(holder);
|
||||||
|
convertView.setEnabled(true);
|
||||||
|
} else {
|
||||||
// Bind the data efficiently with the holder
|
// Bind the data efficiently with the holder
|
||||||
ApplicationsState.AppEntry entry = mEntries.get(position);
|
ApplicationsState.AppEntry entry = mEntries.get(position);
|
||||||
synchronized (entry) {
|
synchronized (entry) {
|
||||||
@@ -1194,9 +1258,11 @@ public class ManageApplications extends InstrumentedPreferenceFragment
|
|||||||
holder.disabled.setVisibility(View.GONE);
|
holder.disabled.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
convertView.setEnabled(isEnabled(position));
|
||||||
|
}
|
||||||
|
|
||||||
mActive.remove(convertView);
|
mActive.remove(convertView);
|
||||||
mActive.add(convertView);
|
mActive.add(convertView);
|
||||||
convertView.setEnabled(isEnabled(position));
|
|
||||||
return convertView;
|
return convertView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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.app.Fragment;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.provider.DocumentsContract;
|
||||||
|
import android.support.annotation.WorkerThread;
|
||||||
|
import android.text.format.Formatter;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.Utils;
|
||||||
|
import com.android.settings.deviceinfo.storage.StorageStatsSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MusicViewHolderController controls an Audio/Music file view in the ManageApplications view.
|
||||||
|
*/
|
||||||
|
public class MusicViewHolderController implements FileViewHolderController {
|
||||||
|
private static final String AUTHORITY_MEDIA = "com.android.providers.media.documents";
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private StorageStatsSource mSource;
|
||||||
|
private String mVolumeUuid;
|
||||||
|
private long mMusicSize;
|
||||||
|
|
||||||
|
public MusicViewHolderController(
|
||||||
|
Context context, StorageStatsSource source, String volumeUuid) {
|
||||||
|
mContext = context;
|
||||||
|
mSource = source;
|
||||||
|
mVolumeUuid = volumeUuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@WorkerThread
|
||||||
|
public void queryStats() {
|
||||||
|
mMusicSize = mSource.getExternalStorageStats(mVolumeUuid, UserHandle.CURRENT).audioBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldShow() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setupView(AppViewHolder holder) {
|
||||||
|
holder.appIcon.setImageDrawable(mContext.getDrawable(R.drawable.empty_icon));
|
||||||
|
holder.appName.setText(mContext.getText(R.string.audio_files_title));
|
||||||
|
holder.summary.setText(Formatter.formatFileSize(mContext, mMusicSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(Fragment fragment) {
|
||||||
|
Intent intent = new Intent(DocumentsContract.ACTION_BROWSE);
|
||||||
|
intent.setData(DocumentsContract.buildRootUri(AUTHORITY_MEDIA, "audio_root"));
|
||||||
|
intent.addCategory(Intent.CATEGORY_DEFAULT);
|
||||||
|
intent.putExtra(Intent.EXTRA_USER_ID, UserHandle.CURRENT);
|
||||||
|
Utils.launchIntent(fragment, intent);
|
||||||
|
}
|
||||||
|
}
|
@@ -533,7 +533,7 @@ public class PrivateVolumeSettings extends SettingsPreferenceFragment {
|
|||||||
if (intent != null) {
|
if (intent != null) {
|
||||||
intent.putExtra(Intent.EXTRA_USER_ID, userId);
|
intent.putExtra(Intent.EXTRA_USER_ID, userId);
|
||||||
|
|
||||||
launchIntent(this, intent);
|
Utils.launchIntent(this, intent);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return super.onPreferenceTreeClick(pref);
|
return super.onPreferenceTreeClick(pref);
|
||||||
@@ -670,20 +670,6 @@ public class PrivateVolumeSettings extends SettingsPreferenceFragment {
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void launchIntent(Fragment fragment, Intent intent) {
|
|
||||||
try {
|
|
||||||
final int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, -1);
|
|
||||||
|
|
||||||
if (userId == -1) {
|
|
||||||
fragment.startActivity(intent);
|
|
||||||
} else {
|
|
||||||
fragment.getActivity().startActivityAsUser(intent, new UserHandle(userId));
|
|
||||||
}
|
|
||||||
} catch (ActivityNotFoundException e) {
|
|
||||||
Log.w(TAG, "No activity found for " + intent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final StorageEventListener mStorageListener = new StorageEventListener() {
|
private final StorageEventListener mStorageListener = new StorageEventListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
|
public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
|
||||||
@@ -815,7 +801,7 @@ public class PrivateVolumeSettings extends SettingsPreferenceFragment {
|
|||||||
new DialogInterface.OnClickListener() {
|
new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
launchIntent(OtherInfoFragment.this, intent);
|
Utils.launchIntent(OtherInfoFragment.this, intent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
builder.setNegativeButton(android.R.string.cancel, null);
|
builder.setNegativeButton(android.R.string.cancel, null);
|
||||||
|
@@ -243,10 +243,15 @@ public class StorageItemPreferenceController extends PreferenceController
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Intent getAudioIntent() {
|
private Intent getAudioIntent() {
|
||||||
Intent intent = new Intent(DocumentsContract.ACTION_BROWSE);
|
Bundle args = new Bundle();
|
||||||
intent.setData(DocumentsContract.buildRootUri(AUTHORITY_MEDIA, "audio_root"));
|
args.putString(ManageApplications.EXTRA_CLASSNAME,
|
||||||
intent.addCategory(Intent.CATEGORY_DEFAULT);
|
Settings.StorageUseActivity.class.getName());
|
||||||
return intent;
|
args.putString(ManageApplications.EXTRA_VOLUME_UUID, mVolume.getFsUuid());
|
||||||
|
args.putString(ManageApplications.EXTRA_VOLUME_NAME, mVolume.getDescription());
|
||||||
|
args.putInt(ManageApplications.EXTRA_STORAGE_TYPE, ManageApplications.STORAGE_TYPE_MUSIC);
|
||||||
|
return Utils.onBuildStartFragmentIntent(mContext,
|
||||||
|
ManageApplications.class.getName(), args, null, R.string.audio_storage_title, null,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Intent getAppsIntent() {
|
private Intent getAppsIntent() {
|
||||||
|
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* 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.deviceinfo.storage;
|
||||||
|
|
||||||
|
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 mSsm;
|
||||||
|
|
||||||
|
public StorageStatsSource(Context context) {
|
||||||
|
mSsm = context.getSystemService(StorageStatsManager.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExternalStorageStats getExternalStorageStats(String volumeUuid, UserHandle user) {
|
||||||
|
return new ExternalStorageStats(mSsm.queryExternalStatsForUser(volumeUuid, user));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ExternalStorageStats {
|
||||||
|
public long totalBytes;
|
||||||
|
public long audioBytes;
|
||||||
|
public long videoBytes;
|
||||||
|
public long imageBytes;
|
||||||
|
|
||||||
|
public ExternalStorageStats(long totalBytes, long audioBytes, long videoBytes,
|
||||||
|
long imageBytes) {
|
||||||
|
this.totalBytes = totalBytes;
|
||||||
|
this.audioBytes = audioBytes;
|
||||||
|
this.videoBytes = videoBytes;
|
||||||
|
this.imageBytes = imageBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExternalStorageStats(android.app.usage.ExternalStorageStats stats) {
|
||||||
|
totalBytes = stats.getTotalBytes();
|
||||||
|
audioBytes = stats.getAudioBytes();
|
||||||
|
videoBytes = stats.getVideoBytes();
|
||||||
|
imageBytes = stats.getImageBytes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* 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.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.Fragment;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.os.storage.VolumeInfo;
|
||||||
|
import android.provider.DocumentsContract;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
|
||||||
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.deviceinfo.storage.StorageStatsSource;
|
||||||
|
import com.android.settingslib.deviceinfo.StorageVolumeProvider;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Answers;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
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 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;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
mContext = RuntimeEnvironment.application;
|
||||||
|
mVolume = new VolumeInfo("id", 0, null, "id");
|
||||||
|
mController = new MusicViewHolderController(mContext, mSource, mVolume.fsUuid);
|
||||||
|
|
||||||
|
LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||||
|
mHolder = AppViewHolder.createOrRecycle(inflater, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void storageShouldBeZeroBytesIfQueriedBeforeStorageQueryFinishes() {
|
||||||
|
mController.setupView(mHolder);
|
||||||
|
|
||||||
|
assertThat(mHolder.summary.getText().toString()).isEqualTo("0.00B");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void storageShouldRepresentStorageStatsQuery() {
|
||||||
|
when(mSource.getExternalStorageStats(any(String.class), any(UserHandle.class))).thenReturn(
|
||||||
|
new StorageStatsSource.ExternalStorageStats(1, 1, 0, 0));
|
||||||
|
|
||||||
|
mController.queryStats();
|
||||||
|
mController.setupView(mHolder);
|
||||||
|
|
||||||
|
assertThat(mHolder.summary.getText().toString()).isEqualTo("1.00B");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clickingShouldIntentIntoFilesApp() {
|
||||||
|
mController.onClick(mFragment);
|
||||||
|
|
||||||
|
final ArgumentCaptor<Intent> argumentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||||
|
verify(mFragment).startActivity(argumentCaptor.capture());
|
||||||
|
Intent intent = argumentCaptor.getValue();
|
||||||
|
|
||||||
|
assertThat(intent.getAction()).isEqualTo(DocumentsContract.ACTION_BROWSE);
|
||||||
|
assertThat(intent.getData()).isEqualTo(DocumentsContract.buildRootUri(
|
||||||
|
"com.android.providers.media.documents",
|
||||||
|
"audio_root"));
|
||||||
|
}
|
||||||
|
}
|
@@ -35,6 +35,7 @@ import android.view.View;
|
|||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.Settings;
|
||||||
import com.android.settings.SettingsActivity;
|
import com.android.settings.SettingsActivity;
|
||||||
import com.android.settings.SettingsRobolectricTestRunner;
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
import com.android.settings.SubSettings;
|
import com.android.settings.SubSettings;
|
||||||
@@ -118,12 +119,15 @@ public class StorageItemPreferenceControllerTest {
|
|||||||
final ArgumentCaptor<Intent> argumentCaptor = ArgumentCaptor.forClass(Intent.class);
|
final ArgumentCaptor<Intent> argumentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||||
verify(mFragment.getActivity()).startActivityAsUser(argumentCaptor.capture(),
|
verify(mFragment.getActivity()).startActivityAsUser(argumentCaptor.capture(),
|
||||||
any(UserHandle.class));
|
any(UserHandle.class));
|
||||||
|
|
||||||
Intent intent = argumentCaptor.getValue();
|
Intent intent = argumentCaptor.getValue();
|
||||||
assertThat(intent.getAction()).isEqualTo(DocumentsContract.ACTION_BROWSE);
|
|
||||||
assertThat(intent.getData()).isEqualTo(DocumentsContract.buildRootUri(
|
assertThat(intent.getAction()).isEqualTo(Intent.ACTION_MAIN);
|
||||||
"com.android.providers.media.documents",
|
assertThat(intent.getComponent().getClassName()).isEqualTo(SubSettings.class.getName());
|
||||||
"audio_root"));
|
assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)).isEqualTo(
|
||||||
|
ManageApplications.class.getName());
|
||||||
|
assertThat(intent.getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS).getInt(
|
||||||
|
ManageApplications.EXTRA_STORAGE_TYPE, 0)).isEqualTo(
|
||||||
|
ManageApplications.STORAGE_TYPE_MUSIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@@ -61,7 +61,6 @@ public class StorageSummaryDonutPreferenceControllerTest {
|
|||||||
final View view =
|
final View view =
|
||||||
inflater.inflate(
|
inflater.inflate(
|
||||||
mPreference.getLayoutResource(), new LinearLayout(mContext), false);
|
mPreference.getLayoutResource(), new LinearLayout(mContext), false);
|
||||||
|
|
||||||
mHolder = new PreferenceViewHolder(view);
|
mHolder = new PreferenceViewHolder(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user