Home | History | Annotate | Download | only in deviceinfo
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.settings.deviceinfo;
     18 
     19 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
     20 
     21 import android.app.AlertDialog;
     22 import android.app.Dialog;
     23 import android.app.Fragment;
     24 import android.content.Context;
     25 import android.content.DialogInterface;
     26 import android.content.Intent;
     27 import android.graphics.Color;
     28 import android.graphics.drawable.Drawable;
     29 import android.os.AsyncTask;
     30 import android.os.Bundle;
     31 import android.os.UserHandle;
     32 import android.os.UserManager;
     33 import android.os.storage.DiskInfo;
     34 import android.os.storage.StorageEventListener;
     35 import android.os.storage.StorageManager;
     36 import android.os.storage.VolumeInfo;
     37 import android.os.storage.VolumeRecord;
     38 import android.support.annotation.NonNull;
     39 import android.support.annotation.VisibleForTesting;
     40 import android.support.v7.preference.Preference;
     41 import android.support.v7.preference.PreferenceCategory;
     42 import android.text.TextUtils;
     43 import android.text.format.Formatter;
     44 import android.text.format.Formatter.BytesResult;
     45 import android.util.Log;
     46 import android.widget.Toast;
     47 
     48 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
     49 import com.android.settings.R;
     50 import com.android.settings.SettingsPreferenceFragment;
     51 import com.android.settings.core.SubSettingLauncher;
     52 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
     53 import com.android.settings.dashboard.SummaryLoader;
     54 import com.android.settings.search.BaseSearchIndexProvider;
     55 import com.android.settings.search.Indexable;
     56 import com.android.settings.search.SearchIndexableRaw;
     57 import com.android.settingslib.RestrictedLockUtils;
     58 import com.android.settingslib.deviceinfo.PrivateStorageInfo;
     59 import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;
     60 
     61 import java.text.NumberFormat;
     62 import java.util.ArrayList;
     63 import java.util.Collections;
     64 import java.util.List;
     65 
     66 /**
     67  * Panel showing both internal storage (both built-in storage and private
     68  * volumes) and removable storage (public volumes).
     69  */
     70 public class StorageSettings extends SettingsPreferenceFragment implements Indexable {
     71     static final String TAG = "StorageSettings";
     72 
     73     private static final String TAG_VOLUME_UNMOUNTED = "volume_unmounted";
     74     private static final String TAG_DISK_INIT = "disk_init";
     75     private static final int METRICS_CATEGORY = MetricsEvent.DEVICEINFO_STORAGE;
     76 
     77     static final int COLOR_PUBLIC = Color.parseColor("#ff9e9e9e");
     78 
     79     static final int[] COLOR_PRIVATE = new int[]{
     80             Color.parseColor("#ff26a69a"),
     81             Color.parseColor("#ffab47bc"),
     82             Color.parseColor("#fff2a600"),
     83             Color.parseColor("#ffec407a"),
     84             Color.parseColor("#ffc0ca33"),
     85     };
     86 
     87     private StorageManager mStorageManager;
     88 
     89     private PreferenceCategory mInternalCategory;
     90     private PreferenceCategory mExternalCategory;
     91 
     92     private StorageSummaryPreference mInternalSummary;
     93     private static long sTotalInternalStorage;
     94 
     95     private boolean mHasLaunchedPrivateVolumeSettings = false;
     96 
     97     @Override
     98     public int getMetricsCategory() {
     99         return METRICS_CATEGORY;
    100     }
    101 
    102     @Override
    103     public int getHelpResource() {
    104         return R.string.help_uri_storage;
    105     }
    106 
    107     @Override
    108     public void onCreate(Bundle icicle) {
    109         super.onCreate(icicle);
    110 
    111         final Context context = getActivity();
    112 
    113         mStorageManager = context.getSystemService(StorageManager.class);
    114 
    115         if (sTotalInternalStorage <= 0) {
    116             sTotalInternalStorage = mStorageManager.getPrimaryStorageSize();
    117         }
    118 
    119         addPreferencesFromResource(R.xml.device_info_storage);
    120 
    121         mInternalCategory = (PreferenceCategory) findPreference("storage_internal");
    122         mExternalCategory = (PreferenceCategory) findPreference("storage_external");
    123 
    124         mInternalSummary = new StorageSummaryPreference(getPrefContext());
    125 
    126         setHasOptionsMenu(true);
    127     }
    128 
    129     private final StorageEventListener mStorageListener = new StorageEventListener() {
    130         @Override
    131         public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
    132             if (isInteresting(vol)) {
    133                 refresh();
    134             }
    135         }
    136 
    137         @Override
    138         public void onDiskDestroyed(DiskInfo disk) {
    139             refresh();
    140         }
    141     };
    142 
    143     private static boolean isInteresting(VolumeInfo vol) {
    144         switch (vol.getType()) {
    145             case VolumeInfo.TYPE_PRIVATE:
    146             case VolumeInfo.TYPE_PUBLIC:
    147                 return true;
    148             default:
    149                 return false;
    150         }
    151     }
    152 
    153     private synchronized void refresh() {
    154         final Context context = getPrefContext();
    155 
    156         getPreferenceScreen().removeAll();
    157         mInternalCategory.removeAll();
    158         mExternalCategory.removeAll();
    159 
    160         mInternalCategory.addPreference(mInternalSummary);
    161 
    162         int privateCount = 0;
    163 
    164         final StorageManagerVolumeProvider smvp = new StorageManagerVolumeProvider(mStorageManager);
    165         final PrivateStorageInfo info = PrivateStorageInfo.getPrivateStorageInfo(smvp);
    166         final long privateTotalBytes = info.totalBytes;
    167         final long privateUsedBytes = info.totalBytes - info.freeBytes;
    168 
    169         final List<VolumeInfo> volumes = mStorageManager.getVolumes();
    170         Collections.sort(volumes, VolumeInfo.getDescriptionComparator());
    171 
    172         for (VolumeInfo vol : volumes) {
    173             if (vol.getType() == VolumeInfo.TYPE_PRIVATE) {
    174                 final long volumeTotalBytes = PrivateStorageInfo.getTotalSize(vol,
    175                         sTotalInternalStorage);
    176                 final int color = COLOR_PRIVATE[privateCount++ % COLOR_PRIVATE.length];
    177                 mInternalCategory.addPreference(
    178                         new StorageVolumePreference(context, vol, color, volumeTotalBytes));
    179             } else if (vol.getType() == VolumeInfo.TYPE_PUBLIC) {
    180                 mExternalCategory.addPreference(
    181                         new StorageVolumePreference(context, vol, COLOR_PUBLIC, 0));
    182             }
    183         }
    184 
    185         // Show missing private volumes
    186         final List<VolumeRecord> recs = mStorageManager.getVolumeRecords();
    187         for (VolumeRecord rec : recs) {
    188             if (rec.getType() == VolumeInfo.TYPE_PRIVATE
    189                     && mStorageManager.findVolumeByUuid(rec.getFsUuid()) == null) {
    190                 // TODO: add actual storage type to record
    191                 final Drawable icon = context.getDrawable(R.drawable.ic_sim_sd);
    192                 icon.mutate();
    193                 icon.setTint(COLOR_PUBLIC);
    194 
    195                 final Preference pref = new Preference(context);
    196                 pref.setKey(rec.getFsUuid());
    197                 pref.setTitle(rec.getNickname());
    198                 pref.setSummary(com.android.internal.R.string.ext_media_status_missing);
    199                 pref.setIcon(icon);
    200                 mInternalCategory.addPreference(pref);
    201             }
    202         }
    203 
    204         // Show unsupported disks to give a chance to init
    205         final List<DiskInfo> disks = mStorageManager.getDisks();
    206         for (DiskInfo disk : disks) {
    207             if (disk.volumeCount == 0 && disk.size > 0) {
    208                 final Preference pref = new Preference(context);
    209                 pref.setKey(disk.getId());
    210                 pref.setTitle(disk.getDescription());
    211                 pref.setSummary(com.android.internal.R.string.ext_media_status_unsupported);
    212                 pref.setIcon(R.drawable.ic_sim_sd);
    213                 mExternalCategory.addPreference(pref);
    214             }
    215         }
    216 
    217         final BytesResult result = Formatter.formatBytes(getResources(), privateUsedBytes, 0);
    218         mInternalSummary.setTitle(TextUtils.expandTemplate(getText(R.string.storage_size_large),
    219                 result.value, result.units));
    220         mInternalSummary.setSummary(getString(R.string.storage_volume_used_total,
    221                 Formatter.formatFileSize(context, privateTotalBytes)));
    222         if (mInternalCategory.getPreferenceCount() > 0) {
    223             getPreferenceScreen().addPreference(mInternalCategory);
    224         }
    225         if (mExternalCategory.getPreferenceCount() > 0) {
    226             getPreferenceScreen().addPreference(mExternalCategory);
    227         }
    228 
    229         if (mInternalCategory.getPreferenceCount() == 2
    230                 && mExternalCategory.getPreferenceCount() == 0) {
    231             // Only showing primary internal storage, so just shortcut
    232             if (!mHasLaunchedPrivateVolumeSettings) {
    233                 mHasLaunchedPrivateVolumeSettings = true;
    234                 final Bundle args = new Bundle();
    235                 args.putString(VolumeInfo.EXTRA_VOLUME_ID, VolumeInfo.ID_PRIVATE_INTERNAL);
    236                 new SubSettingLauncher(getActivity())
    237                         .setDestination(StorageDashboardFragment.class.getName())
    238                         .setArguments(args)
    239                         .setTitle(R.string.storage_settings)
    240                         .setSourceMetricsCategory(getMetricsCategory())
    241                         .launch();
    242                 finish();
    243             }
    244         }
    245     }
    246 
    247     @Override
    248     public void onResume() {
    249         super.onResume();
    250         mStorageManager.registerListener(mStorageListener);
    251         refresh();
    252     }
    253 
    254     @Override
    255     public void onPause() {
    256         super.onPause();
    257         mStorageManager.unregisterListener(mStorageListener);
    258     }
    259 
    260     @Override
    261     public boolean onPreferenceTreeClick(Preference pref) {
    262         final String key = pref.getKey();
    263         if (pref instanceof StorageVolumePreference) {
    264             // Picked a normal volume
    265             final VolumeInfo vol = mStorageManager.findVolumeById(key);
    266 
    267             if (vol == null) {
    268                 return false;
    269             }
    270 
    271             if (vol.getState() == VolumeInfo.STATE_UNMOUNTED) {
    272                 VolumeUnmountedFragment.show(this, vol.getId());
    273                 return true;
    274             } else if (vol.getState() == VolumeInfo.STATE_UNMOUNTABLE) {
    275                 DiskInitFragment.show(this, R.string.storage_dialog_unmountable, vol.getDiskId());
    276                 return true;
    277             }
    278 
    279             if (vol.getType() == VolumeInfo.TYPE_PRIVATE) {
    280                 final Bundle args = new Bundle();
    281                 args.putString(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
    282 
    283                 if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.getId())) {
    284                     new SubSettingLauncher(getContext())
    285                             .setDestination(StorageDashboardFragment.class.getCanonicalName())
    286                             .setTitle(R.string.storage_settings)
    287                             .setSourceMetricsCategory(getMetricsCategory())
    288                             .setArguments(args)
    289                             .launch();
    290                 } else {
    291                     // TODO: Go to the StorageDashboardFragment once it fully handles all of the
    292                     //       SD card cases and other private internal storage cases.
    293                     PrivateVolumeSettings.setVolumeSize(args, PrivateStorageInfo.getTotalSize(vol,
    294                             sTotalInternalStorage));
    295                     new SubSettingLauncher(getContext())
    296                             .setDestination(PrivateVolumeSettings.class.getCanonicalName())
    297                             .setTitle(-1)
    298                             .setSourceMetricsCategory(getMetricsCategory())
    299                             .setArguments(args)
    300                             .launch();
    301                 }
    302 
    303                 return true;
    304 
    305             } else if (vol.getType() == VolumeInfo.TYPE_PUBLIC) {
    306                 return handlePublicVolumeClick(getContext(), vol);
    307             }
    308 
    309         } else if (key.startsWith("disk:")) {
    310             // Picked an unsupported disk
    311             DiskInitFragment.show(this, R.string.storage_dialog_unsupported, key);
    312             return true;
    313 
    314         } else {
    315             // Picked a missing private volume
    316             final Bundle args = new Bundle();
    317             args.putString(VolumeRecord.EXTRA_FS_UUID, key);
    318             new SubSettingLauncher(getContext())
    319                     .setDestination(PrivateVolumeForget.class.getCanonicalName())
    320                     .setTitle(R.string.storage_menu_forget)
    321                     .setSourceMetricsCategory(getMetricsCategory())
    322                     .setArguments(args)
    323                     .launch();
    324             return true;
    325         }
    326 
    327         return false;
    328     }
    329 
    330     @VisibleForTesting
    331     static boolean handlePublicVolumeClick(Context context, VolumeInfo vol) {
    332         final Intent intent = vol.buildBrowseIntent();
    333         if (vol.isMountedReadable() && intent != null) {
    334             context.startActivity(intent);
    335             return true;
    336         } else {
    337             final Bundle args = new Bundle();
    338             args.putString(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
    339             new SubSettingLauncher(context)
    340                     .setDestination(PublicVolumeSettings.class.getCanonicalName())
    341                     .setTitle(-1)
    342                     .setSourceMetricsCategory(METRICS_CATEGORY)
    343                     .setArguments(args)
    344                     .launch();
    345             return true;
    346         }
    347     }
    348 
    349     public static class MountTask extends AsyncTask<Void, Void, Exception> {
    350         private final Context mContext;
    351         private final StorageManager mStorageManager;
    352         private final String mVolumeId;
    353         private final String mDescription;
    354 
    355         public MountTask(Context context, VolumeInfo volume) {
    356             mContext = context.getApplicationContext();
    357             mStorageManager = mContext.getSystemService(StorageManager.class);
    358             mVolumeId = volume.getId();
    359             mDescription = mStorageManager.getBestVolumeDescription(volume);
    360         }
    361 
    362         @Override
    363         protected Exception doInBackground(Void... params) {
    364             try {
    365                 mStorageManager.mount(mVolumeId);
    366                 return null;
    367             } catch (Exception e) {
    368                 return e;
    369             }
    370         }
    371 
    372         @Override
    373         protected void onPostExecute(Exception e) {
    374             if (e == null) {
    375                 Toast.makeText(mContext, mContext.getString(R.string.storage_mount_success,
    376                         mDescription), Toast.LENGTH_SHORT).show();
    377             } else {
    378                 Log.e(TAG, "Failed to mount " + mVolumeId, e);
    379                 Toast.makeText(mContext, mContext.getString(R.string.storage_mount_failure,
    380                         mDescription), Toast.LENGTH_SHORT).show();
    381             }
    382         }
    383     }
    384 
    385     public static class UnmountTask extends AsyncTask<Void, Void, Exception> {
    386         private final Context mContext;
    387         private final StorageManager mStorageManager;
    388         private final String mVolumeId;
    389         private final String mDescription;
    390 
    391         public UnmountTask(Context context, VolumeInfo volume) {
    392             mContext = context.getApplicationContext();
    393             mStorageManager = mContext.getSystemService(StorageManager.class);
    394             mVolumeId = volume.getId();
    395             mDescription = mStorageManager.getBestVolumeDescription(volume);
    396         }
    397 
    398         @Override
    399         protected Exception doInBackground(Void... params) {
    400             try {
    401                 mStorageManager.unmount(mVolumeId);
    402                 return null;
    403             } catch (Exception e) {
    404                 return e;
    405             }
    406         }
    407 
    408         @Override
    409         protected void onPostExecute(Exception e) {
    410             if (e == null) {
    411                 Toast.makeText(mContext, mContext.getString(R.string.storage_unmount_success,
    412                         mDescription), Toast.LENGTH_SHORT).show();
    413             } else {
    414                 Log.e(TAG, "Failed to unmount " + mVolumeId, e);
    415                 Toast.makeText(mContext, mContext.getString(R.string.storage_unmount_failure,
    416                         mDescription), Toast.LENGTH_SHORT).show();
    417             }
    418         }
    419     }
    420 
    421     public static class VolumeUnmountedFragment extends InstrumentedDialogFragment {
    422         public static void show(Fragment parent, String volumeId) {
    423             final Bundle args = new Bundle();
    424             args.putString(VolumeInfo.EXTRA_VOLUME_ID, volumeId);
    425 
    426             final VolumeUnmountedFragment dialog = new VolumeUnmountedFragment();
    427             dialog.setArguments(args);
    428             dialog.setTargetFragment(parent, 0);
    429             dialog.show(parent.getFragmentManager(), TAG_VOLUME_UNMOUNTED);
    430         }
    431 
    432         @Override
    433         public int getMetricsCategory() {
    434             return MetricsEvent.DIALOG_VOLUME_UNMOUNT;
    435         }
    436 
    437         @Override
    438         public Dialog onCreateDialog(Bundle savedInstanceState) {
    439             final Context context = getActivity();
    440             final StorageManager sm = context.getSystemService(StorageManager.class);
    441 
    442             final String volumeId = getArguments().getString(VolumeInfo.EXTRA_VOLUME_ID);
    443             final VolumeInfo vol = sm.findVolumeById(volumeId);
    444 
    445             final AlertDialog.Builder builder = new AlertDialog.Builder(context);
    446             builder.setMessage(TextUtils.expandTemplate(
    447                     getText(R.string.storage_dialog_unmounted), vol.getDisk().getDescription()));
    448 
    449             builder.setPositiveButton(R.string.storage_menu_mount,
    450                     new DialogInterface.OnClickListener() {
    451                         /**
    452                          * Check if an {@link
    453                          * RestrictedLockUtils#sendShowAdminSupportDetailsIntent admin
    454                          * details intent} should be shown for the restriction and show it.
    455                          *
    456                          * @param restriction The restriction to check
    457                          * @return {@code true} iff a intent was shown.
    458                          */
    459                         private boolean wasAdminSupportIntentShown(@NonNull String restriction) {
    460                             EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(
    461                                     getActivity(), restriction, UserHandle.myUserId());
    462                             boolean hasBaseUserRestriction =
    463                                     RestrictedLockUtils.hasBaseUserRestriction(
    464                                             getActivity(), restriction, UserHandle.myUserId());
    465                             if (admin != null && !hasBaseUserRestriction) {
    466                                 RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(),
    467                                         admin);
    468                                 return true;
    469                             }
    470 
    471                             return false;
    472                         }
    473 
    474                         @Override
    475                         public void onClick(DialogInterface dialog, int which) {
    476                             if (wasAdminSupportIntentShown(
    477                                     UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA)) {
    478                                 return;
    479                             }
    480 
    481                             if (vol.disk != null && vol.disk.isUsb() &&
    482                                     wasAdminSupportIntentShown(
    483                                             UserManager.DISALLOW_USB_FILE_TRANSFER)) {
    484                                 return;
    485                             }
    486 
    487                             new MountTask(context, vol).execute();
    488                         }
    489                     });
    490             builder.setNegativeButton(R.string.cancel, null);
    491 
    492             return builder.create();
    493         }
    494     }
    495 
    496     public static class DiskInitFragment extends InstrumentedDialogFragment {
    497         @Override
    498         public int getMetricsCategory() {
    499             return MetricsEvent.DIALOG_VOLUME_INIT;
    500         }
    501 
    502         public static void show(Fragment parent, int resId, String diskId) {
    503             final Bundle args = new Bundle();
    504             args.putInt(Intent.EXTRA_TEXT, resId);
    505             args.putString(DiskInfo.EXTRA_DISK_ID, diskId);
    506 
    507             final DiskInitFragment dialog = new DiskInitFragment();
    508             dialog.setArguments(args);
    509             dialog.setTargetFragment(parent, 0);
    510             dialog.show(parent.getFragmentManager(), TAG_DISK_INIT);
    511         }
    512 
    513         @Override
    514         public Dialog onCreateDialog(Bundle savedInstanceState) {
    515             final Context context = getActivity();
    516             final StorageManager sm = context.getSystemService(StorageManager.class);
    517 
    518             final int resId = getArguments().getInt(Intent.EXTRA_TEXT);
    519             final String diskId = getArguments().getString(DiskInfo.EXTRA_DISK_ID);
    520             final DiskInfo disk = sm.findDiskById(diskId);
    521 
    522             final AlertDialog.Builder builder = new AlertDialog.Builder(context);
    523             builder.setMessage(TextUtils.expandTemplate(getText(resId), disk.getDescription()));
    524 
    525             builder.setPositiveButton(R.string.storage_menu_set_up,
    526                     new DialogInterface.OnClickListener() {
    527                         @Override
    528                         public void onClick(DialogInterface dialog, int which) {
    529                             final Intent intent = new Intent(context, StorageWizardInit.class);
    530                             intent.putExtra(DiskInfo.EXTRA_DISK_ID, diskId);
    531                             startActivity(intent);
    532                         }
    533                     });
    534             builder.setNegativeButton(R.string.cancel, null);
    535 
    536             return builder.create();
    537         }
    538     }
    539 
    540     private static class SummaryProvider implements SummaryLoader.SummaryProvider {
    541         private final Context mContext;
    542         private final SummaryLoader mLoader;
    543         private final StorageManagerVolumeProvider mStorageManagerVolumeProvider;
    544 
    545         private SummaryProvider(Context context, SummaryLoader loader) {
    546             mContext = context;
    547             mLoader = loader;
    548             final StorageManager storageManager = mContext.getSystemService(StorageManager.class);
    549             mStorageManagerVolumeProvider = new StorageManagerVolumeProvider(storageManager);
    550         }
    551 
    552         @Override
    553         public void setListening(boolean listening) {
    554             if (listening) {
    555                 updateSummary();
    556             }
    557         }
    558 
    559         private void updateSummary() {
    560             // TODO: Register listener.
    561             final NumberFormat percentageFormat = NumberFormat.getPercentInstance();
    562             final PrivateStorageInfo info = PrivateStorageInfo.getPrivateStorageInfo(
    563                     mStorageManagerVolumeProvider);
    564             double privateUsedBytes = info.totalBytes - info.freeBytes;
    565             mLoader.setSummary(this, mContext.getString(R.string.storage_summary,
    566                     percentageFormat.format(privateUsedBytes / info.totalBytes),
    567                     Formatter.formatFileSize(mContext, info.freeBytes)));
    568         }
    569     }
    570 
    571 
    572     public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY
    573             = (activity, summaryLoader) -> new SummaryProvider(activity, summaryLoader);
    574 
    575     /** Enable indexing of searchable data */
    576     public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
    577             new BaseSearchIndexProvider() {
    578                 @Override
    579                 public List<SearchIndexableRaw> getRawDataToIndex(
    580                         Context context, boolean enabled) {
    581                     final List<SearchIndexableRaw> result = new ArrayList<>();
    582 
    583                     SearchIndexableRaw data = new SearchIndexableRaw(context);
    584                     data.title = context.getString(R.string.storage_settings);
    585                     data.key = "storage_settings";
    586                     data.screenTitle = context.getString(R.string.storage_settings);
    587                     data.keywords = context.getString(R.string.keywords_storage_settings);
    588                     result.add(data);
    589 
    590                     data = new SearchIndexableRaw(context);
    591                     data.title = context.getString(R.string.internal_storage);
    592                     data.key = "storage_settings_internal_storage";
    593                     data.screenTitle = context.getString(R.string.storage_settings);
    594                     result.add(data);
    595 
    596                     data = new SearchIndexableRaw(context);
    597                     final StorageManager storage = context.getSystemService(StorageManager.class);
    598                     final List<VolumeInfo> vols = storage.getVolumes();
    599                     for (VolumeInfo vol : vols) {
    600                         if (isInteresting(vol)) {
    601                             data.title = storage.getBestVolumeDescription(vol);
    602                             data.key = "storage_settings_volume_" + vol.id;
    603                             data.screenTitle = context.getString(R.string.storage_settings);
    604                             result.add(data);
    605                         }
    606                     }
    607 
    608                     data = new SearchIndexableRaw(context);
    609                     data.title = context.getString(R.string.memory_size);
    610                     data.key = "storage_settings_memory_size";
    611                     data.screenTitle = context.getString(R.string.storage_settings);
    612                     result.add(data);
    613 
    614                     data = new SearchIndexableRaw(context);
    615                     data.title = context.getString(R.string.memory_available);
    616                     data.key = "storage_settings_memory_available";
    617                     data.screenTitle = context.getString(R.string.storage_settings);
    618                     result.add(data);
    619 
    620                     data = new SearchIndexableRaw(context);
    621                     data.title = context.getString(R.string.memory_apps_usage);
    622                     data.key = "storage_settings_apps_space";
    623                     data.screenTitle = context.getString(R.string.storage_settings);
    624                     result.add(data);
    625 
    626                     data = new SearchIndexableRaw(context);
    627                     data.title = context.getString(R.string.memory_dcim_usage);
    628                     data.key = "storage_settings_dcim_space";
    629                     data.screenTitle = context.getString(R.string.storage_settings);
    630                     result.add(data);
    631 
    632                     data = new SearchIndexableRaw(context);
    633                     data.title = context.getString(R.string.memory_music_usage);
    634                     data.key = "storage_settings_music_space";
    635                     data.screenTitle = context.getString(R.string.storage_settings);
    636                     result.add(data);
    637 
    638                     data = new SearchIndexableRaw(context);
    639                     data.title = context.getString(R.string.memory_media_misc_usage);
    640                     data.key = "storage_settings_misc_space";
    641                     data.screenTitle = context.getString(R.string.storage_settings);
    642                     result.add(data);
    643 
    644                     data = new SearchIndexableRaw(context);
    645                     data.title = context.getString(R.string.storage_menu_free);
    646                     data.key = "storage_settings_free_space";
    647                     data.screenTitle = context.getString(R.string.storage_menu_free);
    648                     // We need to define all three in order for this to trigger properly.
    649                     data.intentAction = StorageManager.ACTION_MANAGE_STORAGE;
    650                     data.intentTargetPackage =
    651                             context.getString(R.string.config_deletion_helper_package);
    652                     data.intentTargetClass =
    653                             context.getString(R.string.config_deletion_helper_class);
    654                     result.add(data);
    655 
    656                     return result;
    657                 }
    658             };
    659 }
    660