blob: 85a2e0bf751edf802334f05b1181e27dc52b3590 [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 Mehat5b77dab2010-01-26 13:28:50 -0800529 /*
530 * Since we'll be calling back into the NativeDaemonConnector,
531 * we need to do our work in a new thread.
532 */
San Mehat7fd0fee2009-12-17 07:12:23 -0800533 new Thread() {
534 public void run() {
San Mehat5b77dab2010-01-26 13:28:50 -0800535 /**
536 * Determine media state and UMS detection status
537 */
538 String path = Environment.getExternalStorageDirectory().getPath();
539 String state = Environment.MEDIA_REMOVED;
540
San Mehat7fd0fee2009-12-17 07:12:23 -0800541 try {
San Mehat5b77dab2010-01-26 13:28:50 -0800542 String[] vols = mConnector.doListCommand(
543 "list_volumes", VoldResponseCode.VolumeListResult);
544 for (String volstr : vols) {
545 String[] tok = volstr.split(" ");
546 // FMT: <label> <mountpoint> <state>
547 if (!tok[1].equals(path)) {
548 Log.w(TAG, String.format(
549 "Skipping unknown volume '%s'",tok[1]));
550 continue;
San Mehat7fd0fee2009-12-17 07:12:23 -0800551 }
San Mehat5b77dab2010-01-26 13:28:50 -0800552 int st = Integer.parseInt(tok[2]);
553 if (st == VolumeState.NoMedia) {
554 state = Environment.MEDIA_REMOVED;
555 } else if (st == VolumeState.Idle) {
556 state = Environment.MEDIA_UNMOUNTED;
557 try {
558 mountVolume(path);
559 } catch (Exception ex) {
560 Log.e(TAG, "Connection-mount failed", ex);
561 }
562 } else if (st == VolumeState.Mounted) {
563 state = Environment.MEDIA_MOUNTED;
564 Log.i(TAG, "Media already mounted on daemon connection");
565 } else if (st == VolumeState.Shared) {
566 state = Environment.MEDIA_SHARED;
567 Log.i(TAG, "Media shared on daemon connection");
568 } else {
569 throw new Exception(String.format("Unexpected state %d", st));
570 }
San Mehat7fd0fee2009-12-17 07:12:23 -0800571 }
San Mehat5b77dab2010-01-26 13:28:50 -0800572 updatePublicVolumeState(path, state);
573 } catch (Exception e) {
574 Log.e(TAG, "Error processing initial volume state", e);
575 updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
San Mehat7fd0fee2009-12-17 07:12:23 -0800576 }
577
578 try {
San Mehat22dd86e2010-01-12 12:21:18 -0800579 boolean avail = getShareAvailable("ums");
San Mehat7fd0fee2009-12-17 07:12:23 -0800580 notifyShareAvailabilityChange("ums", avail);
581 } catch (Exception ex) {
582 Log.w(TAG, "Failed to get share availability");
583 }
584 }
585 }.start();
586 }
587
San Mehat22dd86e2010-01-12 12:21:18 -0800588 /**
589 *
590 * Callback from NativeDaemonConnector
591 */
592 public boolean onEvent(int code, String raw, String[] cooked) {
593 // Log.d(TAG, "event {" + raw + "}");
594 if (code == VoldResponseCode.VolumeStateChange) {
595 // FMT: NNN Volume <label> <mountpoint> state changed
596 // from <old_#> (<old_str>) to <new_#> (<new_str>)
597 notifyVolumeStateChange(
598 cooked[2], cooked[3], Integer.parseInt(cooked[7]),
599 Integer.parseInt(cooked[10]));
600 } else if (code == VoldResponseCode.VolumeMountFailedBlank) {
601 // FMT: NNN Volume <label> <mountpoint> mount failed - no supported file-systems
602 notifyMediaNoFs(cooked[3]);
603 // FMT: NNN Volume <label> <mountpoint> mount failed - no media
604 } else if (code == VoldResponseCode.VolumeMountFailedNoMedia) {
605 notifyMediaRemoved(cooked[3]);
606 } else if (code == VoldResponseCode.VolumeMountFailedDamaged) {
607 // FMT: NNN Volume <label> <mountpoint> mount failed - filesystem check failed
608 notifyMediaUnmountable(cooked[3]);
609 } else if (code == VoldResponseCode.ShareAvailabilityChange) {
610 // FMT: NNN Share method <method> now <available|unavailable>
611 boolean avail = false;
612 if (cooked[5].equals("available")) {
613 avail = true;
614 }
615 notifyShareAvailabilityChange(cooked[3], avail);
616 } else if (code == VoldResponseCode.VolumeDiskInserted) {
617 // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
618 notifyMediaInserted(cooked[3]);
619 } else if (code == VoldResponseCode.VolumeDiskRemoved) {
620 // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
621 notifyMediaRemoved(cooked[3]);
622 } else if (code == VoldResponseCode.VolumeBadRemoval) {
623 // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
624 notifyMediaBadRemoval(cooked[3]);
625 } else {
626 return false;
627 }
628 return true;
629 }
630
San Mehat7fd0fee2009-12-17 07:12:23 -0800631 void notifyVolumeStateChange(String label, String mountPoint, int oldState,
San Mehat36972292010-01-06 11:06:32 -0800632 int newState) throws IllegalStateException {
San Mehat7fd0fee2009-12-17 07:12:23 -0800633 String vs = getVolumeState(mountPoint);
634
635 if (newState == VolumeState.Init) {
636 } else if (newState == VolumeState.NoMedia) {
637 // NoMedia is handled via Disk Remove events
638 } else if (newState == VolumeState.Idle) {
San Mehat5fbf4092010-01-15 10:13:59 -0800639 /*
640 * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or
641 * if we're in the process of enabling UMS
642 */
San Mehat7fd0fee2009-12-17 07:12:23 -0800643 if (!vs.equals(Environment.MEDIA_BAD_REMOVAL) &&
644 !vs.equals(Environment.MEDIA_NOFS) &&
San Mehat5fbf4092010-01-15 10:13:59 -0800645 !vs.equals(Environment.MEDIA_UNMOUNTABLE) &&
646 !mUmsEnabling) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800647 notifyMediaUnmounted(mountPoint);
648 }
649 } else if (newState == VolumeState.Pending) {
650 } else if (newState == VolumeState.Checking) {
651 notifyMediaChecking(mountPoint);
652 } else if (newState == VolumeState.Mounted) {
653 notifyMediaMounted(mountPoint, false);
654 } else if (newState == VolumeState.Unmounting) {
655 notifyMediaUnmounting(mountPoint);
656 } else if (newState == VolumeState.Formatting) {
657 } else if (newState == VolumeState.Shared) {
658 notifyMediaShared(mountPoint, false);
659 } else if (newState == VolumeState.SharedMnt) {
660 notifyMediaShared(mountPoint, true);
661 } else {
662 Log.e(TAG, "Unhandled VolumeState {" + newState + "}");
663 }
664 }
665
666
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 /**
668 * Broadcasts the USB mass storage connected event to all clients.
669 */
670 void notifyUmsConnected() {
San Mehat7fd0fee2009-12-17 07:12:23 -0800671 mUmsConnected = true;
672
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800673 String storageState = Environment.getExternalStorageState();
674 if (!storageState.equals(Environment.MEDIA_REMOVED) &&
675 !storageState.equals(Environment.MEDIA_BAD_REMOVAL) &&
676 !storageState.equals(Environment.MEDIA_CHECKING)) {
677
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700678 if (mAutoStartUms) {
679 try {
680 setMassStorageEnabled(true);
San Mehat36972292010-01-06 11:06:32 -0800681 } catch (IllegalStateException e) {
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700682 }
San Mehat1f6301e2010-01-07 22:40:27 -0800683 } else if (mPromptUms) {
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700684 updateUsbMassStorageNotification(false, true);
685 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 }
687
688 Intent intent = new Intent(Intent.ACTION_UMS_CONNECTED);
689 mContext.sendBroadcast(intent);
690 }
691
San Mehat1f6301e2010-01-07 22:40:27 -0800692 void notifyShareAvailabilityChange(String method, final boolean avail) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800693 if (!method.equals("ums")) {
694 Log.w(TAG, "Ignoring unsupported share method {" + method + "}");
695 return;
696 }
San Mehat1f6301e2010-01-07 22:40:27 -0800697
698 /*
699 * Notification needs to run in a different thread as
700 * it may need to call back into vold
701 */
702 new Thread() {
703 public void run() {
704 try {
705 if (avail) {
706 notifyUmsConnected();
707 } else {
708 notifyUmsDisconnected();
709 }
710 } catch (Exception ex) {
711 Log.w(TAG, "Failed to mount media on insertion");
712 }
713 }
714 }.start();
San Mehat7fd0fee2009-12-17 07:12:23 -0800715 }
716
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717 /**
718 * Broadcasts the USB mass storage disconnected event to all clients.
719 */
720 void notifyUmsDisconnected() {
San Mehat7fd0fee2009-12-17 07:12:23 -0800721 mUmsConnected = false;
San Mehat1f6301e2010-01-07 22:40:27 -0800722 if (mUmsEnabled) {
723 try {
724 Log.w(TAG, "UMS disconnected while enabled!");
725 setMassStorageEnabled(false);
726 } catch (Exception ex) {
727 Log.e(TAG, "Error disabling UMS on unsafe UMS disconnect", ex);
728 }
729 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 updateUsbMassStorageNotification(false, false);
731 Intent intent = new Intent(Intent.ACTION_UMS_DISCONNECTED);
732 mContext.sendBroadcast(intent);
733 }
734
San Mehat36972292010-01-06 11:06:32 -0800735 void notifyMediaInserted(final String path) throws IllegalStateException {
San Mehat7fd0fee2009-12-17 07:12:23 -0800736 new Thread() {
737 public void run() {
738 try {
San Mehat22dd86e2010-01-12 12:21:18 -0800739 mountVolume(path);
San Mehat7fd0fee2009-12-17 07:12:23 -0800740 } catch (Exception ex) {
San Mehat1f6301e2010-01-07 22:40:27 -0800741 Log.w(TAG, "Failed to mount media on insertion", ex);
San Mehat7fd0fee2009-12-17 07:12:23 -0800742 }
743 }
744 }.start();
745 }
746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 /**
748 * Broadcasts the media removed event to all clients.
749 */
San Mehat36972292010-01-06 11:06:32 -0800750 void notifyMediaRemoved(String path) throws IllegalStateException {
San Mehat7fd0fee2009-12-17 07:12:23 -0800751
752 // Suppress this on bad removal
753 if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
754 return;
755 }
756
757 updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
758
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 updateUsbMassStorageNotification(true, false);
760
761 setMediaStorageNotification(
San Mehat7fd0fee2009-12-17 07:12:23 -0800762 com.android.internal.R.string.ext_media_nomedia_notification_title,
763 com.android.internal.R.string.ext_media_nomedia_notification_message,
764 com.android.internal.R.drawable.stat_notify_sdcard_usb,
765 true, false, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 handlePossibleExplicitUnmountBroadcast(path);
767
768 Intent intent = new Intent(Intent.ACTION_MEDIA_REMOVED,
769 Uri.parse("file://" + path));
770 mContext.sendBroadcast(intent);
771 }
772
773 /**
774 * Broadcasts the media unmounted event to all clients.
775 */
776 void notifyMediaUnmounted(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800777
778 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
779
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800780 // Update media status on PackageManagerService to unmount packages on sdcard
781 mPms.updateExternalMediaStatus(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782 if (mShowSafeUnmountNotificationWhenUnmounted) {
783 setMediaStorageNotification(
784 com.android.internal.R.string.ext_media_safe_unmount_notification_title,
785 com.android.internal.R.string.ext_media_safe_unmount_notification_message,
Mike Lockwoodde46acdd2009-09-30 19:30:56 -0400786 com.android.internal.R.drawable.stat_notify_sdcard,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787 true, true, null);
788 mShowSafeUnmountNotificationWhenUnmounted = false;
789 } else {
790 setMediaStorageNotification(0, 0, 0, false, false, null);
791 }
792 updateUsbMassStorageNotification(false, false);
793
794 Intent intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTED,
795 Uri.parse("file://" + path));
796 mContext.sendBroadcast(intent);
797 }
798
799 /**
800 * Broadcasts the media checking event to all clients.
801 */
802 void notifyMediaChecking(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800803 updatePublicVolumeState(path, Environment.MEDIA_CHECKING);
804
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 setMediaStorageNotification(
806 com.android.internal.R.string.ext_media_checking_notification_title,
807 com.android.internal.R.string.ext_media_checking_notification_message,
Mike Lockwoodde46acdd2009-09-30 19:30:56 -0400808 com.android.internal.R.drawable.stat_notify_sdcard_prepare,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 true, false, null);
810
811 updateUsbMassStorageNotification(true, false);
812 Intent intent = new Intent(Intent.ACTION_MEDIA_CHECKING,
813 Uri.parse("file://" + path));
814 mContext.sendBroadcast(intent);
815 }
816
817 /**
818 * Broadcasts the media nofs event to all clients.
819 */
820 void notifyMediaNoFs(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800821 updatePublicVolumeState(path, Environment.MEDIA_NOFS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822
823 Intent intent = new Intent();
824 intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
825 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
826
827 setMediaStorageNotification(com.android.internal.R.string.ext_media_nofs_notification_title,
828 com.android.internal.R.string.ext_media_nofs_notification_message,
Mike Lockwooda7ef2692009-09-10 11:15:26 -0400829 com.android.internal.R.drawable.stat_notify_sdcard_usb,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800830 true, false, pi);
831 updateUsbMassStorageNotification(false, false);
832 intent = new Intent(Intent.ACTION_MEDIA_NOFS,
833 Uri.parse("file://" + path));
834 mContext.sendBroadcast(intent);
835 }
836
837 /**
838 * Broadcasts the media mounted event to all clients.
839 */
840 void notifyMediaMounted(String path, boolean readOnly) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800841 updatePublicVolumeState(path, Environment.MEDIA_MOUNTED);
842
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800843 // Update media status on PackageManagerService to mount packages on sdcard
844 mPms.updateExternalMediaStatus(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845 setMediaStorageNotification(0, 0, 0, false, false, null);
846 updateUsbMassStorageNotification(false, false);
847 Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED,
848 Uri.parse("file://" + path));
849 intent.putExtra("read-only", readOnly);
850 mMounted = true;
851 mContext.sendBroadcast(intent);
852 }
853
854 /**
855 * Broadcasts the media shared event to all clients.
856 */
San Mehat7fd0fee2009-12-17 07:12:23 -0800857 void notifyMediaShared(String path, boolean mounted) {
858 if (mounted) {
859 Log.e(TAG, "Live shared mounts not supported yet!");
860 return;
861 }
862
863 updatePublicVolumeState(path, Environment.MEDIA_SHARED);
864
San Mehat1f6301e2010-01-07 22:40:27 -0800865 if (mUmsActiveNotify) {
866 Intent intent = new Intent();
867 intent.setClass(mContext, com.android.internal.app.UsbStorageStopActivity.class);
868 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
869 setUsbStorageNotification(com.android.internal.R.string.usb_storage_stop_notification_title,
870 com.android.internal.R.string.usb_storage_stop_notification_message,
871 com.android.internal.R.drawable.stat_sys_warning,
872 false, true, pi);
873 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 handlePossibleExplicitUnmountBroadcast(path);
San Mehat1f6301e2010-01-07 22:40:27 -0800875 Intent intent = new Intent(Intent.ACTION_MEDIA_SHARED,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 Uri.parse("file://" + path));
877 mContext.sendBroadcast(intent);
878 }
879
880 /**
881 * Broadcasts the media bad removal event to all clients.
882 */
883 void notifyMediaBadRemoval(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800884 updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL);
885
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800886 updateUsbMassStorageNotification(true, false);
887 setMediaStorageNotification(com.android.internal.R.string.ext_media_badremoval_notification_title,
888 com.android.internal.R.string.ext_media_badremoval_notification_message,
889 com.android.internal.R.drawable.stat_sys_warning,
890 true, true, null);
891
892 handlePossibleExplicitUnmountBroadcast(path);
893 Intent intent = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL,
894 Uri.parse("file://" + path));
895 mContext.sendBroadcast(intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800896 }
897
898 /**
899 * Broadcasts the media unmountable event to all clients.
900 */
901 void notifyMediaUnmountable(String path) {
San Mehat7fd0fee2009-12-17 07:12:23 -0800902 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE);
903
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 Intent intent = new Intent();
905 intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
906 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
907
908 setMediaStorageNotification(com.android.internal.R.string.ext_media_unmountable_notification_title,
909 com.android.internal.R.string.ext_media_unmountable_notification_message,
Mike Lockwooda7ef2692009-09-10 11:15:26 -0400910 com.android.internal.R.drawable.stat_notify_sdcard_usb,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 true, false, pi);
912 updateUsbMassStorageNotification(false, false);
913
914 handlePossibleExplicitUnmountBroadcast(path);
915
916 intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE,
917 Uri.parse("file://" + path));
918 mContext.sendBroadcast(intent);
919 }
920
921 /**
922 * Broadcasts the media eject event to all clients.
923 */
San Mehat7fd0fee2009-12-17 07:12:23 -0800924 void notifyMediaUnmounting(String path) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800925 Intent intent = new Intent(Intent.ACTION_MEDIA_EJECT,
926 Uri.parse("file://" + path));
927 mContext.sendBroadcast(intent);
928 }
929
930 /**
931 * Sets the USB storage notification.
932 */
933 private synchronized void setUsbStorageNotification(int titleId, int messageId, int icon, boolean sound, boolean visible,
934 PendingIntent pi) {
935
936 if (!visible && mUsbStorageNotification == null) {
937 return;
938 }
939
940 NotificationManager notificationManager = (NotificationManager) mContext
941 .getSystemService(Context.NOTIFICATION_SERVICE);
942
943 if (notificationManager == null) {
944 return;
945 }
946
947 if (visible) {
948 Resources r = Resources.getSystem();
949 CharSequence title = r.getText(titleId);
950 CharSequence message = r.getText(messageId);
951
952 if (mUsbStorageNotification == null) {
953 mUsbStorageNotification = new Notification();
954 mUsbStorageNotification.icon = icon;
955 mUsbStorageNotification.when = 0;
956 }
957
958 if (sound && mPlaySounds) {
959 mUsbStorageNotification.defaults |= Notification.DEFAULT_SOUND;
960 } else {
961 mUsbStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
962 }
963
964 mUsbStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
965
966 mUsbStorageNotification.tickerText = title;
967 if (pi == null) {
968 Intent intent = new Intent();
969 pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
970 }
971
972 mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi);
973 }
974
975 final int notificationId = mUsbStorageNotification.icon;
976 if (visible) {
977 notificationManager.notify(notificationId, mUsbStorageNotification);
978 } else {
979 notificationManager.cancel(notificationId);
980 }
981 }
982
983 private synchronized boolean getMediaStorageNotificationDismissable() {
984 if ((mMediaStorageNotification != null) &&
985 ((mMediaStorageNotification.flags & Notification.FLAG_AUTO_CANCEL) ==
986 Notification.FLAG_AUTO_CANCEL))
987 return true;
988
989 return false;
990 }
991
992 /**
993 * Sets the media storage notification.
994 */
995 private synchronized void setMediaStorageNotification(int titleId, int messageId, int icon, boolean visible,
996 boolean dismissable, PendingIntent pi) {
997
998 if (!visible && mMediaStorageNotification == null) {
999 return;
1000 }
1001
1002 NotificationManager notificationManager = (NotificationManager) mContext
1003 .getSystemService(Context.NOTIFICATION_SERVICE);
1004
1005 if (notificationManager == null) {
1006 return;
1007 }
1008
1009 if (mMediaStorageNotification != null && visible) {
1010 /*
1011 * Dismiss the previous notification - we're about to
1012 * re-use it.
1013 */
1014 final int notificationId = mMediaStorageNotification.icon;
1015 notificationManager.cancel(notificationId);
1016 }
1017
1018 if (visible) {
1019 Resources r = Resources.getSystem();
1020 CharSequence title = r.getText(titleId);
1021 CharSequence message = r.getText(messageId);
1022
1023 if (mMediaStorageNotification == null) {
1024 mMediaStorageNotification = new Notification();
1025 mMediaStorageNotification.when = 0;
1026 }
1027
1028 if (mPlaySounds) {
1029 mMediaStorageNotification.defaults |= Notification.DEFAULT_SOUND;
1030 } else {
1031 mMediaStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
1032 }
1033
1034 if (dismissable) {
1035 mMediaStorageNotification.flags = Notification.FLAG_AUTO_CANCEL;
1036 } else {
1037 mMediaStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
1038 }
1039
1040 mMediaStorageNotification.tickerText = title;
1041 if (pi == null) {
1042 Intent intent = new Intent();
1043 pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
1044 }
1045
1046 mMediaStorageNotification.icon = icon;
1047 mMediaStorageNotification.setLatestEventInfo(mContext, title, message, pi);
1048 }
1049
1050 final int notificationId = mMediaStorageNotification.icon;
1051 if (visible) {
1052 notificationManager.notify(notificationId, mMediaStorageNotification);
1053 } else {
1054 notificationManager.cancel(notificationId);
1055 }
1056 }
San Mehat36972292010-01-06 11:06:32 -08001057
San Mehat0f5525a2010-01-11 10:15:16 -08001058 public String[] getSecureContainerList() throws IllegalStateException {
San Mehat8ab61352010-01-20 15:16:42 -08001059 return mConnector.doListCommand("list_asec", VoldResponseCode.AsecListResult);
San Mehat36972292010-01-06 11:06:32 -08001060 }
1061
San Mehat0f5525a2010-01-11 10:15:16 -08001062 public String createSecureContainer(String id, int sizeMb, String fstype,
San Mehat36972292010-01-06 11:06:32 -08001063 String key, int ownerUid) throws IllegalStateException {
San Mehat22dd86e2010-01-12 12:21:18 -08001064 String cmd = String.format("create_asec %s %d %s %s %d",
1065 id, sizeMb, fstype, key, ownerUid);
1066 mConnector.doCommand(cmd);
1067 return getSecureContainerPath(id);
San Mehat36972292010-01-06 11:06:32 -08001068 }
1069
San Mehat0f5525a2010-01-11 10:15:16 -08001070 public void finalizeSecureContainer(String id) throws IllegalStateException {
San Mehat22dd86e2010-01-12 12:21:18 -08001071 mConnector.doCommand(String.format("finalize_asec %s", id));
San Mehat36972292010-01-06 11:06:32 -08001072 }
1073
San Mehat0f5525a2010-01-11 10:15:16 -08001074 public void destroySecureContainer(String id) throws IllegalStateException {
San Mehat22dd86e2010-01-12 12:21:18 -08001075 mConnector.doCommand(String.format("destroy_asec %s", id));
San Mehat36972292010-01-06 11:06:32 -08001076 }
1077
San Mehat22dd86e2010-01-12 12:21:18 -08001078 public String mountSecureContainer(String id, String key,
1079 int ownerUid) throws IllegalStateException {
1080 String cmd = String.format("mount_asec %s %s %d",
1081 id, key, ownerUid);
1082 mConnector.doCommand(cmd);
1083 return getSecureContainerPath(id);
San Mehat36972292010-01-06 11:06:32 -08001084 }
1085
San Mehat9dba7092010-01-18 06:47:41 -08001086 public void unmountSecureContainer(String id) throws IllegalStateException {
San Mehat3e3a6432010-01-22 16:46:23 -08001087 String cmd = String.format("unmount_asec %s", id);
San Mehat9dba7092010-01-18 06:47:41 -08001088 mConnector.doCommand(cmd);
1089 }
1090
San Mehat45f61042010-01-23 08:12:43 -08001091 public void renameSecureContainer(String oldId, String newId) throws IllegalStateException {
1092 String cmd = String.format("rename_asec %s %s", oldId, newId);
1093 mConnector.doCommand(cmd);
1094 }
1095
San Mehat0f5525a2010-01-11 10:15:16 -08001096 public String getSecureContainerPath(String id) throws IllegalStateException {
San Mehat22dd86e2010-01-12 12:21:18 -08001097 ArrayList<String> rsp = mConnector.doCommand("asec_path " + id);
San Mehat36972292010-01-06 11:06:32 -08001098
San Mehat22dd86e2010-01-12 12:21:18 -08001099 for (String line : rsp) {
1100 String []tok = line.split(" ");
1101 int code = Integer.parseInt(tok[0]);
1102 if (code == VoldResponseCode.AsecPathResult) {
1103 return tok[1];
1104 } else {
1105 throw new IllegalStateException(String.format("Unexpected response code %d", code));
1106 }
1107 }
1108 throw new IllegalStateException("Got an empty response");
1109 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110}
1111