OSDN Git Service

Erase SD Card fixed in Settings/Storage.
[android-x86/packages-apps-Settings.git] / src / com / android / settings / deviceinfo / StorageVolumePreferenceCategory.java
1 /*
2  * Copyright (C) 2011 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 android.app.DownloadManager;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.res.Resources;
23 import android.graphics.drawable.ShapeDrawable;
24 import android.graphics.drawable.shapes.RectShape;
25 import android.os.Bundle;
26 import android.os.Environment;
27 import android.os.Handler;
28 import android.os.Message;
29 import android.os.storage.StorageManager;
30 import android.os.storage.StorageVolume;
31 import android.preference.Preference;
32 import android.preference.PreferenceCategory;
33 import android.text.format.Formatter;
34
35 import com.android.settings.R;
36 import com.android.settings.deviceinfo.StorageMeasurement.MeasurementReceiver;
37
38 import java.util.HashSet;
39 import java.util.Set;
40
41 public class StorageVolumePreferenceCategory extends PreferenceCategory implements
42         MeasurementReceiver {
43
44     static final int TOTAL_SIZE = 0;
45     static final int APPLICATIONS = 1;
46     static final int DCIM = 2; // Pictures and Videos
47     static final int MUSIC = 3;
48     static final int DOWNLOADS = 4;
49     static final int MISC = 5;
50     static final int AVAILABLE = 6;
51
52     private UsageBarPreference mUsageBarPreference;
53     private Preference[] mPreferences;
54     private Preference mMountTogglePreference;
55     private Preference mFormatPreference;
56     private int[] mColors;
57
58     private Resources mResources;
59
60     private StorageVolume mStorageVolume;
61
62     private StorageManager mStorageManager = null;
63
64     private StorageMeasurement mMeasurement;
65
66     static class CategoryInfo {
67         final int mTitle;
68         final int mColor;
69
70         public CategoryInfo(int title, int color) {
71             mTitle = title;
72             mColor = color;
73         }
74     }
75
76     static final CategoryInfo[] sCategoryInfos = new CategoryInfo[] {
77         new CategoryInfo(R.string.memory_size, 0),
78         new CategoryInfo(R.string.memory_apps_usage, R.color.memory_apps_usage),
79         new CategoryInfo(R.string.memory_dcim_usage, R.color.memory_dcim),
80         new CategoryInfo(R.string.memory_music_usage, R.color.memory_music),
81         new CategoryInfo(R.string.memory_downloads_usage, R.color.memory_downloads),
82         new CategoryInfo(R.string.memory_media_misc_usage, R.color.memory_misc),
83         new CategoryInfo(R.string.memory_available, R.color.memory_avail),
84     };
85
86     public static final Set<String> sPathsExcludedForMisc = new HashSet<String>();
87
88     static class MediaCategory {
89         final String[] mDirPaths;
90         final int mCategory;
91         //final int mMediaType;
92
93         public MediaCategory(int category, String... directories) {
94             mCategory = category;
95             final int length = directories.length;
96             mDirPaths = new String[length];
97             for (int i = 0; i < length; i++) {
98                 final String name = directories[i];
99                 final String path = Environment.getExternalStoragePublicDirectory(name).
100                         getAbsolutePath();
101                 mDirPaths[i] = path;
102                 sPathsExcludedForMisc.add(path);
103             }
104         }
105     }
106
107     static final MediaCategory[] sMediaCategories = new MediaCategory[] {
108         new MediaCategory(DCIM, Environment.DIRECTORY_DCIM, Environment.DIRECTORY_MOVIES,
109                 Environment.DIRECTORY_PICTURES),
110         new MediaCategory(MUSIC, Environment.DIRECTORY_MUSIC, Environment.DIRECTORY_ALARMS,
111                 Environment.DIRECTORY_NOTIFICATIONS, Environment.DIRECTORY_RINGTONES,
112                 Environment.DIRECTORY_PODCASTS)
113     };
114
115     static {
116         // Downloads
117         sPathsExcludedForMisc.add(Environment.getExternalStoragePublicDirectory(
118                 Environment.DIRECTORY_DOWNLOADS).getAbsolutePath());
119         // Apps
120         sPathsExcludedForMisc.add(Environment.getExternalStorageDirectory().getAbsolutePath() +
121                 "/Android");
122     }
123
124     // Updates the memory usage bar graph.
125     private static final int MSG_UI_UPDATE_APPROXIMATE = 1;
126
127     // Updates the memory usage bar graph.
128     private static final int MSG_UI_UPDATE_EXACT = 2;
129
130     private Handler mUpdateHandler = new Handler() {
131         @Override
132         public void handleMessage(Message msg) {
133             switch (msg.what) {
134                 case MSG_UI_UPDATE_APPROXIMATE: {
135                     Bundle bundle = msg.getData();
136                     final long totalSize = bundle.getLong(StorageMeasurement.TOTAL_SIZE);
137                     final long availSize = bundle.getLong(StorageMeasurement.AVAIL_SIZE);
138                     updateApproximate(totalSize, availSize);
139                     break;
140                 }
141                 case MSG_UI_UPDATE_EXACT: {
142                     Bundle bundle = msg.getData();
143                     final long totalSize = bundle.getLong(StorageMeasurement.TOTAL_SIZE);
144                     final long availSize = bundle.getLong(StorageMeasurement.AVAIL_SIZE);
145                     final long appsUsed = bundle.getLong(StorageMeasurement.APPS_USED);
146                     final long downloadsSize = bundle.getLong(StorageMeasurement.DOWNLOADS_SIZE);
147                     final long miscSize = bundle.getLong(StorageMeasurement.MISC_SIZE);
148                     final long[] mediaSizes = bundle.getLongArray(StorageMeasurement.MEDIA_SIZES);
149                     updateExact(totalSize, availSize, appsUsed, downloadsSize, miscSize,
150                             mediaSizes);
151                     break;
152                 }
153             }
154         }
155     };
156
157     public StorageVolumePreferenceCategory(Context context, Resources resources,
158             StorageVolume storageVolume, StorageManager storageManager, boolean isPrimary) {
159         super(context);
160         mResources = resources;
161         mStorageVolume = storageVolume;
162         mStorageManager = storageManager;
163         setTitle(storageVolume.getDescription());
164         mMeasurement = StorageMeasurement.getInstance(context, storageVolume, isPrimary);
165         mMeasurement.setReceiver(this);
166     }
167
168     public void init() {
169         mUsageBarPreference = new UsageBarPreference(getContext());
170
171         final int width = (int) mResources.getDimension(R.dimen.device_memory_usage_button_width);
172         final int height = (int) mResources.getDimension(R.dimen.device_memory_usage_button_height);
173
174         final int numberOfCategories = sCategoryInfos.length;
175         mPreferences = new Preference[numberOfCategories];
176         mColors = new int[numberOfCategories];
177         for (int i = 0; i < numberOfCategories; i++) {
178             final Preference preference = new Preference(getContext());
179             mPreferences[i] = preference;
180             preference.setTitle(sCategoryInfos[i].mTitle);
181             preference.setSummary(R.string.memory_calculating_size);
182             if (i != TOTAL_SIZE) {
183                 // TOTAL_SIZE has no associated color
184                 mColors[i] = mResources.getColor(sCategoryInfos[i].mColor);
185                 preference.setIcon(createRectShape(width, height, mColors[i]));
186             }
187         }
188
189         mMountTogglePreference = new Preference(getContext());
190         mMountTogglePreference.setTitle(R.string.sd_eject);
191         mMountTogglePreference.setSummary(R.string.sd_eject_summary);
192
193         mFormatPreference = new Preference(getContext());
194         mFormatPreference.setTitle(R.string.sd_format);
195         mFormatPreference.setSummary(R.string.sd_format_summary);
196     }
197
198     public StorageVolume getStorageVolume() {
199         return mStorageVolume;
200     }
201
202     /**
203      * Successive mounts can change the list of visible preferences.
204      * This makes sure all preferences are visible and displayed in the right order.
205      */
206     private void resetPreferences() {
207         final int numberOfCategories = sCategoryInfos.length;
208
209         removePreference(mUsageBarPreference);
210         for (int i = 0; i < numberOfCategories; i++) {
211             removePreference(mPreferences[i]);
212         }
213         removePreference(mMountTogglePreference);
214         removePreference(mFormatPreference);
215
216         addPreference(mUsageBarPreference);
217         for (int i = 0; i < numberOfCategories; i++) {
218             addPreference(mPreferences[i]);
219         }
220         addPreference(mMountTogglePreference);
221         addPreference(mFormatPreference);
222
223         mMountTogglePreference.setEnabled(true);
224     }
225
226     private void updatePreferencesFromState() {
227         resetPreferences();
228
229         String state = mStorageManager.getVolumeState(mStorageVolume.getPath());
230
231         String readOnly = "";
232         if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
233             state = Environment.MEDIA_MOUNTED;
234             readOnly = mResources.getString(R.string.read_only);
235             removePreference(mFormatPreference);
236         }
237
238         if (mStorageVolume.isEmulated()) {
239             removePreference(mFormatPreference);
240         }
241
242         if (!mStorageVolume.isRemovable() && !Environment.MEDIA_UNMOUNTED.equals(state)) {
243             // This device has built-in storage that is not removable.
244             // There is no reason for the user to unmount it.
245             removePreference(mMountTogglePreference);
246         }
247
248         if (Environment.MEDIA_MOUNTED.equals(state)) {
249             mPreferences[AVAILABLE].setSummary(mPreferences[AVAILABLE].getSummary() + readOnly);
250
251             mMountTogglePreference.setEnabled(true);
252             mMountTogglePreference.setTitle(mResources.getString(R.string.sd_eject));
253             mMountTogglePreference.setSummary(mResources.getString(R.string.sd_eject_summary));
254         } else {
255             if (Environment.MEDIA_UNMOUNTED.equals(state) || Environment.MEDIA_NOFS.equals(state)
256                     || Environment.MEDIA_UNMOUNTABLE.equals(state)) {
257                 mMountTogglePreference.setEnabled(true);
258                 mMountTogglePreference.setTitle(mResources.getString(R.string.sd_mount));
259                 mMountTogglePreference.setSummary(mResources.getString(R.string.sd_mount_summary));
260             } else {
261                 mMountTogglePreference.setEnabled(false);
262                 mMountTogglePreference.setTitle(mResources.getString(R.string.sd_mount));
263                 mMountTogglePreference.setSummary(mResources.getString(R.string.sd_insert_summary));
264             }
265
266             removePreference(mUsageBarPreference);
267             removePreference(mPreferences[TOTAL_SIZE]);
268             removePreference(mPreferences[AVAILABLE]);
269             removePreference(mFormatPreference);
270         }
271     }
272
273     public void updateApproximate(long totalSize, long availSize) {
274         mPreferences[TOTAL_SIZE].setSummary(formatSize(totalSize));
275         mPreferences[AVAILABLE].setSummary(formatSize(availSize));
276
277         final long usedSize = totalSize - availSize;
278
279         mUsageBarPreference.clear();
280         mUsageBarPreference.addEntry(usedSize / (float) totalSize, android.graphics.Color.GRAY);
281         mUsageBarPreference.commit();
282
283         updatePreferencesFromState();
284     }
285
286     public void updateExact(long totalSize, long availSize, long appsSize, long downloadsSize,
287             long miscSize, long[] mediaSizes) {
288         mUsageBarPreference.clear();
289
290         mPreferences[TOTAL_SIZE].setSummary(formatSize(totalSize));
291
292         updatePreference(appsSize, totalSize, APPLICATIONS);
293
294         long totalMediaSize = 0;
295         for (int i = 0; i < sMediaCategories.length; i++) {
296             final int category = sMediaCategories[i].mCategory;
297             final long size = mediaSizes[i];
298             updatePreference(size, totalSize, category);
299             totalMediaSize += size;
300         }
301
302         updatePreference(downloadsSize, totalSize, DOWNLOADS);
303
304         // Note miscSize != totalSize - availSize - appsSize - downloadsSize - totalMediaSize
305         // Block size is taken into account. That can be extra space from folders. TODO Investigate
306         updatePreference(miscSize, totalSize, MISC);
307
308         updatePreference(availSize, totalSize, AVAILABLE);
309
310         mUsageBarPreference.commit();
311     }
312
313     private void updatePreference(long size, long totalSize, int category) {
314         if (size > 0) {
315             mPreferences[category].setSummary(formatSize(size));
316             mUsageBarPreference.addEntry(size / (float) totalSize, mColors[category]);
317         } else {
318             removePreference(mPreferences[category]);
319         }
320     }
321
322     private void measure() {
323         mMeasurement.invalidate();
324         mMeasurement.measure();
325     }
326
327     public void onResume() {
328         mMeasurement.setReceiver(this);
329         measure();
330     }
331
332     public void onStorageStateChanged() {
333         measure();
334     }
335
336     public void onMediaScannerFinished() {
337         measure();
338     }
339
340     public void onPause() {
341         mMeasurement.cleanUp();
342     }
343
344     private static ShapeDrawable createRectShape(int width, int height, int color) {
345         ShapeDrawable shape = new ShapeDrawable(new RectShape());
346         shape.setIntrinsicHeight(height);
347         shape.setIntrinsicWidth(width);
348         shape.getPaint().setColor(color);
349         return shape;
350     }
351
352     private String formatSize(long size) {
353         return Formatter.formatFileSize(getContext(), size);
354     }
355
356     @Override
357     public void updateApproximate(Bundle bundle) {
358         final Message message = mUpdateHandler.obtainMessage(MSG_UI_UPDATE_APPROXIMATE);
359         message.setData(bundle);
360         mUpdateHandler.sendMessage(message);
361     }
362
363     @Override
364     public void updateExact(Bundle bundle) {
365         final Message message = mUpdateHandler.obtainMessage(MSG_UI_UPDATE_EXACT);
366         message.setData(bundle);
367         mUpdateHandler.sendMessage(message);
368     }
369
370     public boolean mountToggleClicked(Preference preference) {
371         return preference == mMountTogglePreference;
372     }
373
374     public Intent intentForClick(Preference preference) {
375         Intent intent = null;
376
377         // TODO The current "delete" story is not fully handled by the respective applications.
378         // When it is done, make sure the intent types below are correct.
379         // If that cannot be done, remove these intents.
380         if (preference == mFormatPreference) {
381             intent = new Intent(Intent.ACTION_VIEW);
382             intent.setClass(getContext(), com.android.settings.MediaFormat.class);
383             intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, mStorageVolume);
384         } else if (preference == mPreferences[APPLICATIONS]) {
385             intent = new Intent(Intent.ACTION_MANAGE_PACKAGE_STORAGE);
386             intent.setClass(getContext(),
387                     com.android.settings.Settings.ManageApplicationsActivity.class);
388         } else if (preference == mPreferences[DOWNLOADS]) {
389             intent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS).putExtra(
390                     DownloadManager.INTENT_EXTRAS_SORT_BY_SIZE, true);
391         } else if (preference == mPreferences[MUSIC]) {
392             intent = new Intent(Intent.ACTION_GET_CONTENT);
393             intent.setType("audio/mp3");
394         } else if (preference == mPreferences[DCIM]) {
395             intent = new Intent(Intent.ACTION_GET_CONTENT);
396             intent.setType("image/jpeg"); // TODO Create a Videos category, type = video/*
397         } else if (preference == mPreferences[MISC]) {
398             Context context = getContext().getApplicationContext();
399             if (mMeasurement.getMiscSize() > 0) {
400                 intent = new Intent(context, MiscFilesHandler.class);
401                 intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, mStorageVolume);
402             }
403         }
404
405         return intent;
406     }
407 }