blob: 0cee31df59fd482b465ce58e2b0b806bce6c06c4 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 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
17package com.android.server;
18
19import android.app.Notification;
20import android.app.NotificationManager;
21import android.app.PendingIntent;
22import android.content.BroadcastReceiver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.content.pm.PackageManager;
27import android.content.res.Resources;
28import android.net.Uri;
29import android.os.IMountService;
30import android.os.Environment;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -080031import android.os.ServiceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.os.SystemProperties;
33import android.os.UEventObserver;
San Mehat1f6301e2010-01-07 22:40:27 -080034import android.os.Handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.text.TextUtils;
36import android.util.Log;
San Mehat22dd86e2010-01-12 12:21:18 -080037import java.util.ArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038
San Mehat1f6301e2010-01-07 22:40:27 -080039import android.provider.Settings;
40import android.content.ContentResolver;
41import android.database.ContentObserver;
42
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import java.io.File;
44import java.io.FileReader;
San Mehat36972292010-01-06 11:06:32 -080045import java.lang.IllegalStateException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046
47/**
48 * MountService implements an to the mount service daemon
49 * @hide
50 */
San Mehat22dd86e2010-01-12 12:21:18 -080051class MountService extends IMountService.Stub
52 implements INativeDaemonConnectorCallbacks {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053
54 private static final String TAG = "MountService";
55
San Mehat7fd0fee2009-12-17 07:12:23 -080056 class VolumeState {
57 public static final int Init = -1;
58 public static final int NoMedia = 0;
59 public static final int Idle = 1;
60 public static final int Pending = 2;
61 public static final int Checking = 3;
62 public static final int Mounted = 4;
63 public static final int Unmounting = 5;
64 public static final int Formatting = 6;
65 public static final int Shared = 7;
66 public static final int SharedMnt = 8;
67 }
68
San Mehat22dd86e2010-01-12 12:21:18 -080069 class VoldResponseCode {
70 public static final int VolumeListResult = 110;
71 public static final int AsecListResult = 111;
72
73 public static final int ShareAvailabilityResult = 210;
74 public static final int AsecPathResult = 211;
75
76 public static final int VolumeStateChange = 605;
77 public static final int VolumeMountFailedBlank = 610;
78 public static final int VolumeMountFailedDamaged = 611;
79 public static final int VolumeMountFailedNoMedia = 612;
80 public static final int ShareAvailabilityChange = 620;
81 public static final int VolumeDiskInserted = 630;
82 public static final int VolumeDiskRemoved = 631;
83 public static final int VolumeBadRemoval = 632;
84 }
85
86
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 /**
88 * Binder context for this service
89 */
90 private Context mContext;
91
92 /**
San Mehat22dd86e2010-01-12 12:21:18 -080093 * connectorr object for communicating with vold
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 */
San Mehat22dd86e2010-01-12 12:21:18 -080095 private NativeDaemonConnector mConnector;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096
97 /**
98 * The notification that is shown when a USB mass storage host
99 * is connected.
100 * <p>
101 * This is lazily created, so use {@link #setUsbStorageNotification()}.
102 */
103 private Notification mUsbStorageNotification;
104
105
106 /**
107 * The notification that is shown when the following media events occur:
108 * - Media is being checked
109 * - Media is blank (or unknown filesystem)
110 * - Media is corrupt
111 * - Media is safe to unmount
112 * - Media is missing
113 * <p>
114 * This is lazily created, so use {@link #setMediaStorageNotification()}.
115 */
116 private Notification mMediaStorageNotification;
117
118 private boolean mShowSafeUnmountNotificationWhenUnmounted;
119
120 private boolean mPlaySounds;
121
122 private boolean mMounted;
123
San Mehat1f6301e2010-01-07 22:40:27 -0800124 private SettingsWatcher mSettingsWatcher;
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700125 private boolean mAutoStartUms;
San Mehat1f6301e2010-01-07 22:40:27 -0800126 private boolean mPromptUms;
127 private boolean mUmsActiveNotify;
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700128
San Mehat7fd0fee2009-12-17 07:12:23 -0800129 private boolean mUmsConnected = false;
130 private boolean mUmsEnabled = false;
San Mehat5fbf4092010-01-15 10:13:59 -0800131 private boolean mUmsEnabling = false;
San Mehat7fd0fee2009-12-17 07:12:23 -0800132
133 private String mLegacyState = Environment.MEDIA_REMOVED;
134
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800135 private PackageManagerService mPms;
136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 /**
138 * Constructs a new MountService instance
139 *
140 * @param context Binder context for this service
141 */
142 public MountService(Context context) {
143 mContext = context;
144
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800145 mPms = (PackageManagerService) ServiceManager.getService("package");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 // Register a BOOT_COMPLETED handler so that we can start
San Mehat22dd86e2010-01-12 12:21:18 -0800147 // our NativeDaemonConnector. We defer the startup so that we don't
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148 // start processing events before we ought-to
149 mContext.registerReceiver(mBroadcastReceiver,
150 new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
151
San Mehat22dd86e2010-01-12 12:21:18 -0800152 mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 mShowSafeUnmountNotificationWhenUnmounted = false;
154
155 mPlaySounds = SystemProperties.get("persist.service.mount.playsnd", "1").equals("1");
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700156
San Mehat1f6301e2010-01-07 22:40:27 -0800157 ContentResolver cr = mContext.getContentResolver();
158 mAutoStartUms = (Settings.Secure.getInt(
159 cr, Settings.Secure.MOUNT_UMS_AUTOSTART, 0) == 1);
160 mPromptUms = (Settings.Secure.getInt(
161 cr, Settings.Secure.MOUNT_UMS_PROMPT, 1) == 1);
162 mUmsActiveNotify = (Settings.Secure.getInt(
163 cr, Settings.Secure.MOUNT_UMS_NOTIFY_ENABLED, 1) == 1);
164
165 mSettingsWatcher = new SettingsWatcher(new Handler());
166 }
167
168 private class SettingsWatcher extends ContentObserver {
169 public SettingsWatcher(Handler handler) {
170 super(handler);
171 ContentResolver cr = mContext.getContentResolver();
172 cr.registerContentObserver(Settings.System.getUriFor(
173 Settings.Secure.MOUNT_PLAY_NOTIFICATION_SND), false, this);
174 cr.registerContentObserver(Settings.Secure.getUriFor(
175 Settings.Secure.MOUNT_UMS_AUTOSTART), false, this);
176 cr.registerContentObserver(Settings.Secure.getUriFor(
177 Settings.Secure.MOUNT_UMS_PROMPT), false, this);
178 cr.registerContentObserver(Settings.Secure.getUriFor(
179 Settings.Secure.MOUNT_UMS_NOTIFY_ENABLED), false, this);
180 }
181
182 public void onChange(boolean selfChange) {
183 super.onChange(selfChange);
184 ContentResolver cr = mContext.getContentResolver();
185
186 boolean newPlayNotificationSounds = (Settings.Secure.getInt(
187 cr, Settings.Secure.MOUNT_PLAY_NOTIFICATION_SND, 1) == 1);
188
189 boolean newUmsAutostart = (Settings.Secure.getInt(
190 cr, Settings.Secure.MOUNT_UMS_AUTOSTART, 0) == 1);
191
192 if (newUmsAutostart != mAutoStartUms) {
San Mehat1f6301e2010-01-07 22:40:27 -0800193 mAutoStartUms = newUmsAutostart;
194 }
195
196 boolean newUmsPrompt = (Settings.Secure.getInt(
197 cr, Settings.Secure.MOUNT_UMS_PROMPT, 1) == 1);
198
199 if (newUmsPrompt != mPromptUms) {
San Mehat1f6301e2010-01-07 22:40:27 -0800200 mPromptUms = newUmsAutostart;
201 }
202
203 boolean newUmsNotifyEnabled = (Settings.Secure.getInt(
204 cr, Settings.Secure.MOUNT_UMS_NOTIFY_ENABLED, 1) == 1);
205
San Mehat1f6301e2010-01-07 22:40:27 -0800206 if (mUmsEnabled) {
207 if (newUmsNotifyEnabled) {
208 Intent intent = new Intent();
209 intent.setClass(mContext, com.android.internal.app.UsbStorageStopActivity.class);
210 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
211 setUsbStorageNotification(com.android.internal.R.string.usb_storage_stop_notification_title,
212 com.android.internal.R.string.usb_storage_stop_notification_message,
213 com.android.internal.R.drawable.stat_sys_warning,
214 false, true, pi);
215 } else {
216 setUsbStorageNotification(0, 0, 0, false, false, null);
217 }
218 }
219 if (newUmsNotifyEnabled != mUmsActiveNotify) {
San Mehat1f6301e2010-01-07 22:40:27 -0800220 mUmsActiveNotify = newUmsNotifyEnabled;
221 }
222 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 }
224
225 BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
226 public void onReceive(Context context, Intent intent) {
San Mehat91c77612010-01-07 10:39:41 -0800227 String action = intent.getAction();
228
229 if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
San Mehat22dd86e2010-01-12 12:21:18 -0800230 /*
231 * Vold does not run in the simulator, so fake out a mounted
232 * event to trigger MediaScanner
233 */
234 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
235 notifyMediaMounted(
236 Environment.getExternalStorageDirectory().getPath(), false);
237 return;
238 }
239
240 Thread thread = new Thread(
241 mConnector, NativeDaemonConnector.class.getName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 thread.start();
243 }
244 }
245 };
246
San Mehat91c77612010-01-07 10:39:41 -0800247 public void shutdown() {
248 if (mContext.checkCallingOrSelfPermission(
249 android.Manifest.permission.SHUTDOWN)
250 != PackageManager.PERMISSION_GRANTED) {
251 throw new SecurityException("Requires SHUTDOWN permission");
252 }
253
San Mehat7ebf0172010-01-12 07:57:42 -0800254 Log.d(TAG, "Shutting down");
San Mehat91c77612010-01-07 10:39:41 -0800255 String state = Environment.getExternalStorageState();
256
257 if (state.equals(Environment.MEDIA_SHARED)) {
258 /*
259 * If the media is currently shared, unshare it.
260 * XXX: This is still dangerous!. We should not
261 * be rebooting at *all* if UMS is enabled, since
262 * the UMS host could have dirty FAT cache entries
263 * yet to flush.
264 */
265 try {
266 setMassStorageEnabled(false);
267 } catch (Exception e) {
268 Log.e(TAG, "ums disable failed", e);
269 }
270 } else if (state.equals(Environment.MEDIA_CHECKING)) {
271 /*
272 * If the media is being checked, then we need to wait for
273 * it to complete before being able to proceed.
274 */
275 // XXX: @hackbod - Should we disable the ANR timer here?
276 int retries = 30;
277 while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {
278 try {
279 Thread.sleep(1000);
280 } catch (InterruptedException iex) {
281 Log.e(TAG, "Interrupted while waiting for media", iex);
282 break;
283 }
284 state = Environment.getExternalStorageState();
285 }
286 if (retries == 0) {
287 Log.e(TAG, "Timed out waiting for media to check");
288 }
289 }
290
291 if (state.equals(Environment.MEDIA_MOUNTED)) {
292 /*
293 * If the media is mounted, then gracefully unmount it.
294 */
295 try {
296 String m = Environment.getExternalStorageDirectory().toString();
San Mehat22dd86e2010-01-12 12:21:18 -0800297 unmountVolume(m);
San Mehat7ebf0172010-01-12 07:57:42 -0800298
299 int retries = 12;
300 while (!state.equals(Environment.MEDIA_UNMOUNTED) && (retries-- >=0)) {
301 try {
302 Thread.sleep(1000);
303 } catch (InterruptedException iex) {
304 Log.e(TAG, "Interrupted while waiting for media", iex);
305 break;
306 }
307 state = Environment.getExternalStorageState();
308 }
309 if (retries == 0) {
310 Log.e(TAG, "Timed out waiting for media to unmount");
Jean-Baptiste Querufa101532010-01-12 11:53:42 -0800311 }
San Mehat91c77612010-01-07 10:39:41 -0800312 } catch (Exception e) {
313 Log.e(TAG, "external storage unmount failed", e);
314 }
315 }
316 }
317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 /**
319 * @return true if USB mass storage support is enabled.
320 */
San Mehat36972292010-01-06 11:06:32 -0800321 public boolean getMassStorageEnabled() {
San Mehat7fd0fee2009-12-17 07:12:23 -0800322 return mUmsEnabled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323 }
324
325 /**
326 * Enables or disables USB mass storage support.
327 *
328 * @param enable true to enable USB mass storage support
329 */
San Mehat36972292010-01-06 11:06:32 -0800330 public void setMassStorageEnabled(boolean enable) throws IllegalStateException {
San Mehat1f6301e2010-01-07 22:40:27 -0800331 if (mContext.checkCallingOrSelfPermission(
332 android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
333 != PackageManager.PERMISSION_GRANTED) {
334 throw new SecurityException("Requires MOUNT_UNMOUNT_FILESYSTEMS permission");
335 }
San Mehat7fd0fee2009-12-17 07:12:23 -0800336 try {
337 String vp = Environment.getExternalStorageDirectory().getPath();
338 String vs = getVolumeState(vp);
339
San Mehat5fbf4092010-01-15 10:13:59 -0800340 mUmsEnabling = enable;
San Mehat7fd0fee2009-12-17 07:12:23 -0800341 if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
San Mehat22dd86e2010-01-12 12:21:18 -0800342 unmountVolume(vp);
San Mehat5fbf4092010-01-15 10:13:59 -0800343 mUmsEnabling = false;
San Mehat1f6301e2010-01-07 22:40:27 -0800344 updateUsbMassStorageNotification(true, false);
San Mehat7fd0fee2009-12-17 07:12:23 -0800345 }
346
San Mehat22dd86e2010-01-12 12:21:18 -0800347 setShareMethodEnabled(vp, "ums", enable);
San Mehat7fd0fee2009-12-17 07:12:23 -0800348 mUmsEnabled = enable;
San Mehat5fbf4092010-01-15 10:13:59 -0800349 mUmsEnabling = false;
San Mehat7fd0fee2009-12-17 07:12:23 -0800350 if (!enable) {
San Mehat22dd86e2010-01-12 12:21:18 -0800351 mountVolume(vp);
San Mehat1f6301e2010-01-07 22:40:27 -0800352 if (mPromptUms) {
353 updateUsbMassStorageNotification(false, false);
354 } else {
355 updateUsbMassStorageNotification(true, false);
356 }
San Mehat7fd0fee2009-12-17 07:12:23 -0800357 }
San Mehat36972292010-01-06 11:06:32 -0800358 } catch (IllegalStateException rex) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800359 Log.e(TAG, "Failed to set ums enable {" + enable + "}");
360 return;
361 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 }
363
364 /**
365 * @return true if USB mass storage is connected.
366 */
San Mehat36972292010-01-06 11:06:32 -0800367 public boolean getMassStorageConnected() {
San Mehat7fd0fee2009-12-17 07:12:23 -0800368 return mUmsConnected;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 }
San Mehat7fd0fee2009-12-17 07:12:23 -0800370
371 /**
372 * @return state of the volume at the specified mount point
373 */
San Mehat36972292010-01-06 11:06:32 -0800374 public String getVolumeState(String mountPoint) throws IllegalStateException {
San Mehat7fd0fee2009-12-17 07:12:23 -0800375 /*
376 * XXX: Until we have multiple volume discovery, just hardwire
377 * this to /sdcard
378 */
379 if (!mountPoint.equals(Environment.getExternalStorageDirectory().getPath())) {
380 Log.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume");
381 throw new IllegalArgumentException();
382 }
383
384 return mLegacyState;
385 }
386
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387
388 /**
389 * Attempt to mount external media
390 */
San Mehat22dd86e2010-01-12 12:21:18 -0800391 public void mountVolume(String mountPath) throws IllegalStateException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 if (mContext.checkCallingOrSelfPermission(
393 android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
394 != PackageManager.PERMISSION_GRANTED) {
395 throw new SecurityException("Requires MOUNT_UNMOUNT_FILESYSTEMS permission");
396 }
San Mehat22dd86e2010-01-12 12:21:18 -0800397 mConnector.doCommand(String.format("mount %s", mountPath));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 }
399
400 /**
401 * Attempt to unmount external media to prepare for eject
402 */
San Mehat22dd86e2010-01-12 12:21:18 -0800403 public void unmountVolume(String mountPath) throws IllegalStateException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 if (mContext.checkCallingOrSelfPermission(
405 android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
406 != PackageManager.PERMISSION_GRANTED) {
407 throw new SecurityException("Requires MOUNT_UNMOUNT_FILESYSTEMS permission");
408 }
409
410 // Set a flag so that when we get the unmounted event, we know
411 // to display the notification
412 mShowSafeUnmountNotificationWhenUnmounted = true;
413
San Mehat22dd86e2010-01-12 12:21:18 -0800414 mConnector.doCommand(String.format("unmount %s", mountPath));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 }
416
417 /**
418 * Attempt to format external media
419 */
San Mehat22dd86e2010-01-12 12:21:18 -0800420 public void formatVolume(String formatPath) throws IllegalStateException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 if (mContext.checkCallingOrSelfPermission(
422 android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS)
423 != PackageManager.PERMISSION_GRANTED) {
424 throw new SecurityException("Requires MOUNT_FORMAT_FILESYSTEMS permission");
425 }
426
San Mehat22dd86e2010-01-12 12:21:18 -0800427 mConnector.doCommand(String.format("format %s", formatPath));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 }
429
San Mehat22dd86e2010-01-12 12:21:18 -0800430 boolean getShareAvailable(String method) throws IllegalStateException {
431 ArrayList<String> rsp = mConnector.doCommand("share_available " + method);
432
433 for (String line : rsp) {
434 String []tok = line.split(" ");
435 int code = Integer.parseInt(tok[0]);
436 if (code == VoldResponseCode.ShareAvailabilityResult) {
437 if (tok[2].equals("available"))
438 return true;
439 return false;
440 } else {
441 throw new IllegalStateException(String.format("Unexpected response code %d", code));
442 }
443 }
444 throw new IllegalStateException("Got an empty response");
445 }
446
447 /**
448 * Enables or disables USB mass storage support.
449 *
450 * @param enable true to enable USB mass storage support
451 */
452 void setShareMethodEnabled(String mountPoint, String method,
453 boolean enable) throws IllegalStateException {
454 mConnector.doCommand(String.format(
455 "%sshare %s %s", (enable ? "" : "un"), mountPoint, method));
456 }
457
458
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 /**
460 * Returns true if we're playing media notification sounds.
461 */
462 public boolean getPlayNotificationSounds() {
463 return mPlaySounds;
464 }
465
466 /**
467 * Set whether or not we're playing media notification sounds.
468 */
469 public void setPlayNotificationSounds(boolean enabled) {
470 if (mContext.checkCallingOrSelfPermission(
471 android.Manifest.permission.WRITE_SETTINGS)
472 != PackageManager.PERMISSION_GRANTED) {
473 throw new SecurityException("Requires WRITE_SETTINGS permission");
474 }
475 mPlaySounds = enabled;
476 SystemProperties.set("persist.service.mount.playsnd", (enabled ? "1" : "0"));
477 }
478
San Mehat7fd0fee2009-12-17 07:12:23 -0800479 void updatePublicVolumeState(String mountPoint, String state) {
480 if (!mountPoint.equals(Environment.getExternalStorageDirectory().getPath())) {
481 Log.w(TAG, "Multiple volumes not currently supported");
482 return;
483 }
San Mehat22dd86e2010-01-12 12:21:18 -0800484 Log.i(TAG, "State for {" + mountPoint + "} = {" + state + "}");
San Mehat7fd0fee2009-12-17 07:12:23 -0800485 mLegacyState = state;
486 }
487
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700488 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 * Update the state of the USB mass storage notification
490 */
491 void updateUsbMassStorageNotification(boolean suppressIfConnected, boolean sound) {
492
493 try {
494
495 if (getMassStorageConnected() && !suppressIfConnected) {
496 Intent intent = new Intent();
497 intent.setClass(mContext, com.android.internal.app.UsbStorageActivity.class);
Mike Lockwood95174432009-08-26 09:44:09 -0700498 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
500 setUsbStorageNotification(
501 com.android.internal.R.string.usb_storage_notification_title,
502 com.android.internal.R.string.usb_storage_notification_message,
503 com.android.internal.R.drawable.stat_sys_data_usb,
504 sound, true, pi);
505 } else {
506 setUsbStorageNotification(0, 0, 0, false, false, null);
507 }
San Mehat36972292010-01-06 11:06:32 -0800508 } catch (IllegalStateException e) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 // Nothing to do
510 }
511 }
512
513 void handlePossibleExplicitUnmountBroadcast(String path) {
514 if (mMounted) {
515 mMounted = false;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800516 // Update media status on PackageManagerService to unmount packages on sdcard
517 mPms.updateExternalMediaStatus(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 Intent intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTED,
519 Uri.parse("file://" + path));
520 mContext.sendBroadcast(intent);
521 }
522 }
523
San Mehat22dd86e2010-01-12 12:21:18 -0800524 /**
525 *
526 * Callback from NativeDaemonConnector
527 */
528 public void onDaemonConnected() {
San Mehat7fd0fee2009-12-17 07:12:23 -0800529 new Thread() {
530 public void run() {
531 try {
532 if (!getVolumeState(Environment.getExternalStorageDirectory().getPath())
533 .equals(Environment.MEDIA_MOUNTED)) {
534 try {
San Mehat22dd86e2010-01-12 12:21:18 -0800535 mountVolume(Environment.getExternalStorageDirectory().getPath());
San Mehat7fd0fee2009-12-17 07:12:23 -0800536 } catch (Exception ex) {
537 Log.w(TAG, "Connection-mount failed");
538 }
539 } else {
540 Log.d(TAG, "Skipping connection-mount; already mounted");
541 }
San Mehat36972292010-01-06 11:06:32 -0800542 } catch (IllegalStateException rex) {
San Mehat1f6301e2010-01-07 22:40:27 -0800543 Log.e(TAG, "Exception while handling connection mount ", rex);
San Mehat7fd0fee2009-12-17 07:12:23 -0800544 }
545
546 try {
San Mehat22dd86e2010-01-12 12:21:18 -0800547 boolean avail = getShareAvailable("ums");
San Mehat7fd0fee2009-12-17 07:12:23 -0800548 notifyShareAvailabilityChange("ums", avail);
549 } catch (Exception ex) {
550 Log.w(TAG, "Failed to get share availability");
551 }
552 }
553 }.start();
554 }
555
San Mehat22dd86e2010-01-12 12:21:18 -0800556 /**
557 *
558 * Callback from NativeDaemonConnector
559 */
560 public boolean onEvent(int code, String raw, String[] cooked) {
561 // Log.d(TAG, "event {" + raw + "}");
562 if (code == VoldResponseCode.VolumeStateChange) {
563 // FMT: NNN Volume <label> <mountpoint> state changed
564 // from <old_#> (<old_str>) to <new_#> (<new_str>)
565 notifyVolumeStateChange(
566 cooked[2], cooked[3], Integer.parseInt(cooked[7]),
567 Integer.parseInt(cooked[10]));
568 } else if (code == VoldResponseCode.VolumeMountFailedBlank) {
569 // FMT: NNN Volume <label> <mountpoint> mount failed - no supported file-systems
570 notifyMediaNoFs(cooked[3]);
571 // FMT: NNN Volume <label> <mountpoint> mount failed - no media
572 } else if (code == VoldResponseCode.VolumeMountFailedNoMedia) {
573 notifyMediaRemoved(cooked[3]);
574 } else if (code == VoldResponseCode.VolumeMountFailedDamaged) {
575 // FMT: NNN Volume <label> <mountpoint> mount failed - filesystem check failed
576 notifyMediaUnmountable(cooked[3]);
577 } else if (code == VoldResponseCode.ShareAvailabilityChange) {
578 // FMT: NNN Share method <method> now <available|unavailable>
579 boolean avail = false;
580 if (cooked[5].equals("available")) {
581 avail = true;
582 }
583 notifyShareAvailabilityChange(cooked[3], avail);
584 } else if (code == VoldResponseCode.VolumeDiskInserted) {
585 // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
586 notifyMediaInserted(cooked[3]);
587 } else if (code == VoldResponseCode.VolumeDiskRemoved) {
588 // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
589 notifyMediaRemoved(cooked[3]);
590 } else if (code == VoldResponseCode.VolumeBadRemoval) {
591 // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
592 notifyMediaBadRemoval(cooked[3]);
593 } else {
594 return false;
595 }
596 return true;
597 }
598
San Mehat7fd0fee2009-12-17 07:12:23 -0800599 void notifyVolumeStateChange(String label, String mountPoint, int oldState,
San Mehat36972292010-01-06 11:06:32 -0800600 int newState) throws IllegalStateException {
San Mehat7fd0fee2009-12-17 07:12:23 -0800601 String vs = getVolumeState(mountPoint);
602
603 if (newState == VolumeState.Init) {
604 } else if (newState == VolumeState.NoMedia) {
605 // NoMedia is handled via Disk Remove events
606 } else if (newState == VolumeState.Idle) {
San Mehat5fbf4092010-01-15 10:13:59 -0800607 /*
608 * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or
609 * if we're in the process of enabling UMS
610 */
San Mehat7fd0fee2009-12-17 07:12:23 -0800611 if (!vs.equals(Environment.MEDIA_BAD_REMOVAL) &&
612 !vs.equals(Environment.MEDIA_NOFS) &&
San Mehat5fbf4092010-01-15 10:13:59 -0800613 !vs.equals(Environment.MEDIA_UNMOUNTABLE) &&
614 !mUmsEnabling) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800615 notifyMediaUnmounted(mountPoint);
616 }
617 } else if (newState == VolumeState.Pending) {
618 } else if (newState == VolumeState.Checking) {
619 notifyMediaChecking(mountPoint);
620 } else if (newState == VolumeState.Mounted) {
621 notifyMediaMounted(mountPoint, false);
622 } else if (newState == VolumeState.Unmounting) {
623 notifyMediaUnmounting(mountPoint);
624 } else if (newState == VolumeState.Formatting) {
625 } else if (newState == VolumeState.Shared) {
626 notifyMediaShared(mountPoint, false);
627 } else if (newState == VolumeState.SharedMnt) {
628 notifyMediaShared(mountPoint, true);
629 } else {
630 Log.e(TAG, "Unhandled VolumeState {" + newState + "}");
631 }
632 }
633
634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 /**
636 * Broadcasts the USB mass storage connected event to all clients.
637 */
638 void notifyUmsConnected() {
San Mehat7fd0fee2009-12-17 07:12:23 -0800639 mUmsConnected = true;
640
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641 String storageState = Environment.getExternalStorageState();
642 if (!storageState.equals(Environment.MEDIA_REMOVED) &&
643 !storageState.equals(Environment.MEDIA_BAD_REMOVAL) &&
644 !storageState.equals(Environment.MEDIA_CHECKING)) {
645
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700646 if (mAutoStartUms) {
647 try {
648 setMassStorageEnabled(true);
San Mehat36972292010-01-06 11:06:32 -0800649 } catch (IllegalStateException e) {
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700650 }
San Mehat1f6301e2010-01-07 22:40:27 -0800651 } else if (mPromptUms) {
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700652 updateUsbMassStorageNotification(false, true);
653 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 }
655
656 Intent intent = new Intent(Intent.ACTION_UMS_CONNECTED);
657 mContext.sendBroadcast(intent);
658 }
659
San Mehat1f6301e2010-01-07 22:40:27 -0800660 void notifyShareAvailabilityChange(String method, final boolean avail) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800661 if (!method.equals("ums")) {
662 Log.w(TAG, "Ignoring unsupported share method {" + method + "}");
663 return;
664 }
San Mehat1f6301e2010-01-07 22:40:27 -0800665
666 /*
667 * Notification needs to run in a different thread as
668 * it may need to call back into vold
669 */
670 new Thread() {
671 public void run() {
672 try {
673 if (avail) {
674 notifyUmsConnected();
675 } else {
676 notifyUmsDisconnected();
677 }
678 } catch (Exception ex) {
679 Log.w(TAG, "Failed to mount media on insertion");
680 }
681 }
682 }.start();
San Mehat7fd0fee2009-12-17 07:12:23 -0800683 }
684
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 /**
686 * Broadcasts the USB mass storage disconnected event to all clients.
687 */
688 void notifyUmsDisconnected() {
San Mehat7fd0fee2009-12-17 07:12:23 -0800689 mUmsConnected = false;
San Mehat1f6301e2010-01-07 22:40:27 -0800690 if (mUmsEnabled) {
691 try {
692 Log.w(TAG, "UMS disconnected while enabled!");
693 setMassStorageEnabled(false);
694 } catch (Exception ex) {
695 Log.e(TAG, "Error disabling UMS on unsafe UMS disconnect", ex);
696 }
697 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698 updateUsbMassStorageNotification(false, false);
699 Intent intent = new Intent(Intent.ACTION_UMS_DISCONNECTED);
700 mContext.sendBroadcast(intent);
701 }
702
San Mehat36972292010-01-06 11:06:32 -0800703 void notifyMediaInserted(final String path) throws IllegalStateException {
San Mehat7fd0fee2009-12-17 07:12:23 -0800704 new Thread() {
705 public void run() {
706 try {
San Mehat22dd86e2010-01-12 12:21:18 -0800707 mountVolume(path);
San Mehat7fd0fee2009-12-17 07:12:23 -0800708 } catch (Exception ex) {
San Mehat1f6301e2010-01-07 22:40:27 -0800709 Log.w(TAG, "Failed to mount media on insertion", ex);
San Mehat7fd0fee2009-12-17 07:12:23 -0800710 }
711 }
712 }.start();
713 }
714
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 /**
716 * Broadcasts the media removed event to all clients.
717 */
San Mehat36972292010-01-06 11:06:32 -0800718 void notifyMediaRemoved(String path) throws IllegalStateException {
San Mehat7fd0fee2009-12-17 07:12:23 -0800719
720 // Suppress this on bad removal
721 if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
722 return;
723 }
724
725 updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
726
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 updateUsbMassStorageNotification(true, false);
728
729 setMediaStorageNotification(
San Mehat7fd0fee2009-12-17 07:12:23 -0800730 com.android.internal.R.string.ext_media_nomedia_notification_title,
731 com.android.internal.R.string.ext_media_nomedia_notification_message,
732 com.android.internal.R.drawable.stat_notify_sdcard_usb,
733 true, false, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 handlePossibleExplicitUnmountBroadcast(path);
735
736 Intent intent = new Intent(Intent.ACTION_MEDIA_REMOVED,
737 Uri.parse("file://" + path));
738 mContext.sendBroadcast(intent);
739 }
740
741 /**
742 * Broadcasts the media unmounted event to all clients.
743 */
744 void notifyMediaUnmounted(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800745
746 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
747
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800748 // Update media status on PackageManagerService to unmount packages on sdcard
749 mPms.updateExternalMediaStatus(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 if (mShowSafeUnmountNotificationWhenUnmounted) {
751 setMediaStorageNotification(
752 com.android.internal.R.string.ext_media_safe_unmount_notification_title,
753 com.android.internal.R.string.ext_media_safe_unmount_notification_message,
Mike Lockwoodde46acd2009-09-30 19:30:56 -0400754 com.android.internal.R.drawable.stat_notify_sdcard,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800755 true, true, null);
756 mShowSafeUnmountNotificationWhenUnmounted = false;
757 } else {
758 setMediaStorageNotification(0, 0, 0, false, false, null);
759 }
760 updateUsbMassStorageNotification(false, false);
761
762 Intent intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTED,
763 Uri.parse("file://" + path));
764 mContext.sendBroadcast(intent);
765 }
766
767 /**
768 * Broadcasts the media checking event to all clients.
769 */
770 void notifyMediaChecking(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800771 updatePublicVolumeState(path, Environment.MEDIA_CHECKING);
772
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 setMediaStorageNotification(
774 com.android.internal.R.string.ext_media_checking_notification_title,
775 com.android.internal.R.string.ext_media_checking_notification_message,
Mike Lockwoodde46acd2009-09-30 19:30:56 -0400776 com.android.internal.R.drawable.stat_notify_sdcard_prepare,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 true, false, null);
778
779 updateUsbMassStorageNotification(true, false);
780 Intent intent = new Intent(Intent.ACTION_MEDIA_CHECKING,
781 Uri.parse("file://" + path));
782 mContext.sendBroadcast(intent);
783 }
784
785 /**
786 * Broadcasts the media nofs event to all clients.
787 */
788 void notifyMediaNoFs(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800789 updatePublicVolumeState(path, Environment.MEDIA_NOFS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800790
791 Intent intent = new Intent();
792 intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
793 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
794
795 setMediaStorageNotification(com.android.internal.R.string.ext_media_nofs_notification_title,
796 com.android.internal.R.string.ext_media_nofs_notification_message,
Mike Lockwooda7ef2692009-09-10 11:15:26 -0400797 com.android.internal.R.drawable.stat_notify_sdcard_usb,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 true, false, pi);
799 updateUsbMassStorageNotification(false, false);
800 intent = new Intent(Intent.ACTION_MEDIA_NOFS,
801 Uri.parse("file://" + path));
802 mContext.sendBroadcast(intent);
803 }
804
805 /**
806 * Broadcasts the media mounted event to all clients.
807 */
808 void notifyMediaMounted(String path, boolean readOnly) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800809 updatePublicVolumeState(path, Environment.MEDIA_MOUNTED);
810
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800811 // Update media status on PackageManagerService to mount packages on sdcard
812 mPms.updateExternalMediaStatus(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813 setMediaStorageNotification(0, 0, 0, false, false, null);
814 updateUsbMassStorageNotification(false, false);
815 Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED,
816 Uri.parse("file://" + path));
817 intent.putExtra("read-only", readOnly);
818 mMounted = true;
819 mContext.sendBroadcast(intent);
820 }
821
822 /**
823 * Broadcasts the media shared event to all clients.
824 */
San Mehat7fd0fee2009-12-17 07:12:23 -0800825 void notifyMediaShared(String path, boolean mounted) {
826 if (mounted) {
827 Log.e(TAG, "Live shared mounts not supported yet!");
828 return;
829 }
830
831 updatePublicVolumeState(path, Environment.MEDIA_SHARED);
832
San Mehat1f6301e2010-01-07 22:40:27 -0800833 if (mUmsActiveNotify) {
834 Intent intent = new Intent();
835 intent.setClass(mContext, com.android.internal.app.UsbStorageStopActivity.class);
836 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
837 setUsbStorageNotification(com.android.internal.R.string.usb_storage_stop_notification_title,
838 com.android.internal.R.string.usb_storage_stop_notification_message,
839 com.android.internal.R.drawable.stat_sys_warning,
840 false, true, pi);
841 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800842 handlePossibleExplicitUnmountBroadcast(path);
San Mehat1f6301e2010-01-07 22:40:27 -0800843 Intent intent = new Intent(Intent.ACTION_MEDIA_SHARED,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 Uri.parse("file://" + path));
845 mContext.sendBroadcast(intent);
846 }
847
848 /**
849 * Broadcasts the media bad removal event to all clients.
850 */
851 void notifyMediaBadRemoval(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800852 updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL);
853
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854 updateUsbMassStorageNotification(true, false);
855 setMediaStorageNotification(com.android.internal.R.string.ext_media_badremoval_notification_title,
856 com.android.internal.R.string.ext_media_badremoval_notification_message,
857 com.android.internal.R.drawable.stat_sys_warning,
858 true, true, null);
859
860 handlePossibleExplicitUnmountBroadcast(path);
861 Intent intent = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL,
862 Uri.parse("file://" + path));
863 mContext.sendBroadcast(intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 }
865
866 /**
867 * Broadcasts the media unmountable event to all clients.
868 */
869 void notifyMediaUnmountable(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800870 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE);
871
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800872 Intent intent = new Intent();
873 intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
874 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
875
876 setMediaStorageNotification(com.android.internal.R.string.ext_media_unmountable_notification_title,
877 com.android.internal.R.string.ext_media_unmountable_notification_message,
Mike Lockwooda7ef2692009-09-10 11:15:26 -0400878 com.android.internal.R.drawable.stat_notify_sdcard_usb,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879 true, false, pi);
880 updateUsbMassStorageNotification(false, false);
881
882 handlePossibleExplicitUnmountBroadcast(path);
883
884 intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE,
885 Uri.parse("file://" + path));
886 mContext.sendBroadcast(intent);
887 }
888
889 /**
890 * Broadcasts the media eject event to all clients.
891 */
San Mehat7fd0fee2009-12-17 07:12:23 -0800892 void notifyMediaUnmounting(String path) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800893 Intent intent = new Intent(Intent.ACTION_MEDIA_EJECT,
894 Uri.parse("file://" + path));
895 mContext.sendBroadcast(intent);
896 }
897
898 /**
899 * Sets the USB storage notification.
900 */
901 private synchronized void setUsbStorageNotification(int titleId, int messageId, int icon, boolean sound, boolean visible,
902 PendingIntent pi) {
903
904 if (!visible && mUsbStorageNotification == null) {
905 return;
906 }
907
908 NotificationManager notificationManager = (NotificationManager) mContext
909 .getSystemService(Context.NOTIFICATION_SERVICE);
910
911 if (notificationManager == null) {
912 return;
913 }
914
915 if (visible) {
916 Resources r = Resources.getSystem();
917 CharSequence title = r.getText(titleId);
918 CharSequence message = r.getText(messageId);
919
920 if (mUsbStorageNotification == null) {
921 mUsbStorageNotification = new Notification();
922 mUsbStorageNotification.icon = icon;
923 mUsbStorageNotification.when = 0;
924 }
925
926 if (sound && mPlaySounds) {
927 mUsbStorageNotification.defaults |= Notification.DEFAULT_SOUND;
928 } else {
929 mUsbStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
930 }
931
932 mUsbStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
933
934 mUsbStorageNotification.tickerText = title;
935 if (pi == null) {
936 Intent intent = new Intent();
937 pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
938 }
939
940 mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi);
941 }
942
943 final int notificationId = mUsbStorageNotification.icon;
944 if (visible) {
945 notificationManager.notify(notificationId, mUsbStorageNotification);
946 } else {
947 notificationManager.cancel(notificationId);
948 }
949 }
950
951 private synchronized boolean getMediaStorageNotificationDismissable() {
952 if ((mMediaStorageNotification != null) &&
953 ((mMediaStorageNotification.flags & Notification.FLAG_AUTO_CANCEL) ==
954 Notification.FLAG_AUTO_CANCEL))
955 return true;
956
957 return false;
958 }
959
960 /**
961 * Sets the media storage notification.
962 */
963 private synchronized void setMediaStorageNotification(int titleId, int messageId, int icon, boolean visible,
964 boolean dismissable, PendingIntent pi) {
965
966 if (!visible && mMediaStorageNotification == null) {
967 return;
968 }
969
970 NotificationManager notificationManager = (NotificationManager) mContext
971 .getSystemService(Context.NOTIFICATION_SERVICE);
972
973 if (notificationManager == null) {
974 return;
975 }
976
977 if (mMediaStorageNotification != null && visible) {
978 /*
979 * Dismiss the previous notification - we're about to
980 * re-use it.
981 */
982 final int notificationId = mMediaStorageNotification.icon;
983 notificationManager.cancel(notificationId);
984 }
985
986 if (visible) {
987 Resources r = Resources.getSystem();
988 CharSequence title = r.getText(titleId);
989 CharSequence message = r.getText(messageId);
990
991 if (mMediaStorageNotification == null) {
992 mMediaStorageNotification = new Notification();
993 mMediaStorageNotification.when = 0;
994 }
995
996 if (mPlaySounds) {
997 mMediaStorageNotification.defaults |= Notification.DEFAULT_SOUND;
998 } else {
999 mMediaStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
1000 }
1001
1002 if (dismissable) {
1003 mMediaStorageNotification.flags = Notification.FLAG_AUTO_CANCEL;
1004 } else {
1005 mMediaStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
1006 }
1007
1008 mMediaStorageNotification.tickerText = title;
1009 if (pi == null) {
1010 Intent intent = new Intent();
1011 pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
1012 }
1013
1014 mMediaStorageNotification.icon = icon;
1015 mMediaStorageNotification.setLatestEventInfo(mContext, title, message, pi);
1016 }
1017
1018 final int notificationId = mMediaStorageNotification.icon;
1019 if (visible) {
1020 notificationManager.notify(notificationId, mMediaStorageNotification);
1021 } else {
1022 notificationManager.cancel(notificationId);
1023 }
1024 }
San Mehat36972292010-01-06 11:06:32 -08001025
San Mehat0f5525a2010-01-11 10:15:16 -08001026 public String[] getSecureContainerList() throws IllegalStateException {
San Mehat8ab61352010-01-20 15:16:42 -08001027 return mConnector.doListCommand("list_asec", VoldResponseCode.AsecListResult);
San Mehat36972292010-01-06 11:06:32 -08001028 }
1029
San Mehat0f5525a2010-01-11 10:15:16 -08001030 public String createSecureContainer(String id, int sizeMb, String fstype,
San Mehat36972292010-01-06 11:06:32 -08001031 String key, int ownerUid) throws IllegalStateException {
San Mehat22dd86e2010-01-12 12:21:18 -08001032 String cmd = String.format("create_asec %s %d %s %s %d",
1033 id, sizeMb, fstype, key, ownerUid);
1034 mConnector.doCommand(cmd);
1035 return getSecureContainerPath(id);
San Mehat36972292010-01-06 11:06:32 -08001036 }
1037
San Mehat0f5525a2010-01-11 10:15:16 -08001038 public void finalizeSecureContainer(String id) throws IllegalStateException {
San Mehat22dd86e2010-01-12 12:21:18 -08001039 mConnector.doCommand(String.format("finalize_asec %s", id));
San Mehat36972292010-01-06 11:06:32 -08001040 }
1041
San Mehat0f5525a2010-01-11 10:15:16 -08001042 public void destroySecureContainer(String id) throws IllegalStateException {
San Mehat22dd86e2010-01-12 12:21:18 -08001043 mConnector.doCommand(String.format("destroy_asec %s", id));
San Mehat36972292010-01-06 11:06:32 -08001044 }
1045
San Mehat22dd86e2010-01-12 12:21:18 -08001046 public String mountSecureContainer(String id, String key,
1047 int ownerUid) throws IllegalStateException {
1048 String cmd = String.format("mount_asec %s %s %d",
1049 id, key, ownerUid);
1050 mConnector.doCommand(cmd);
1051 return getSecureContainerPath(id);
San Mehat36972292010-01-06 11:06:32 -08001052 }
1053
San Mehat9dba7092010-01-18 06:47:41 -08001054 public void unmountSecureContainer(String id) throws IllegalStateException {
San Mehat3e3a64302010-01-22 16:46:23 -08001055 String cmd = String.format("unmount_asec %s", id);
San Mehat9dba7092010-01-18 06:47:41 -08001056 mConnector.doCommand(cmd);
1057 }
1058
San Mehat0f5525a2010-01-11 10:15:16 -08001059 public String getSecureContainerPath(String id) throws IllegalStateException {
San Mehat22dd86e2010-01-12 12:21:18 -08001060 ArrayList<String> rsp = mConnector.doCommand("asec_path " + id);
San Mehat36972292010-01-06 11:06:32 -08001061
San Mehat22dd86e2010-01-12 12:21:18 -08001062 for (String line : rsp) {
1063 String []tok = line.split(" ");
1064 int code = Integer.parseInt(tok[0]);
1065 if (code == VoldResponseCode.AsecPathResult) {
1066 return tok[1];
1067 } else {
1068 throw new IllegalStateException(String.format("Unexpected response code %d", code));
1069 }
1070 }
1071 throw new IllegalStateException("Got an empty response");
1072 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073}
1074