OSDN Git Service

am 9a10fb0b: am e8531ff6: Merge "Changed the text input type of APN name to plain...
[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     private 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             mSdMountPreferenceGroup.removePreference(mSdSize);
175             mSdMountPreferenceGroup.removePreference(mSdAvail);
176             mSdMountPreferenceGroup.removePreference(mSdMountToggle);
177         }
178
179         mInternalSize = findPreference(MEMORY_INTERNAL_SIZE);
180         mInternalAvail = findPreference(MEMORY_INTERNAL_AVAIL);
181         mInternalMediaUsage = findPreference(MEMORY_INTERNAL_MEDIA);
182         mInternalAppsUsage = findPreference(MEMORY_INTERNAL_APPS);
183
184         mInternalMediaColor = mRes.getColor(R.color.memory_media_usage);
185         mInternalAppsColor = mRes.getColor(R.color.memory_apps_usage);
186         mInternalUsedColor = mRes.getColor(R.color.memory_used);
187
188         float[] radius = new float[] {
189                 5f, 5f, 5f, 5f, 5f, 5f, 5f, 5f
190         };
191         RoundRectShape shape1 = new RoundRectShape(radius, null, null);
192
193         ShapeDrawable mediaShape = new ShapeDrawable(shape1);
194         mediaShape.setIntrinsicWidth(32);
195         mediaShape.setIntrinsicHeight(32);
196         mediaShape.getPaint().setColor(mInternalMediaColor);
197         mInternalMediaUsage.setIcon(mediaShape);
198
199         ShapeDrawable appsShape = new ShapeDrawable(shape1);
200         appsShape.setIntrinsicWidth(32);
201         appsShape.setIntrinsicHeight(32);
202         appsShape.getPaint().setColor(mInternalAppsColor);
203         mInternalAppsUsage.setIcon(appsShape);
204
205         mInternalUsageChart = (UsageBarPreference) findPreference(MEMORY_INTERNAL_CHART);
206
207         mMeasurement = MemoryMeasurement.getInstance(getActivity());
208         mMeasurement.setReceiver(this);
209     }
210
211     @Override
212     public void onResume() {
213         super.onResume();
214
215         IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_STARTED);
216         intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
217         intentFilter.addDataScheme("file");
218         getActivity().registerReceiver(mReceiver, intentFilter);
219
220         if (!Environment.isExternalStorageEmulated()) {
221             mMeasurement.measureExternal();
222         }
223         mMeasurement.measureInternal();
224     }
225
226     StorageEventListener mStorageListener = new StorageEventListener() {
227         @Override
228         public void onStorageStateChanged(String path, String oldState, String newState) {
229             Log.i(TAG, "Received storage state changed notification that " +
230                     path + " changed state from " + oldState +
231                     " to " + newState);
232             if (!Environment.isExternalStorageEmulated()) {
233                 mMeasurement.measureExternal();
234             }
235         }
236     };
237
238     @Override
239     public void onPause() {
240         super.onPause();
241         getActivity().unregisterReceiver(mReceiver);
242         mMeasurement.cleanUp();
243     }
244
245     @Override
246     public void onDestroy() {
247         if (mStorageManager != null && mStorageListener != null) {
248             mStorageManager.unregisterListener(mStorageListener);
249         }
250         super.onDestroy();
251     }
252
253     private synchronized IMountService getMountService() {
254        if (mMountService == null) {
255            IBinder service = ServiceManager.getService("mount");
256            if (service != null) {
257                mMountService = IMountService.Stub.asInterface(service);
258            } else {
259                Log.e(TAG, "Can't get mount service");
260            }
261        }
262        return mMountService;
263     }
264     
265     @Override
266     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
267         if (preference == mSdMountToggle) {
268             String status = Environment.getExternalStorageState();
269             if (status.equals(Environment.MEDIA_MOUNTED)) {
270                 unmount();
271             } else {
272                 mount();
273             }
274             return true;
275         } else if (preference == mSdFormat) {
276             Intent intent = new Intent(Intent.ACTION_VIEW);
277             intent.setClass(getActivity(), com.android.settings.MediaFormat.class);
278             startActivity(intent);
279             return true;
280         }
281
282         return false;
283     }
284      
285     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
286         @Override
287         public void onReceive(Context context, Intent intent) {
288             mMeasurement.invalidate();
289
290             if (!Environment.isExternalStorageEmulated()) {
291                 mMeasurement.measureExternal();
292             }
293             mMeasurement.measureInternal();
294         }
295     };
296
297     @Override
298     public Dialog onCreateDialog(int id) {
299         switch (id) {
300         case DLG_CONFIRM_UNMOUNT:
301                 return new AlertDialog.Builder(getActivity())
302                     .setTitle(R.string.dlg_confirm_unmount_title)
303                     .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
304                         public void onClick(DialogInterface dialog, int which) {
305                             doUnmount(true);
306                         }})
307                     .setNegativeButton(R.string.cancel, null)
308                     .setMessage(R.string.dlg_confirm_unmount_text)
309                     .setOnCancelListener(this)
310                     .create();
311         case DLG_ERROR_UNMOUNT:
312                 return new AlertDialog.Builder(getActivity())
313             .setTitle(R.string.dlg_error_unmount_title)
314             .setNeutralButton(R.string.dlg_ok, null)
315             .setMessage(R.string.dlg_error_unmount_text)
316             .setOnCancelListener(this)
317             .create();
318         }
319         return null;
320     }
321
322     private void doUnmount(boolean force) {
323         // Present a toast here
324         Toast.makeText(getActivity(), R.string.unmount_inform_text, Toast.LENGTH_SHORT).show();
325         IMountService mountService = getMountService();
326         String extStoragePath = Environment.getExternalStorageDirectory().toString();
327         try {
328             mSdMountToggle.setEnabled(false);
329             mSdMountToggle.setTitle(mRes.getString(R.string.sd_ejecting_title));
330             mSdMountToggle.setSummary(mRes.getString(R.string.sd_ejecting_summary));
331             mountService.unmountVolume(extStoragePath, force);
332         } catch (RemoteException e) {
333             // Informative dialog to user that
334             // unmount failed.
335             showDialogInner(DLG_ERROR_UNMOUNT);
336         }
337     }
338
339     private void showDialogInner(int id) {
340         removeDialog(id);
341         showDialog(id);
342     }
343
344     private boolean hasAppsAccessingStorage() throws RemoteException {
345         String extStoragePath = Environment.getExternalStorageDirectory().toString();
346         IMountService mountService = getMountService();
347         int stUsers[] = mountService.getStorageUsers(extStoragePath);
348         if (stUsers != null && stUsers.length > 0) {
349             return true;
350         }
351         ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
352         List<ApplicationInfo> list = am.getRunningExternalApplications();
353         if (list != null && list.size() > 0) {
354             return true;
355         }
356         return false;
357     }
358
359     private void unmount() {
360         // Check if external media is in use.
361         try {
362            if (hasAppsAccessingStorage()) {
363                if (localLOGV) Log.i(TAG, "Do have storage users accessing media");
364                // Present dialog to user
365                showDialogInner(DLG_CONFIRM_UNMOUNT);
366            } else {
367                doUnmount(true);
368            }
369         } catch (RemoteException e) {
370             // Very unlikely. But present an error dialog anyway
371             Log.e(TAG, "Is MountService running?");
372             showDialogInner(DLG_ERROR_UNMOUNT);
373         }
374     }
375
376     private void mount() {
377         IMountService mountService = getMountService();
378         try {
379             if (mountService != null) {
380                 mountService.mountVolume(Environment.getExternalStorageDirectory().toString());
381             } else {
382                 Log.e(TAG, "Mount service is null, can't mount");
383             }
384         } catch (RemoteException ex) {
385         }
386     }
387
388     private void updateUiExact(long totalSize, long availSize, long mediaSize, long appsSize) {
389         mInternalSize.setSummary(formatSize(totalSize));
390         mInternalAvail.setSummary(formatSize(availSize));
391         mInternalMediaUsage.setSummary(formatSize(mediaSize));
392         mInternalAppsUsage.setSummary(formatSize(appsSize));
393
394         mInternalUsageChart.clear();
395         mInternalUsageChart.addEntry(mediaSize / (float) totalSize, mInternalMediaColor);
396         mInternalUsageChart.addEntry(appsSize / (float) totalSize, mInternalAppsColor);
397
398         final long usedSize = totalSize - availSize;
399
400         // There are other things that can take up storage, but we didn't
401         // measure it.
402         final long remaining = usedSize - (mediaSize + appsSize);
403         if (remaining > 0) {
404             mInternalUsageChart.addEntry(remaining / (float) totalSize, mInternalUsedColor);
405         }
406         mInternalUsageChart.commit();
407     }
408
409     private void updateUiApproximate(long totalSize, long availSize) {
410         mInternalSize.setSummary(formatSize(totalSize));
411         mInternalAvail.setSummary(formatSize(availSize));
412
413         final long usedSize = totalSize - availSize;
414
415         mInternalUsageChart.clear();
416         mInternalUsageChart.addEntry(usedSize / (float) totalSize, mInternalUsedColor);
417         mInternalUsageChart.commit();
418     }
419
420     private void updateExternalStorage(long totalSize, long availSize) {
421         String status = Environment.getExternalStorageState();
422         String readOnly = "";
423         if (status.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
424             status = Environment.MEDIA_MOUNTED;
425             readOnly = mRes.getString(R.string.read_only);
426         }
427
428         if (status.equals(Environment.MEDIA_MOUNTED)) {
429             if (!Environment.isExternalStorageRemovable()) {
430                 // This device has built-in storage that is not removable.
431                 // There is no reason for the user to unmount it.
432                 if (mSdMountToggleAdded) {
433                     mSdMountPreferenceGroup.removePreference(mSdMountToggle);
434                     mSdMountToggleAdded = false;
435                 }
436             }
437             try {
438                 mSdSize.setSummary(formatSize(totalSize));
439                 mSdAvail.setSummary(formatSize(availSize) + readOnly);
440
441                 mSdMountToggle.setEnabled(true);
442                 mSdMountToggle.setTitle(mRes.getString(R.string.sd_eject));
443                 mSdMountToggle.setSummary(mRes.getString(R.string.sd_eject_summary));
444
445             } catch (IllegalArgumentException e) {
446                 // this can occur if the SD card is removed, but we haven't
447                 // received the
448                 // ACTION_MEDIA_REMOVED Intent yet.
449                 status = Environment.MEDIA_REMOVED;
450             }
451         } else {
452             mSdSize.setSummary(mRes.getString(R.string.sd_unavailable));
453             mSdAvail.setSummary(mRes.getString(R.string.sd_unavailable));
454
455             if (!Environment.isExternalStorageRemovable()) {
456                 if (status.equals(Environment.MEDIA_UNMOUNTED)) {
457                     if (!mSdMountToggleAdded) {
458                         mSdMountPreferenceGroup.addPreference(mSdMountToggle);
459                         mSdMountToggleAdded = true;
460                     }
461                 }
462             }
463
464             if (status.equals(Environment.MEDIA_UNMOUNTED) || status.equals(Environment.MEDIA_NOFS)
465                     || status.equals(Environment.MEDIA_UNMOUNTABLE)) {
466                 mSdMountToggle.setEnabled(true);
467                 mSdMountToggle.setTitle(mRes.getString(R.string.sd_mount));
468                 mSdMountToggle.setSummary(mRes.getString(R.string.sd_mount_summary));
469             } else {
470                 mSdMountToggle.setEnabled(false);
471                 mSdMountToggle.setTitle(mRes.getString(R.string.sd_mount));
472                 mSdMountToggle.setSummary(mRes.getString(R.string.sd_insert_summary));
473             }
474         }
475     }
476
477     private String formatSize(long size) {
478         return Formatter.formatFileSize(getActivity(), size);
479     }
480
481     public void onCancel(DialogInterface dialog) {
482         // TODO: Is this really required?
483         // finish();
484     }
485
486     @Override
487     public void updateApproximateExternal(Bundle bundle) {
488         final Message message = mUpdateHandler.obtainMessage(MSG_UI_UPDATE_EXTERNAL_APPROXIMATE);
489         message.setData(bundle);
490         mUpdateHandler.sendMessage(message);
491     }
492
493     @Override
494     public void updateApproximateInternal(Bundle bundle) {
495         final Message message = mUpdateHandler.obtainMessage(MSG_UI_UPDATE_INTERNAL_APPROXIMATE);
496         message.setData(bundle);
497         mUpdateHandler.sendMessage(message);
498     }
499
500     @Override
501     public void updateExactInternal(Bundle bundle) {
502         final Message message = mUpdateHandler.obtainMessage(MSG_UI_UPDATE_INTERNAL_EXACT);
503         message.setData(bundle);
504         mUpdateHandler.sendMessage(message);
505     }
506 }