OSDN Git Service

am 95112e5b: (-s ours) Import revised translations. DO NOT MERGE
[android-x86/packages-apps-Settings.git] / src / com / android / settings / deviceinfo / Memory.java
1 /*
2  * Copyright (C) 2008 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 com.android.settings.R;
20 import com.android.settings.SettingsPreferenceFragment;
21 import com.android.settings.deviceinfo.MemoryMeasurement.MeasurementReceiver;
22
23 import android.app.ActivityManager;
24 import android.app.AlertDialog;
25 import android.app.Dialog;
26 import android.content.BroadcastReceiver;
27 import android.content.Context;
28 import android.content.DialogInterface;
29 import android.content.Intent;
30 import android.content.IntentFilter;
31 import android.content.DialogInterface.OnCancelListener;
32 import android.content.pm.ApplicationInfo;
33 import android.content.res.Resources;
34 import android.graphics.drawable.ShapeDrawable;
35 import android.graphics.drawable.shapes.RectShape;
36 import android.graphics.drawable.shapes.RoundRectShape;
37 import android.hardware.UsbManager;
38 import android.os.Bundle;
39 import android.os.Environment;
40 import android.os.Handler;
41 import android.os.IBinder;
42 import android.os.Message;
43 import android.os.RemoteException;
44 import android.os.ServiceManager;
45 import android.os.storage.IMountService;
46 import android.os.storage.StorageEventListener;
47 import android.os.storage.StorageManager;
48 import android.preference.Preference;
49 import android.preference.PreferenceGroup;
50 import android.preference.PreferenceScreen;
51 import android.text.format.Formatter;
52 import android.util.Log;
53 import android.widget.Toast;
54
55 import java.util.List;
56
57 public class Memory extends SettingsPreferenceFragment implements OnCancelListener,
58         MeasurementReceiver {
59     private static final String TAG = "Memory";
60     static final boolean localLOGV = false;
61
62     private static final String MEMORY_SD_SIZE = "memory_sd_size";
63
64     private static final String MEMORY_SD_AVAIL = "memory_sd_avail";
65
66     private static final String MEMORY_SD_MOUNT_TOGGLE = "memory_sd_mount_toggle";
67
68     private static final String MEMORY_SD_FORMAT = "memory_sd_format";
69
70     private static final String MEMORY_SD_GROUP = "memory_sd";
71
72     private static final String MEMORY_INTERNAL_SIZE = "memory_internal_size";
73
74     private static final String MEMORY_INTERNAL_AVAIL = "memory_internal_avail";
75
76     private static final String MEMORY_INTERNAL_APPS = "memory_internal_apps";
77
78     private static final String MEMORY_INTERNAL_MEDIA = "memory_internal_media";
79
80     private static final String MEMORY_INTERNAL_CHART = "memory_internal_chart";
81
82     private static final int DLG_CONFIRM_UNMOUNT = 1;
83     private static final int DLG_ERROR_UNMOUNT = 2;
84
85     private Resources mRes;
86
87     // External storage preferences
88     private Preference mSdSize;
89     private Preference mSdAvail;
90     private Preference mSdMountToggle;
91     private Preference mSdFormat;
92     private PreferenceGroup mSdMountPreferenceGroup;
93
94     // Internal storage preferences
95     private Preference mInternalSize;
96     private Preference mInternalAvail;
97     private Preference mInternalMediaUsage;
98     private Preference mInternalAppsUsage;
99     private UsageBarPreference mInternalUsageChart;
100
101     // Internal storage chart colors
102     private int mInternalMediaColor;
103     private int mInternalAppsColor;
104     private int mInternalUsedColor;
105
106     boolean mSdMountToggleAdded = true;
107     
108     // Access using getMountService()
109     private IMountService mMountService = null;
110
111     private StorageManager mStorageManager = null;
112
113     // Updates the memory usage bar graph.
114     private static final int MSG_UI_UPDATE_INTERNAL_APPROXIMATE = 1;
115
116     // Updates the memory usage bar graph.
117     private static final int MSG_UI_UPDATE_INTERNAL_EXACT = 2;
118
119     // Updates the memory usage stats for external.
120     private static final int MSG_UI_UPDATE_EXTERNAL_APPROXIMATE = 3;
121
122     private Handler mUpdateHandler = new Handler() {
123         @Override
124         public void handleMessage(Message msg) {
125             switch (msg.what) {
126                 case MSG_UI_UPDATE_INTERNAL_APPROXIMATE: {
127                     Bundle bundle = msg.getData();
128                     final long totalSize = bundle.getLong(MemoryMeasurement.TOTAL_SIZE);
129                     final long availSize = bundle.getLong(MemoryMeasurement.AVAIL_SIZE);
130                     updateUiApproximate(totalSize, availSize);
131                     break;
132                 }
133                 case MSG_UI_UPDATE_INTERNAL_EXACT: {
134                     Bundle bundle = msg.getData();
135                     final long totalSize = bundle.getLong(MemoryMeasurement.TOTAL_SIZE);
136                     final long availSize = bundle.getLong(MemoryMeasurement.AVAIL_SIZE);
137                     final long mediaUsed = bundle.getLong(MemoryMeasurement.MEDIA_USED);
138                     final long appsUsed = bundle.getLong(MemoryMeasurement.APPS_USED);
139                     updateUiExact(totalSize, availSize, mediaUsed, appsUsed);
140                     break;
141                 }
142                 case MSG_UI_UPDATE_EXTERNAL_APPROXIMATE: {
143                     Bundle bundle = msg.getData();
144                     final long totalSize = bundle.getLong(MemoryMeasurement.TOTAL_SIZE);
145                     final long availSize = bundle.getLong(MemoryMeasurement.AVAIL_SIZE);
146                     updateExternalStorage(totalSize, availSize);
147                     break;
148                 }
149             }
150         }
151     };
152
153     private MemoryMeasurement mMeasurement;
154
155     @Override
156     public void onCreate(Bundle icicle) {
157         super.onCreate(icicle);
158
159         if (mStorageManager == null) {
160             mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
161             mStorageManager.registerListener(mStorageListener);
162         }
163
164         addPreferencesFromResource(R.xml.device_info_memory);
165
166         mRes = getResources();
167         mSdSize = findPreference(MEMORY_SD_SIZE);
168         mSdAvail = findPreference(MEMORY_SD_AVAIL);
169         mSdMountToggle = findPreference(MEMORY_SD_MOUNT_TOGGLE);
170         mSdFormat = findPreference(MEMORY_SD_FORMAT);
171         mSdMountPreferenceGroup = (PreferenceGroup)findPreference(MEMORY_SD_GROUP);
172
173         if (Environment.isExternalStorageEmulated()) {
174             getPreferenceScreen().removePreference(mSdMountPreferenceGroup);
175         }
176
177         mInternalSize = findPreference(MEMORY_INTERNAL_SIZE);
178         mInternalAvail = findPreference(MEMORY_INTERNAL_AVAIL);
179         mInternalMediaUsage = findPreference(MEMORY_INTERNAL_MEDIA);
180         mInternalAppsUsage = findPreference(MEMORY_INTERNAL_APPS);
181
182         mInternalMediaColor = mRes.getColor(R.color.memory_media_usage);
183         mInternalAppsColor = mRes.getColor(R.color.memory_apps_usage);
184         mInternalUsedColor = mRes.getColor(R.color.memory_used);
185
186         float[] radius = new float[] {
187                 5f, 5f, 5f, 5f, 5f, 5f, 5f, 5f
188         };
189         RoundRectShape shape1 = new RoundRectShape(radius, null, null);
190
191         ShapeDrawable mediaShape = new ShapeDrawable(shape1);
192         mediaShape.setIntrinsicWidth(32);
193         mediaShape.setIntrinsicHeight(32);
194         mediaShape.getPaint().setColor(mInternalMediaColor);
195         mInternalMediaUsage.setIcon(mediaShape);
196
197         ShapeDrawable appsShape = new ShapeDrawable(shape1);
198         appsShape.setIntrinsicWidth(32);
199         appsShape.setIntrinsicHeight(32);
200         appsShape.getPaint().setColor(mInternalAppsColor);
201         mInternalAppsUsage.setIcon(appsShape);
202
203         mInternalUsageChart = (UsageBarPreference) findPreference(MEMORY_INTERNAL_CHART);
204
205         mMeasurement = MemoryMeasurement.getInstance(getActivity());
206         mMeasurement.setReceiver(this);
207     }
208
209     @Override
210     public void onResume() {
211         super.onResume();
212
213         IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_STARTED);
214         intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
215         intentFilter.addDataScheme("file");
216         getActivity().registerReceiver(mReceiver, intentFilter);
217
218         mMeasurement.invalidate();
219         if (!Environment.isExternalStorageEmulated()) {
220             mMeasurement.measureExternal();
221         }
222         mMeasurement.measureInternal();
223     }
224
225     StorageEventListener mStorageListener = new StorageEventListener() {
226         @Override
227         public void onStorageStateChanged(String path, String oldState, String newState) {
228             Log.i(TAG, "Received storage state changed notification that " +
229                     path + " changed state from " + oldState +
230                     " to " + newState);
231             if (!Environment.isExternalStorageEmulated()) {
232                 mMeasurement.measureExternal();
233             }
234         }
235     };
236
237     @Override
238     public void onPause() {
239         super.onPause();
240         getActivity().unregisterReceiver(mReceiver);
241         mMeasurement.cleanUp();
242     }
243
244     @Override
245     public void onDestroy() {
246         if (mStorageManager != null && mStorageListener != null) {
247             mStorageManager.unregisterListener(mStorageListener);
248         }
249         super.onDestroy();
250     }
251
252     private synchronized IMountService getMountService() {
253        if (mMountService == null) {
254            IBinder service = ServiceManager.getService("mount");
255            if (service != null) {
256                mMountService = IMountService.Stub.asInterface(service);
257            } else {
258                Log.e(TAG, "Can't get mount service");
259            }
260        }
261        return mMountService;
262     }
263     
264     @Override
265     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
266         if (preference == mSdMountToggle) {
267             String status = Environment.getExternalStorageState();
268             if (status.equals(Environment.MEDIA_MOUNTED)) {
269                 unmount();
270             } else {
271                 mount();
272             }
273             return true;
274         } else if (preference == mSdFormat) {
275             Intent intent = new Intent(Intent.ACTION_VIEW);
276             intent.setClass(getActivity(), com.android.settings.MediaFormat.class);
277             startActivity(intent);
278             return true;
279         } else if (preference == mInternalAppsUsage) {
280             Intent intent = new Intent(Intent.ACTION_MANAGE_PACKAGE_STORAGE);
281             intent.setClass(getActivity(),
282                     com.android.settings.Settings.ManageApplicationsActivity.class);
283             startActivity(intent);
284             return true;
285         }
286
287         return false;
288     }
289      
290     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
291         @Override
292         public void onReceive(Context context, Intent intent) {
293             mMeasurement.invalidate();
294
295             if (!Environment.isExternalStorageEmulated()) {
296                 mMeasurement.measureExternal();
297             }
298             mMeasurement.measureInternal();
299         }
300     };
301
302     @Override
303     public Dialog onCreateDialog(int id) {
304         switch (id) {
305         case DLG_CONFIRM_UNMOUNT:
306                 return new AlertDialog.Builder(getActivity())
307                     .setTitle(R.string.dlg_confirm_unmount_title)
308                     .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
309                         public void onClick(DialogInterface dialog, int which) {
310                             doUnmount(true);
311                         }})
312                     .setNegativeButton(R.string.cancel, null)
313                     .setMessage(R.string.dlg_confirm_unmount_text)
314                     .setOnCancelListener(this)
315                     .create();
316         case DLG_ERROR_UNMOUNT:
317                 return new AlertDialog.Builder(getActivity())
318             .setTitle(R.string.dlg_error_unmount_title)
319             .setNeutralButton(R.string.dlg_ok, null)
320             .setMessage(R.string.dlg_error_unmount_text)
321             .setOnCancelListener(this)
322             .create();
323         }
324         return null;
325     }
326
327     private void doUnmount(boolean force) {
328         // Present a toast here
329         Toast.makeText(getActivity(), R.string.unmount_inform_text, Toast.LENGTH_SHORT).show();
330         IMountService mountService = getMountService();
331         String extStoragePath = Environment.getExternalStorageDirectory().toString();
332         try {
333             mSdMountToggle.setEnabled(false);
334             mSdMountToggle.setTitle(mRes.getString(R.string.sd_ejecting_title));
335             mSdMountToggle.setSummary(mRes.getString(R.string.sd_ejecting_summary));
336             mountService.unmountVolume(extStoragePath, force);
337         } catch (RemoteException e) {
338             // Informative dialog to user that
339             // unmount failed.
340             showDialogInner(DLG_ERROR_UNMOUNT);
341         }
342     }
343
344     private void showDialogInner(int id) {
345         removeDialog(id);
346         showDialog(id);
347     }
348
349     private boolean hasAppsAccessingStorage() throws RemoteException {
350         String extStoragePath = Environment.getExternalStorageDirectory().toString();
351         IMountService mountService = getMountService();
352         int stUsers[] = mountService.getStorageUsers(extStoragePath);
353         if (stUsers != null && stUsers.length > 0) {
354             return true;
355         }
356         ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
357         List<ApplicationInfo> list = am.getRunningExternalApplications();
358         if (list != null && list.size() > 0) {
359             return true;
360         }
361         return false;
362     }
363
364     private void unmount() {
365         // Check if external media is in use.
366         try {
367            if (hasAppsAccessingStorage()) {
368                if (localLOGV) Log.i(TAG, "Do have storage users accessing media");
369                // Present dialog to user
370                showDialogInner(DLG_CONFIRM_UNMOUNT);
371            } else {
372                doUnmount(true);
373            }
374         } catch (RemoteException e) {
375             // Very unlikely. But present an error dialog anyway
376             Log.e(TAG, "Is MountService running?");
377             showDialogInner(DLG_ERROR_UNMOUNT);
378         }
379     }
380
381     private void mount() {
382         IMountService mountService = getMountService();
383         try {
384             if (mountService != null) {
385                 mountService.mountVolume(Environment.getExternalStorageDirectory().toString());
386             } else {
387                 Log.e(TAG, "Mount service is null, can't mount");
388             }
389         } catch (RemoteException ex) {
390         }
391     }
392
393     private void updateUiExact(long totalSize, long availSize, long mediaSize, long appsSize) {
394         mInternalSize.setSummary(formatSize(totalSize));
395         mInternalAvail.setSummary(formatSize(availSize));
396         mInternalMediaUsage.setSummary(formatSize(mediaSize));
397         mInternalAppsUsage.setSummary(formatSize(appsSize));
398
399         mInternalUsageChart.clear();
400         mInternalUsageChart.addEntry(mediaSize / (float) totalSize, mInternalMediaColor);
401         mInternalUsageChart.addEntry(appsSize / (float) totalSize, mInternalAppsColor);
402
403         final long usedSize = totalSize - availSize;
404
405         // There are other things that can take up storage, but we didn't
406         // measure it.
407         final long remaining = usedSize - (mediaSize + appsSize);
408         if (remaining > 0) {
409             mInternalUsageChart.addEntry(remaining / (float) totalSize, mInternalUsedColor);
410         }
411         mInternalUsageChart.commit();
412     }
413
414     private void updateUiApproximate(long totalSize, long availSize) {
415         mInternalSize.setSummary(formatSize(totalSize));
416         mInternalAvail.setSummary(formatSize(availSize));
417
418         final long usedSize = totalSize - availSize;
419
420         mInternalUsageChart.clear();
421         mInternalUsageChart.addEntry(usedSize / (float) totalSize, mInternalUsedColor);
422         mInternalUsageChart.commit();
423     }
424
425     private void updateExternalStorage(long totalSize, long availSize) {
426         String status = Environment.getExternalStorageState();
427         String readOnly = "";
428         if (status.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
429             status = Environment.MEDIA_MOUNTED;
430             readOnly = mRes.getString(R.string.read_only);
431         }
432
433         if (status.equals(Environment.MEDIA_MOUNTED)) {
434             if (!Environment.isExternalStorageRemovable()) {
435                 // This device has built-in storage that is not removable.
436                 // There is no reason for the user to unmount it.
437                 if (mSdMountToggleAdded) {
438                     mSdMountPreferenceGroup.removePreference(mSdMountToggle);
439                     mSdMountToggleAdded = false;
440                 }
441             }
442             try {
443                 mSdSize.setSummary(formatSize(totalSize));
444                 mSdAvail.setSummary(formatSize(availSize) + readOnly);
445
446                 mSdMountToggle.setEnabled(true);
447                 mSdMountToggle.setTitle(mRes.getString(R.string.sd_eject));
448                 mSdMountToggle.setSummary(mRes.getString(R.string.sd_eject_summary));
449
450             } catch (IllegalArgumentException e) {
451                 // this can occur if the SD card is removed, but we haven't
452                 // received the
453                 // ACTION_MEDIA_REMOVED Intent yet.
454                 status = Environment.MEDIA_REMOVED;
455             }
456         } else {
457             mSdSize.setSummary(mRes.getString(R.string.sd_unavailable));
458             mSdAvail.setSummary(mRes.getString(R.string.sd_unavailable));
459
460             if (!Environment.isExternalStorageRemovable()) {
461                 if (status.equals(Environment.MEDIA_UNMOUNTED)) {
462                     if (!mSdMountToggleAdded) {
463                         mSdMountPreferenceGroup.addPreference(mSdMountToggle);
464                         mSdMountToggleAdded = true;
465                     }
466                 }
467             }
468
469             if (status.equals(Environment.MEDIA_UNMOUNTED) || status.equals(Environment.MEDIA_NOFS)
470                     || status.equals(Environment.MEDIA_UNMOUNTABLE)) {
471                 mSdMountToggle.setEnabled(true);
472                 mSdMountToggle.setTitle(mRes.getString(R.string.sd_mount));
473                 mSdMountToggle.setSummary(mRes.getString(R.string.sd_mount_summary));
474             } else {
475                 mSdMountToggle.setEnabled(false);
476                 mSdMountToggle.setTitle(mRes.getString(R.string.sd_mount));
477                 mSdMountToggle.setSummary(mRes.getString(R.string.sd_insert_summary));
478             }
479         }
480     }
481
482     private String formatSize(long size) {
483         return Formatter.formatFileSize(getActivity(), size);
484     }
485
486     public void onCancel(DialogInterface dialog) {
487         // TODO: Is this really required?
488         // finish();
489     }
490
491     @Override
492     public void updateApproximateExternal(Bundle bundle) {
493         final Message message = mUpdateHandler.obtainMessage(MSG_UI_UPDATE_EXTERNAL_APPROXIMATE);
494         message.setData(bundle);
495         mUpdateHandler.sendMessage(message);
496     }
497
498     @Override
499     public void updateApproximateInternal(Bundle bundle) {
500         final Message message = mUpdateHandler.obtainMessage(MSG_UI_UPDATE_INTERNAL_APPROXIMATE);
501         message.setData(bundle);
502         mUpdateHandler.sendMessage(message);
503     }
504
505     @Override
506     public void updateExactInternal(Bundle bundle) {
507         final Message message = mUpdateHandler.obtainMessage(MSG_UI_UPDATE_INTERNAL_EXACT);
508         message.setData(bundle);
509         mUpdateHandler.sendMessage(message);
510     }
511 }