2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings.deviceinfo;
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;
42 import com.android.settings.R;
43 import com.android.settings.SettingsPreferenceFragment;
45 public class Memory extends SettingsPreferenceFragment implements OnCancelListener {
46 private static final String TAG = "MemorySettings";
48 private static final int DLG_CONFIRM_UNMOUNT = 1;
49 private static final int DLG_ERROR_UNMOUNT = 2;
51 private Resources mResources;
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;
58 // Access using getMountService()
59 private IMountService mMountService = null;
61 private StorageManager mStorageManager = null;
63 private StorageVolumePreferenceCategory[] mStorageVolumePreferenceCategories;
66 public void onCreate(Bundle icicle) {
67 super.onCreate(icicle);
69 if (mStorageManager == null) {
70 mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
71 mStorageManager.registerListener(mStorageListener);
74 addPreferencesFromResource(R.xml.device_info_memory);
76 mResources = getResources();
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();
93 public void 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);
100 for (int i = 0; i < mStorageVolumePreferenceCategories.length; i++) {
101 mStorageVolumePreferenceCategories[i].onResume();
105 StorageEventListener mStorageListener = new StorageEventListener() {
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 +
111 for (int i = 0; i < mStorageVolumePreferenceCategories.length; i++) {
112 StorageVolumePreferenceCategory svpc = mStorageVolumePreferenceCategories[i];
113 if (path.equals(svpc.getStorageVolume().getPath())) {
114 svpc.onStorageStateChanged();
122 public void onPause() {
124 getActivity().unregisterReceiver(mMediaScannerReceiver);
125 for (int i = 0; i < mStorageVolumePreferenceCategories.length; i++) {
126 mStorageVolumePreferenceCategories[i].onPause();
131 public void onDestroy() {
132 if (mStorageManager != null && mStorageListener != null) {
133 mStorageManager.unregisterListener(mStorageListener);
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);
144 Log.e(TAG, "Can't get mount service");
147 return mMountService;
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);
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)) {
179 private final BroadcastReceiver mMediaScannerReceiver = new BroadcastReceiver() {
181 public void onReceive(Context context, Intent intent) {
182 for (int i = 0; i < mStorageVolumePreferenceCategories.length; i++) {
183 mStorageVolumePreferenceCategories[i].onMediaScannerFinished();
189 public Dialog onCreateDialog(int 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) {
198 .setNegativeButton(R.string.cancel, null)
199 .setMessage(R.string.dlg_confirm_unmount_text)
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)
212 protected void showDialog(int id) {
213 super.showDialog(id);
216 case DLG_CONFIRM_UNMOUNT:
217 case DLG_ERROR_UNMOUNT:
218 setOnCancelListener(this);
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();
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);
236 mClickedMountToggle = null;
239 private void showDialogInner(int id) {
244 private boolean hasAppsAccessingStorage() throws RemoteException {
245 IMountService mountService = getMountService();
246 int stUsers[] = mountService.getStorageUsers(mClickedMountPoint);
247 if (stUsers != null && stUsers.length > 0) {
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
254 ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
255 List<ApplicationInfo> list = am.getRunningExternalApplications();
256 if (list != null && list.size() > 0) {
263 private void unmount() {
264 // Check if external media is in use.
266 if (hasAppsAccessingStorage()) {
267 // Present dialog to user
268 showDialogInner(DLG_CONFIRM_UNMOUNT);
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;
280 private void mount() {
281 IMountService mountService = getMountService();
283 if (mountService != null) {
284 mountService.mountVolume(mClickedMountPoint);
286 Log.e(TAG, "Mount service is null, can't mount");
288 } catch (RemoteException ex) {
289 // Not much can be done
291 mClickedMountToggle = null;
294 public void onCancel(DialogInterface dialog) {
295 mClickedMountToggle = null;