OSDN Git Service

Merge "Erase SD Card fixed in Settings/Storage." into honeycomb-mr2
[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 android.app.AlertDialog;
20 import android.app.Dialog;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.DialogInterface;
24 import android.content.DialogInterface.OnCancelListener;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.content.res.Resources;
28 import android.os.Bundle;
29 import android.os.Environment;
30 import android.os.IBinder;
31 import android.os.RemoteException;
32 import android.os.ServiceManager;
33 import android.os.storage.IMountService;
34 import android.os.storage.StorageEventListener;
35 import android.os.storage.StorageManager;
36 import android.os.storage.StorageVolume;
37 import android.preference.Preference;
38 import android.preference.PreferenceScreen;
39 import android.util.Log;
40 import android.widget.Toast;
41
42 import com.android.settings.R;
43 import com.android.settings.SettingsPreferenceFragment;
44
45 public class Memory extends SettingsPreferenceFragment implements OnCancelListener {
46     private static final String TAG = "MemorySettings";
47
48     private static final int DLG_CONFIRM_UNMOUNT = 1;
49     private static final int DLG_ERROR_UNMOUNT = 2;
50
51     private Resources mResources;
52
53     // The mountToggle Preference that has been clicked.
54     // The click event will be discarded if this value is not null. Reset to null after (un)mount.
55     private Preference mClickedMountToggle;
56     private String mClickedMountPoint;
57     
58     // Access using getMountService()
59     private IMountService mMountService = null;
60
61     private StorageManager mStorageManager = null;
62
63     private StorageVolumePreferenceCategory[] mStorageVolumePreferenceCategories;
64
65     @Override
66     public void onCreate(Bundle icicle) {
67         super.onCreate(icicle);
68
69         if (mStorageManager == null) {
70             mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
71             mStorageManager.registerListener(mStorageListener);
72         }
73
74         addPreferencesFromResource(R.xml.device_info_memory);
75
76         mResources = getResources();
77
78         StorageVolume[] storageVolumes = mStorageManager.getVolumeList();
79         int length = storageVolumes.length;
80         mStorageVolumePreferenceCategories = new StorageVolumePreferenceCategory[length];
81         for (int i = 0; i < length; i++) {
82             StorageVolume storageVolume = storageVolumes[i];
83             StorageVolumePreferenceCategory storagePreferenceCategory =
84                 new StorageVolumePreferenceCategory(getActivity(), mResources, storageVolume,
85                         mStorageManager, i == 0); // The first volume is the primary volume
86             mStorageVolumePreferenceCategories[i] = storagePreferenceCategory;
87             getPreferenceScreen().addPreference(storagePreferenceCategory);
88             storagePreferenceCategory.init();
89         }
90     }
91
92     @Override
93     public void onResume() {
94         super.onResume();
95         IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_STARTED);
96         intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
97         intentFilter.addDataScheme("file");
98         getActivity().registerReceiver(mMediaScannerReceiver, intentFilter);
99
100         for (int i = 0; i < mStorageVolumePreferenceCategories.length; i++) {
101             mStorageVolumePreferenceCategories[i].onResume();
102         }
103     }
104
105     StorageEventListener mStorageListener = new StorageEventListener() {
106         @Override
107         public void onStorageStateChanged(String path, String oldState, String newState) {
108             Log.i(TAG, "Received storage state changed notification that " +
109                     path + " changed state from " + oldState +
110                     " to " + newState);
111             for (int i = 0; i < mStorageVolumePreferenceCategories.length; i++) {
112                 StorageVolumePreferenceCategory svpc = mStorageVolumePreferenceCategories[i];
113                 if (path.equals(svpc.getStorageVolume().getPath())) {
114                     svpc.onStorageStateChanged();
115                     break;
116                 }
117             }
118         }
119     };
120
121     @Override
122     public void onPause() {
123         super.onPause();
124         getActivity().unregisterReceiver(mMediaScannerReceiver);
125         for (int i = 0; i < mStorageVolumePreferenceCategories.length; i++) {
126             mStorageVolumePreferenceCategories[i].onPause();
127         }
128     }
129
130     @Override
131     public void onDestroy() {
132         if (mStorageManager != null && mStorageListener != null) {
133             mStorageManager.unregisterListener(mStorageListener);
134         }
135         super.onDestroy();
136     }
137
138     private synchronized IMountService getMountService() {
139        if (mMountService == null) {
140            IBinder service = ServiceManager.getService("mount");
141            if (service != null) {
142                mMountService = IMountService.Stub.asInterface(service);
143            } else {
144                Log.e(TAG, "Can't get mount service");
145            }
146        }
147        return mMountService;
148     }
149     
150     @Override
151     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
152         for (int i = 0; i < mStorageVolumePreferenceCategories.length; i++) {
153             StorageVolumePreferenceCategory svpc = mStorageVolumePreferenceCategories[i];
154             Intent intent = svpc.intentForClick(preference);
155             if (intent != null) {
156                 startActivity(intent);
157                 return true;
158             }
159
160             boolean mountToggleClicked = svpc.mountToggleClicked(preference);
161             if (mountToggleClicked && mClickedMountToggle == null) {
162                 mClickedMountToggle = preference;
163                 final StorageVolume storageVolume = svpc.getStorageVolume();
164                 mClickedMountPoint = storageVolume.getPath();
165                 String state = mStorageManager.getVolumeState(storageVolume.getPath());
166                 if (Environment.MEDIA_MOUNTED.equals(state) ||
167                         Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
168                     unmount();
169                 } else {
170                     mount();
171                 }
172                 return true;
173             }
174         }
175
176         return false;
177     }
178      
179     private final BroadcastReceiver mMediaScannerReceiver = new BroadcastReceiver() {
180         @Override
181         public void onReceive(Context context, Intent intent) {
182             for (int i = 0; i < mStorageVolumePreferenceCategories.length; i++) {
183                 mStorageVolumePreferenceCategories[i].onMediaScannerFinished();
184             }
185         }
186     };
187
188     @Override
189     public Dialog onCreateDialog(int id) {
190         switch (id) {
191         case DLG_CONFIRM_UNMOUNT:
192                 return new AlertDialog.Builder(getActivity())
193                     .setTitle(R.string.dlg_confirm_unmount_title)
194                     .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
195                         public void onClick(DialogInterface dialog, int which) {
196                             doUnmount();
197                         }})
198                     .setNegativeButton(R.string.cancel, null)
199                     .setMessage(R.string.dlg_confirm_unmount_text)
200                     .create();
201         case DLG_ERROR_UNMOUNT:
202                 return new AlertDialog.Builder(getActivity())
203             .setTitle(R.string.dlg_error_unmount_title)
204             .setNeutralButton(R.string.dlg_ok, null)
205             .setMessage(R.string.dlg_error_unmount_text)
206             .create();
207         }
208         return null;
209     }
210
211     @Override
212     protected void showDialog(int id) {
213         super.showDialog(id);
214
215         switch (id) {
216             case DLG_CONFIRM_UNMOUNT:
217             case DLG_ERROR_UNMOUNT:
218                 setOnCancelListener(this);
219                 break;
220         }
221     }
222
223     private void doUnmount() {
224         // Present a toast here
225         Toast.makeText(getActivity(), R.string.unmount_inform_text, Toast.LENGTH_SHORT).show();
226         IMountService mountService = getMountService();
227         try {
228             mClickedMountToggle.setEnabled(false);
229             mClickedMountToggle.setTitle(mResources.getString(R.string.sd_ejecting_title));
230             mClickedMountToggle.setSummary(mResources.getString(R.string.sd_ejecting_summary));
231             mountService.unmountVolume(mClickedMountPoint, true);
232         } catch (RemoteException e) {
233             // Informative dialog to user that unmount failed.
234             showDialogInner(DLG_ERROR_UNMOUNT);
235         }
236         mClickedMountToggle = null;
237     }
238
239     private void showDialogInner(int id) {
240         removeDialog(id);
241         showDialog(id);
242     }
243
244     private boolean hasAppsAccessingStorage() throws RemoteException {
245         IMountService mountService = getMountService();
246         int stUsers[] = mountService.getStorageUsers(mClickedMountPoint);
247         if (stUsers != null && stUsers.length > 0) {
248             return true;
249         }
250         // TODO FIXME Parameterize with mountPoint and uncomment.
251         // On HC-MR2, no apps can be installed on sd and the emulated internal storage is not
252         // removable: application cannot interfere with unmount
253         /*
254         ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
255         List<ApplicationInfo> list = am.getRunningExternalApplications();
256         if (list != null && list.size() > 0) {
257             return true;
258         }
259         */
260         return false;
261     }
262
263     private void unmount() {
264         // Check if external media is in use.
265         try {
266            if (hasAppsAccessingStorage()) {
267                // Present dialog to user
268                showDialogInner(DLG_CONFIRM_UNMOUNT);
269            } else {
270                doUnmount();
271            }
272         } catch (RemoteException e) {
273             // Very unlikely. But present an error dialog anyway
274             Log.e(TAG, "Is MountService running?");
275             showDialogInner(DLG_ERROR_UNMOUNT);
276             mClickedMountToggle = null;
277         }
278     }
279
280     private void mount() {
281         IMountService mountService = getMountService();
282         try {
283             if (mountService != null) {
284                 mountService.mountVolume(mClickedMountPoint);
285             } else {
286                 Log.e(TAG, "Mount service is null, can't mount");
287             }
288         } catch (RemoteException ex) {
289             // Not much can be done
290         }
291         mClickedMountToggle = null;
292     }
293
294     public void onCancel(DialogInterface dialog) {
295         mClickedMountToggle = null;
296     }
297 }