From b104340496e3a531e26c8f428c808eca0e039f50 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Fri, 5 Feb 2010 08:26:50 -0800 Subject: Framework: Clean up / Refactor Mount APIs - Move android.storage.* -> android.os.storage.* and refactor users - Refactor generic shares back to explicit ums enable/disable/isEnabled - Remove media insert/removed event callbacks (not ready for Froyo) - Remove 'label' from volume state change callbacks - Add public API functions for enabling/disabling USB mass storage (permissions enforced in MountSevice) - Remove some stray un-needed import lines - Move android.os.IMountService / android.os.IMountServiceListener -> android.os.storage - Improve code comments Updated: MountService: Add dup state check and move debugging behind a conditional UsbStorageActivity: Fix review comments + a TODO StorageNotification: Add @Override tags StorageManager: Don't use a static Listener list MountService: Reduce bloat and fix == where I meant .equals() PackageManagerTests: Update for new API Signed-off-by: San Mehat --- core/java/android/app/ContextImpl.java | 2 +- core/java/android/content/Context.java | 6 +- core/java/android/os/Environment.java | 2 +- core/java/android/os/IMountService.aidl | 142 ---------- core/java/android/os/IMountServiceListener.aidl | 66 ----- core/java/android/os/MountServiceListener.java | 69 ----- core/java/android/os/MountServiceResultCode.java | 34 --- core/java/android/os/Power.java | 2 +- core/java/android/os/storage/IMountService.aidl | 131 +++++++++ .../android/os/storage/IMountServiceListener.aidl | 43 +++ .../android/os/storage/MountServiceListener.java | 44 +++ .../android/os/storage/StorageEventListener.java | 38 +++ core/java/android/os/storage/StorageManager.java | 297 ++++++++++++++++++++ .../java/android/os/storage/StorageResultCode.java | 60 ++++ .../java/android/storage/StorageEventListener.java | 57 ---- core/java/android/storage/StorageManager.java | 304 --------------------- .../internal/app/ExternalMediaFormatActivity.java | 2 +- .../android/internal/app/NetInitiatedActivity.java | 1 - .../com/android/internal/app/ShutdownThread.java | 2 +- .../android/internal/app/StorageNotification.java | 175 +++++++----- .../com/android/internal/app/TetherActivity.java | 1 - .../android/internal/app/UsbStorageActivity.java | 93 +++---- 22 files changed, 769 insertions(+), 802 deletions(-) delete mode 100644 core/java/android/os/IMountService.aidl delete mode 100644 core/java/android/os/IMountServiceListener.aidl delete mode 100644 core/java/android/os/MountServiceListener.java delete mode 100644 core/java/android/os/MountServiceResultCode.java create mode 100644 core/java/android/os/storage/IMountService.aidl create mode 100644 core/java/android/os/storage/IMountServiceListener.aidl create mode 100644 core/java/android/os/storage/MountServiceListener.java create mode 100644 core/java/android/os/storage/StorageEventListener.java create mode 100644 core/java/android/os/storage/StorageManager.java create mode 100644 core/java/android/os/storage/StorageResultCode.java delete mode 100644 core/java/android/storage/StorageEventListener.java delete mode 100644 core/java/android/storage/StorageManager.java (limited to 'core') diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 45d7546..4923eee 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -84,7 +84,7 @@ import android.os.ServiceManager; import android.os.StatFs; import android.os.Vibrator; import android.os.FileUtils.FileStatus; -import android.storage.StorageManager; +import android.os.storage.StorageManager; import android.telephony.TelephonyManager; import android.text.ClipboardManager; import android.util.AndroidRuntimeException; diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 5aefe4c..b4a0bf8 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1110,7 +1110,7 @@ public abstract class Context { * @see #SENSOR_SERVICE * @see android.hardware.SensorManager * @see #STORAGE_SERVICE - * @see android.storage.StorageManager + * @see android.os.storage.StorageManager * @see #VIBRATOR_SERVICE * @see android.os.Vibrator * @see #CONNECTIVITY_SERVICE @@ -1243,11 +1243,11 @@ public abstract class Context { /** * Use with {@link #getSystemService} to retrieve a {@link - * android.storage.StorageManager} for accesssing system storage + * android.os.storage.StorageManager} for accesssing system storage * functions. * * @see #getSystemService - * @see android.storage.StorageManager + * @see android.os.storage.StorageManager */ public static final String STORAGE_SERVICE = "storage"; diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 9491bd4..ef1f3be 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -18,7 +18,7 @@ package android.os; import java.io.File; -import android.os.IMountService; +import android.os.storage.IMountService; /** * Provides access to environment variables. diff --git a/core/java/android/os/IMountService.aidl b/core/java/android/os/IMountService.aidl deleted file mode 100644 index a5828f6..0000000 --- a/core/java/android/os/IMountService.aidl +++ /dev/null @@ -1,142 +0,0 @@ -/* //device/java/android/android/os/IUsb.aidl -** -** Copyright 2007, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -package android.os; - -import android.os.IMountServiceListener; - -/** WARNING! Update IMountService.h and IMountService.cpp if you change this file. - * In particular, the ordering of the methods below must match the - * _TRANSACTION enum in IMountService.cpp - * @hide - */ -interface IMountService -{ - /** - * Registers an IMountServiceListener for receiving async - * notifications. - */ - void registerListener(IMountServiceListener listener); - - /** - * Unregisters an IMountServiceListener - */ - void unregisterListener(IMountServiceListener listener); - - /** - * Gets an Array of supported share methods - */ - String[] getShareMethodList(); - - /** - * Returns true if the share method is available - */ - boolean getShareMethodAvailable(String method); - - /** - * Shares a volume via the specified method - * Returns an int consistent with MountServiceResultCode - */ - int shareVolume(String path, String method); - - /** - * Unshares a volume via the specified method - * Returns an int consistent with MountServiceResultCode - */ - int unshareVolume(String path, String method); - - /** - * Returns true if the volume is shared via the specified method. - */ - boolean getVolumeShared(String path, String method); - - /** - * Mount external storage at given mount point. - * Returns an int consistent with MountServiceResultCode - */ - int mountVolume(String mountPoint); - - /** - * Safely unmount external storage at given mount point. - * Returns an int consistent with MountServiceResultCode - */ - int unmountVolume(String mountPoint); - - /** - * Format external storage given a mount point. - * Returns an int consistent with MountServiceResultCode - */ - int formatVolume(String mountPoint); - - /** - * Gets the state of an volume via it's mountpoint. - */ - String getVolumeState(String mountPoint); - - /* - * Creates a secure container with the specified parameters. - * Returns an int consistent with MountServiceResultCode - */ - int createSecureContainer(String id, int sizeMb, String fstype, String key, int ownerUid); - - /* - * Finalize a container which has just been created and populated. - * After finalization, the container is immutable. - * Returns an int consistent with MountServiceResultCode - */ - int finalizeSecureContainer(String id); - - /* - * Destroy a secure container, and free up all resources associated with it. - * NOTE: Ensure all references are released prior to deleting. - * Returns an int consistent with MountServiceResultCode - */ - int destroySecureContainer(String id); - - /* - * Mount a secure container with the specified key and owner UID. - * Returns an int consistent with MountServiceResultCode - */ - int mountSecureContainer(String id, String key, int ownerUid); - - /* - * Unount a secure container. - * Returns an int consistent with MountServiceResultCode - */ - int unmountSecureContainer(String id); - - /* - * Rename an unmounted secure container. - * Returns an int consistent with MountServiceResultCode - */ - int renameSecureContainer(String oldId, String newId); - - /* - * Returns the filesystem path of a mounted secure container. - */ - String getSecureContainerPath(String id); - - /** - * Gets an Array of currently known secure container IDs - */ - String[] getSecureContainerList(); - - /** - * Shuts down the MountService and gracefully unmounts all external media. - */ - void shutdown(); -} diff --git a/core/java/android/os/IMountServiceListener.aidl b/core/java/android/os/IMountServiceListener.aidl deleted file mode 100644 index 3df64b2..0000000 --- a/core/java/android/os/IMountServiceListener.aidl +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -/** - * Callback class for receiving events from MountService. - * - * @hide - */ -interface IMountServiceListener { - /** - * A sharing method has changed availability state. - * - * @param method The share method which has changed. - * @param available The share availability state. - */ - void onShareAvailabilityChanged(String method, boolean available); - - /** - * Media has been inserted - * - * @param label The volume label. - * @param path The volume mount path. - * @param major The backing device major number. - * @param minor The backing device minor number. - */ - void onMediaInserted(String label, String path, int major, int minor); - - /** - * Media has been removed - * - * @param label The volume label. - * @param path The volume mount path. - * @param major The backing device major number. - * @param minor The backing device minor number. - * @param clean Indicates if the removal was clean (unmounted first). - */ - void onMediaRemoved(String label, String path, int major, int minor, boolean clean); - - /** - * Volume state has changed. - * - * @param label The volume label. - * @param path The volume mount path. - * @param oldState The old state of the volume. - * @param newState The new state of the volume. - * - * Note: State is one of the values returned by Environment.getExternalStorageState() - */ - void onVolumeStateChanged(String label, String path, String oldState, String newState); - -} diff --git a/core/java/android/os/MountServiceListener.java b/core/java/android/os/MountServiceListener.java deleted file mode 100644 index a68f464..0000000 --- a/core/java/android/os/MountServiceListener.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -/** - * Callback class for receiving progress reports during a restore operation. These - * methods will all be called on your application's main thread. - * @hide - */ -public abstract class MountServiceListener { - /** - * A sharing method has changed availability state. - * - * @param method The share method which has changed. - * @param available The share availability state. - */ - void shareAvailabilityChange(String method, boolean available) { - } - - /** - * Media has been inserted - * - * @param label The volume label. - * @param path The volume mount path. - * @param major The backing device major number. - * @param minor The backing device minor number. - */ - void mediaInserted(String label, String path, int major, int minor) { - } - - /** - * Media has been removed - * - * @param label The volume label. - * @param path The volume mount path. - * @param major The backing device major number. - * @param minor The backing device minor number. - * @param clean Indicates if the removal was clean (unmounted first). - */ - void mediaRemoved(String label, String path, int major, int minor, boolean clean) { - } - - /** - * Volume state has changed. - * - * @param label The volume label. - * @param path The volume mount path. - * @param oldState The old state of the volume. - * @param newState The new state of the volume. - * - * Note: State is one of the values returned by Environment.getExternalStorageState() - */ - void volumeStateChange(String label, String path, String oldState, String newState) { - } -} diff --git a/core/java/android/os/MountServiceResultCode.java b/core/java/android/os/MountServiceResultCode.java deleted file mode 100644 index e71dbf4..0000000 --- a/core/java/android/os/MountServiceResultCode.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import java.io.IOException; - -/** - * Class that provides access to constants returned from MountService APIs - * - * {@hide} - */ -public class MountServiceResultCode -{ - public static final int OperationSucceeded = 0; - public static final int OperationFailedInternalError = -1; - public static final int OperationFailedNoMedia = -2; - public static final int OperationFailedMediaBlank = -3; - public static final int OperationFailedMediaCorrupt = -4; - public static final int OperationFailedVolumeNotMounted = -5; -} diff --git a/core/java/android/os/Power.java b/core/java/android/os/Power.java index bc76180..b3df522 100644 --- a/core/java/android/os/Power.java +++ b/core/java/android/os/Power.java @@ -18,7 +18,7 @@ package android.os; import java.io.IOException; import android.os.ServiceManager; -import android.os.IMountService; +import android.os.storage.IMountService; /** * Class that provides access to some of the power management functions. diff --git a/core/java/android/os/storage/IMountService.aidl b/core/java/android/os/storage/IMountService.aidl new file mode 100644 index 0000000..84e3f58 --- /dev/null +++ b/core/java/android/os/storage/IMountService.aidl @@ -0,0 +1,131 @@ +/* //device/java/android/android/os/IUsb.aidl +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.os.storage; + +import android.os.storage.IMountServiceListener; + +/** WARNING! Update IMountService.h and IMountService.cpp if you change this file. + * In particular, the ordering of the methods below must match the + * _TRANSACTION enum in IMountService.cpp + * @hide - Applications should use android.os.storage.StorageManager to access + * storage functions. + */ +interface IMountService +{ + /** + * Registers an IMountServiceListener for receiving async + * notifications. + */ + void registerListener(IMountServiceListener listener); + + /** + * Unregisters an IMountServiceListener + */ + void unregisterListener(IMountServiceListener listener); + + /** + * Returns true if a USB mass storage host is connected + */ + boolean isUsbMassStorageConnected(); + + /** + * Enables / disables USB mass storage. + */ + int setUsbMassStorageEnabled(boolean enable); + + /** + * Returns true if a USB mass storage host is enabled (media is shared) + */ + boolean isUsbMassStorageEnabled(); + + /** + * Mount external storage at given mount point. + * Returns an int consistent with MountServiceResultCode + */ + int mountVolume(String mountPoint); + + /** + * Safely unmount external storage at given mount point. + * Returns an int consistent with MountServiceResultCode + */ + int unmountVolume(String mountPoint); + + /** + * Format external storage given a mount point. + * Returns an int consistent with MountServiceResultCode + */ + int formatVolume(String mountPoint); + + /** + * Gets the state of an volume via it's mountpoint. + */ + String getVolumeState(String mountPoint); + + /* + * Creates a secure container with the specified parameters. + * Returns an int consistent with MountServiceResultCode + */ + int createSecureContainer(String id, int sizeMb, String fstype, String key, int ownerUid); + + /* + * Finalize a container which has just been created and populated. + * After finalization, the container is immutable. + * Returns an int consistent with MountServiceResultCode + */ + int finalizeSecureContainer(String id); + + /* + * Destroy a secure container, and free up all resources associated with it. + * NOTE: Ensure all references are released prior to deleting. + * Returns an int consistent with MountServiceResultCode + */ + int destroySecureContainer(String id); + + /* + * Mount a secure container with the specified key and owner UID. + * Returns an int consistent with MountServiceResultCode + */ + int mountSecureContainer(String id, String key, int ownerUid); + + /* + * Unount a secure container. + * Returns an int consistent with MountServiceResultCode + */ + int unmountSecureContainer(String id); + + /* + * Rename an unmounted secure container. + * Returns an int consistent with MountServiceResultCode + */ + int renameSecureContainer(String oldId, String newId); + + /* + * Returns the filesystem path of a mounted secure container. + */ + String getSecureContainerPath(String id); + + /** + * Gets an Array of currently known secure container IDs + */ + String[] getSecureContainerList(); + + /** + * Shuts down the MountService and gracefully unmounts all external media. + */ + void shutdown(); +} diff --git a/core/java/android/os/storage/IMountServiceListener.aidl b/core/java/android/os/storage/IMountServiceListener.aidl new file mode 100644 index 0000000..883413a --- /dev/null +++ b/core/java/android/os/storage/IMountServiceListener.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os.storage; + +/** + * Callback class for receiving events from MountService. + * + * @hide - Applications should use android.os.storage.IStorageEventListener + * for storage event callbacks. + */ +interface IMountServiceListener { + /** + * Detection state of USB Mass Storage has changed + * + * @param available true if a UMS host is connected. + */ + void onUsbMassStorageConnectionChanged(boolean connected); + + /** + * Storage state has changed. + * + * @param path The volume mount path. + * @param oldState The old state of the volume. + * @param newState The new state of the volume. + * + * Note: State is one of the values returned by Environment.getExternalStorageState() + */ + void onStorageStateChanged(String path, String oldState, String newState); +} diff --git a/core/java/android/os/storage/MountServiceListener.java b/core/java/android/os/storage/MountServiceListener.java new file mode 100644 index 0000000..bebb3f6 --- /dev/null +++ b/core/java/android/os/storage/MountServiceListener.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os.storage; + +/** + * Callback class for receiving progress reports during a restore operation. These + * methods will all be called on your application's main thread. + * @hide + */ +public abstract class MountServiceListener { + /** + * USB Mass storage connection state has changed. + * + * @param connected True if UMS is connected. + */ + void onUsbMassStorageConnectionChanged(boolean connected) { + } + + /** + * Storage state has changed. + * + * @param path The volume mount path. + * @param oldState The old state of the volume. + * @param newState The new state of the volume. + * + * @Note: State is one of the values returned by Environment.getExternalStorageState() + */ + void onStorageStateChange(String path, String oldState, String newState) { + } +} diff --git a/core/java/android/os/storage/StorageEventListener.java b/core/java/android/os/storage/StorageEventListener.java new file mode 100644 index 0000000..d3d39d6 --- /dev/null +++ b/core/java/android/os/storage/StorageEventListener.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os.storage; + +/** + * Used for receiving notifications from the StorageManager + */ +public abstract class StorageEventListener { + /** + * Called when the detection state of a USB Mass Storage host has changed. + * @param connected true if the USB mass storage is connected. + */ + public void onUsbMassStorageConnectionChanged(boolean connected) { + } + + /** + * Called when storage has changed state + * @param path the filesystem path for the storage + * @param oldState the old state as returned by {@link android.os.Environment#getExternalStorageState()}. + * @param newState the old state as returned by {@link android.os.Environment#getExternalStorageState()}. + */ + public void onStorageStateChanged(String path, String oldState, String newState) { + } +} diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java new file mode 100644 index 0000000..e421ea5 --- /dev/null +++ b/core/java/android/os/storage/StorageManager.java @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os.storage; + +import android.content.Context; +import android.os.Binder; +import android.os.Bundle; +import android.os.Looper; +import android.os.Parcelable; +import android.os.ParcelFileDescriptor; +import android.os.Process; +import android.os.RemoteException; +import android.os.Handler; +import android.os.Message; +import android.os.ServiceManager; +import android.os.storage.IMountService; +import android.os.storage.IMountServiceListener; +import android.util.Log; +import android.util.SparseArray; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + +/** + * StorageManager is the interface to the systems storage service. + * Get an instance of this class by calling + * {@link android.content.Context#getSystemService(java.lang.String)} with an argument + * of {@link android.content.Context#STORAGE_SERVICE}. + * + */ + +public class StorageManager +{ + private static final String TAG = "StorageManager"; + + /* + * Our internal MountService binder reference + */ + private IMountService mMountService; + + /* + * The looper target for callbacks + */ + Looper mTgtLooper; + + /* + * Target listener for binder callbacks + */ + private MountServiceBinderListener mBinderListener; + + /* + * List of our listeners + */ + private ArrayList mListeners = new ArrayList(); + + private class MountServiceBinderListener extends IMountServiceListener.Stub { + public void onUsbMassStorageConnectionChanged(boolean available) { + final int size = mListeners.size(); + for (int i = 0; i < size; i++) { + mListeners.get(i).sendShareAvailabilityChanged(available); + } + } + + public void onStorageStateChanged(String path, String oldState, String newState) { + final int size = mListeners.size(); + for (int i = 0; i < size; i++) { + mListeners.get(i).sendStorageStateChanged(path, oldState, newState); + } + } + } + + /** + * Private base class for messages sent between the callback thread + * and the target looper handler. + */ + private class StorageEvent { + public static final int EVENT_UMS_CONNECTION_CHANGED = 1; + public static final int EVENT_STORAGE_STATE_CHANGED = 2; + + private Message mMessage; + + public StorageEvent(int what) { + mMessage = Message.obtain(); + mMessage.what = what; + mMessage.obj = this; + } + + public Message getMessage() { + return mMessage; + } + } + + /** + * Message sent on a USB mass storage connection change. + */ + private class UmsConnectionChangedStorageEvent extends StorageEvent { + public boolean available; + + public UmsConnectionChangedStorageEvent(boolean a) { + super(EVENT_UMS_CONNECTION_CHANGED); + available = a; + } + } + + /** + * Message sent on volume state change. + */ + private class StorageStateChangedStorageEvent extends StorageEvent { + public String path; + public String oldState; + public String newState; + + public StorageStateChangedStorageEvent(String p, String oldS, String newS) { + super(EVENT_STORAGE_STATE_CHANGED); + path = p; + oldState = oldS; + newState = newS; + } + } + + /** + * Private class containing sender and receiver code for StorageEvents. + */ + private class ListenerDelegate { + final StorageEventListener mStorageEventListener; + private final Handler mHandler; + + ListenerDelegate(StorageEventListener listener) { + mStorageEventListener = listener; + mHandler = new Handler(mTgtLooper) { + @Override + public void handleMessage(Message msg) { + StorageEvent e = (StorageEvent) msg.obj; + + if (msg.what == StorageEvent.EVENT_UMS_CONNECTION_CHANGED) { + UmsConnectionChangedStorageEvent ev = (UmsConnectionChangedStorageEvent) e; + mStorageEventListener.onUsbMassStorageConnectionChanged(ev.available); + } else if (msg.what == StorageEvent.EVENT_STORAGE_STATE_CHANGED) { + StorageStateChangedStorageEvent ev = (StorageStateChangedStorageEvent) e; + mStorageEventListener.onStorageStateChanged(ev.path, ev.oldState, ev.newState); + } else { + Log.e(TAG, "Unsupported event " + msg.what); + } + } + }; + } + + StorageEventListener getListener() { + return mStorageEventListener; + } + + void sendShareAvailabilityChanged(boolean available) { + UmsConnectionChangedStorageEvent e = new UmsConnectionChangedStorageEvent(available); + mHandler.sendMessage(e.getMessage()); + } + + void sendStorageStateChanged(String path, String oldState, String newState) { + StorageStateChangedStorageEvent e = new StorageStateChangedStorageEvent(path, oldState, newState); + mHandler.sendMessage(e.getMessage()); + } + } + + /** + * Constructs a StorageManager object through which an application can + * can communicate with the systems mount service. + * + * @param tgtLooper The {@android.os.Looper} which events will be received on. + * + *

Applications can get instance of this class by calling + * {@link android.content.Context#getSystemService(java.lang.String)} with an argument + * of {@link android.content.Context#STORAGE_SERVICE}. + * + * @hide + */ + public StorageManager(Looper tgtLooper) throws RemoteException { + mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount")); + if (mMountService == null) { + Log.e(TAG, "Unable to connect to mount service! - is it running yet?"); + return; + } + mTgtLooper = tgtLooper; + mBinderListener = new MountServiceBinderListener(); + mMountService.registerListener(mBinderListener); + } + + + /** + * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}. + * + * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object. + * + */ + public void registerListener(StorageEventListener listener) { + if (listener == null) { + return; + } + + synchronized (mListeners) { + mListeners.add(new ListenerDelegate(listener)); + } + } + + /** + * Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}. + * + * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object. + * + */ + public void unregisterListener(StorageEventListener listener) { + if (listener == null) { + return; + } + + synchronized (mListeners) { + final int size = mListeners.size(); + for (int i=0 ; i sListeners = new ArrayList(); - - private class MountServiceBinderListener extends IMountServiceListener.Stub { - public void onShareAvailabilityChanged(String method, boolean available) { - final int size = sListeners.size(); - for (int i = 0; i < size; i++) { - sListeners.get(i).sendShareAvailabilityChanged(method, available); - } - } - - public void onMediaInserted(String label, String path, int major, int minor) { - final int size = sListeners.size(); - for (int i = 0; i < size; i++) { - sListeners.get(i).sendMediaInserted(label, path, major, minor); - } - } - - public void onMediaRemoved(String label, String path, int major, int minor, boolean clean) { - final int size = sListeners.size(); - for (int i = 0; i < size; i++) { - sListeners.get(i).sendMediaRemoved(label, path, major, minor, clean); - } - } - - public void onVolumeStateChanged(String label, String path, String oldState, String newState) { - final int size = sListeners.size(); - for (int i = 0; i < size; i++) { - sListeners.get(i).sendVolumeStateChanged(label, path, oldState, newState); - } - } - } - - /** - * Private base class for messages sent between the callback thread - * and the target looper handler - */ - private class StorageEvent { - public static final int EVENT_SHARE_AVAILABILITY_CHANGED = 1; - public static final int EVENT_MEDIA_INSERTED = 2; - public static final int EVENT_MEDIA_REMOVED = 3; - public static final int EVENT_VOLUME_STATE_CHANGED = 4; - - private Message mMessage; - - public StorageEvent(int what) { - mMessage = Message.obtain(); - mMessage.what = what; - mMessage.obj = this; - } - - public Message getMessage() { - return mMessage; - } - } - - /** - * Message sent on a share availability change. - */ - private class ShareAvailabilityChangedStorageEvent extends StorageEvent { - public String method; - public boolean available; - - public ShareAvailabilityChangedStorageEvent(String m, boolean a) { - super(EVENT_SHARE_AVAILABILITY_CHANGED); - method = m; - available = a; - } - } - - /** - * Message sent on media insertion - */ - private class MediaInsertedStorageEvent extends StorageEvent { - public String label; - public String path; - public int major; - public int minor; - - public MediaInsertedStorageEvent(String l, String p, int maj, int min) { - super(EVENT_MEDIA_INSERTED); - label = l; - path = p; - major = maj; - minor = min; - } - } - - /** - * Message sent on media removal - */ - private class MediaRemovedStorageEvent extends StorageEvent { - public String label; - public String path; - public int major; - public int minor; - public boolean clean; - - public MediaRemovedStorageEvent(String l, String p, int maj, int min, boolean c) { - super(EVENT_MEDIA_REMOVED); - label = l; - path = p; - major = maj; - minor = min; - clean = c; - } - } - - /** - * Message sent on volume state change - */ - private class VolumeStateChangedStorageEvent extends StorageEvent { - public String label; - public String path; - public String oldState; - public String newState; - - public VolumeStateChangedStorageEvent(String l, String p, String oldS, String newS) { - super(EVENT_VOLUME_STATE_CHANGED); - label = l; - path = p; - oldState = oldS; - newState = newS; - } - } - - /** - * Private class containing sender and receiver code for StorageEvents - */ - private class ListenerDelegate { - final StorageEventListener mStorageEventListener; - private final Handler mHandler; - - ListenerDelegate(StorageEventListener listener) { - mStorageEventListener = listener; - mHandler = new Handler(mTgtLooper) { - @Override - public void handleMessage(Message msg) { - StorageEvent e = (StorageEvent) msg.obj; - - if (msg.what == StorageEvent.EVENT_SHARE_AVAILABILITY_CHANGED) { - ShareAvailabilityChangedStorageEvent ev = (ShareAvailabilityChangedStorageEvent) e; - mStorageEventListener.onShareAvailabilityChanged(ev.method, ev.available); - } else if (msg.what == StorageEvent.EVENT_MEDIA_INSERTED) { - MediaInsertedStorageEvent ev = (MediaInsertedStorageEvent) e; - mStorageEventListener.onMediaInserted(ev.label, ev.path, ev.major, ev.minor); - } else if (msg.what == StorageEvent.EVENT_MEDIA_REMOVED) { - MediaRemovedStorageEvent ev = (MediaRemovedStorageEvent) e; - mStorageEventListener.onMediaRemoved(ev.label, ev.path, ev.major, ev.minor, ev.clean); - } else if (msg.what == StorageEvent.EVENT_VOLUME_STATE_CHANGED) { - VolumeStateChangedStorageEvent ev = (VolumeStateChangedStorageEvent) e; - mStorageEventListener.onVolumeStateChanged(ev.label, ev.path, ev.oldState, ev.newState); - } else { - Log.e(TAG, "Unsupported event " + msg.what); - } - } - }; - } - - StorageEventListener getListener() { - return mStorageEventListener; - } - - void sendShareAvailabilityChanged(String method, boolean available) { - ShareAvailabilityChangedStorageEvent e = new ShareAvailabilityChangedStorageEvent(method, available); - mHandler.sendMessage(e.getMessage()); - } - - void sendMediaInserted(String label, String path, int major, int minor) { - MediaInsertedStorageEvent e = new MediaInsertedStorageEvent(label, path, major, minor); - mHandler.sendMessage(e.getMessage()); - } - - void sendMediaRemoved(String label, String path, int major, int minor, boolean clean) { - MediaRemovedStorageEvent e = new MediaRemovedStorageEvent(label, path, major, minor, clean); - mHandler.sendMessage(e.getMessage()); - } - - void sendVolumeStateChanged(String label, String path, String oldState, String newState) { - VolumeStateChangedStorageEvent e = new VolumeStateChangedStorageEvent(label, path, oldState, newState); - mHandler.sendMessage(e.getMessage()); - } - } - - /** - * {@hide} - */ - public StorageManager(Looper tgtLooper) throws RemoteException { - mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount")); - if (mMountService == null) { - Log.e(TAG, "Unable to connect to mount service! - is it running yet?"); - return; - } - mTgtLooper = tgtLooper; - mBinderListener = new MountServiceBinderListener(); - mMountService.registerListener(mBinderListener); - } - - - /** - * Registers a {@link android.storage.StorageEventListener StorageEventListener}. - * - * @param listener A {@link android.storage.StorageEventListener StorageEventListener} object. - * - */ - public void registerListener(StorageEventListener listener) { - if (listener == null) { - return; - } - - synchronized (sListeners) { - sListeners.add(new ListenerDelegate(listener)); - } - } - - /** - * Unregisters a {@link android.storage.StorageEventListener StorageEventListener}. - * - * @param listener A {@link android.storage.StorageEventListener StorageEventListener} object. - * - */ - public void unregisterListener(StorageEventListener listener) { - if (listener == null) { - return; - } - synchronized (sListeners) { - final int size = sListeners.size(); - for (int i=0 ; i * This is lazily created, so use {@link #setMediaStorageNotification()}. */ - private Notification mMediaStorageNotification; - - private boolean mShowSafeUnmountNotificationWhenUnmounted; - private boolean mUmsAvailable; - private IMountService mMountService; // XXX: This should go away soon + private Notification mMediaStorageNotification; + private boolean mUmsAvailable; + private StorageManager mStorageManager; public StorageNotification(Context context) { mContext = context; - /* - * XXX: This needs to be exposed via StorageManager - */ - mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount")); - try { - mUmsAvailable = mMountService.getShareMethodAvailable("ums"); - } catch (Exception e) { - Log.e(TAG, "Failed to get ums availability", e); - } - } - - public void onShareAvailabilityChanged(String method, boolean available) { - if (method.equals("ums")) { - mUmsAvailable = available; - /* - * Even though we may have a UMS host connected, we the SD card - * may not be in a state for export. - */ - String st = Environment.getExternalStorageState(); - if (available && (st.equals( - Environment.MEDIA_REMOVED) || st.equals(Environment.MEDIA_CHECKING))) { - /* - * No card or card being checked = don't display - */ - available = false; - } - - updateUsbMassStorageNotification(available); - } - } - - public void onMediaInserted(String label, String path, int major, int minor) { + mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE); + mUmsAvailable = mStorageManager.isUsbMassStorageConnected(); + Log.d(TAG, String.format( "Startup with UMS connection %s (media state %s)", mUmsAvailable, + Environment.getExternalStorageState())); } - public void onMediaRemoved(String label, String path, int major, int minor, boolean clean) { + /* + * @override com.android.os.storage.StorageEventListener + */ + @Override + public void onUsbMassStorageConnectionChanged(boolean connected) { + mUmsAvailable = connected; /* - * Media removed - first clear the USB storage notification (if any) + * Even though we may have a UMS host connected, we the SD card + * may not be in a state for export. */ - updateUsbMassStorageNotification(false); + String st = Environment.getExternalStorageState(); - if (clean) { - setMediaStorageNotification( - com.android.internal.R.string.ext_media_nomedia_notification_title, - com.android.internal.R.string.ext_media_nomedia_notification_message, - com.android.internal.R.drawable.stat_notify_sdcard_usb, - true, false, null); - } else { - setMediaStorageNotification( - com.android.internal.R.string.ext_media_badremoval_notification_title, - com.android.internal.R.string.ext_media_badremoval_notification_message, - com.android.internal.R.drawable.stat_sys_warning, - true, true, null); + Log.i(TAG, String.format("UMS connection changed to %s (media state %s)", connected, st)); + + if (connected && (st.equals( + Environment.MEDIA_REMOVED) || st.equals(Environment.MEDIA_CHECKING))) { + /* + * No card or card being checked = don't display + */ + connected = false; } + updateUsbMassStorageNotification(connected); } - public void onVolumeStateChanged(String label, String path, String oldState, String newState) { + /* + * @override com.android.os.storage.StorageEventListener + */ + @Override + public void onStorageStateChanged(String path, String oldState, String newState) { + Log.i(TAG, String.format( + "Media {%s} state changed from {%s} -> {%s}", path, oldState, newState)); if (newState.equals(Environment.MEDIA_SHARED)) { + /* + * Storage is now shared. Modify the UMS notification + * for stopping UMS. + */ Intent intent = new Intent(); intent.setClass(mContext, com.android.internal.app.UsbStorageActivity.class); PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0); @@ -143,26 +126,60 @@ public class StorageNotification implements StorageEventListener { com.android.internal.R.string.usb_storage_stop_notification_message, com.android.internal.R.drawable.stat_sys_warning, false, true, pi); } else if (newState.equals(Environment.MEDIA_CHECKING)) { + /* + * Storage is now checking. Update media notification and disable + * UMS notification. + */ setMediaStorageNotification( com.android.internal.R.string.ext_media_checking_notification_title, com.android.internal.R.string.ext_media_checking_notification_message, com.android.internal.R.drawable.stat_notify_sdcard_prepare, true, false, null); updateUsbMassStorageNotification(false); } else if (newState.equals(Environment.MEDIA_MOUNTED)) { + /* + * Storage is now mounted. Dismiss any media notifications, + * and enable UMS notification if connected. + */ setMediaStorageNotification(0, 0, 0, false, false, null); updateUsbMassStorageNotification(mUmsAvailable); } else if (newState.equals(Environment.MEDIA_UNMOUNTED)) { - if (mShowSafeUnmountNotificationWhenUnmounted) { - setMediaStorageNotification( - com.android.internal.R.string.ext_media_safe_unmount_notification_title, - com.android.internal.R.string.ext_media_safe_unmount_notification_message, - com.android.internal.R.drawable.stat_notify_sdcard, true, true, null); - mShowSafeUnmountNotificationWhenUnmounted = false; + /* + * Storage is now unmounted. We may have been unmounted + * because the user is enabling/disabling UMS, in which case we don't + * want to display the 'safe to unmount' notification. + */ + if (!mStorageManager.isUsbMassStorageEnabled()) { + if (oldState.equals(Environment.MEDIA_SHARED)) { + /* + * The unmount was due to UMS being enabled. Dismiss any + * media notifications, and enable UMS notification if connected + */ + setMediaStorageNotification(0, 0, 0, false, false, null); + updateUsbMassStorageNotification(mUmsAvailable); + } else { + /* + * Show safe to unmount media notification, and enable UMS + * notification if connected. + */ + setMediaStorageNotification( + com.android.internal.R.string.ext_media_safe_unmount_notification_title, + com.android.internal.R.string.ext_media_safe_unmount_notification_message, + com.android.internal.R.drawable.stat_notify_sdcard, true, true, null); + updateUsbMassStorageNotification(mUmsAvailable); + } } else { + /* + * The unmount was due to UMS being enabled. Dismiss any + * media notifications, and disable the UMS notification + */ setMediaStorageNotification(0, 0, 0, false, false, null); + updateUsbMassStorageNotification(false); } - updateUsbMassStorageNotification(mUmsAvailable); } else if (newState.equals(Environment.MEDIA_NOFS)) { + /* + * Storage has no filesystem. Show blank media notification, + * and enable UMS notification if connected. + */ Intent intent = new Intent(); intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class); PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0); @@ -173,6 +190,10 @@ public class StorageNotification implements StorageEventListener { com.android.internal.R.drawable.stat_notify_sdcard_usb, true, false, pi); updateUsbMassStorageNotification(mUmsAvailable); } else if (newState.equals(Environment.MEDIA_UNMOUNTABLE)) { + /* + * Storage is corrupt. Show corrupt media notification, + * and enable UMS notification if connected. + */ Intent intent = new Intent(); intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class); PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0); @@ -182,6 +203,30 @@ public class StorageNotification implements StorageEventListener { com.android.internal.R.string.ext_media_unmountable_notification_message, com.android.internal.R.drawable.stat_notify_sdcard_usb, true, false, pi); updateUsbMassStorageNotification(mUmsAvailable); + } else if (newState.equals(Environment.MEDIA_REMOVED)) { + /* + * Storage has been removed. Show nomedia media notification, + * and disable UMS notification regardless of connection state. + */ + setMediaStorageNotification( + com.android.internal.R.string.ext_media_nomedia_notification_title, + com.android.internal.R.string.ext_media_nomedia_notification_message, + com.android.internal.R.drawable.stat_notify_sdcard_usb, + true, false, null); + updateUsbMassStorageNotification(false); + } else if (newState.equals(Environment.MEDIA_BAD_REMOVAL)) { + /* + * Storage has been removed unsafely. Show bad removal media notification, + * and disable UMS notification regardless of connection state. + */ + setMediaStorageNotification( + com.android.internal.R.string.ext_media_badremoval_notification_title, + com.android.internal.R.string.ext_media_badremoval_notification_message, + com.android.internal.R.drawable.stat_sys_warning, + true, true, null); + updateUsbMassStorageNotification(false); + } else { + Log.w(TAG, String.format("Ignoring unknown state {%s}", newState)); } } diff --git a/core/java/com/android/internal/app/TetherActivity.java b/core/java/com/android/internal/app/TetherActivity.java index 2b93dbc..cb268b3 100644 --- a/core/java/com/android/internal/app/TetherActivity.java +++ b/core/java/com/android/internal/app/TetherActivity.java @@ -25,7 +25,6 @@ import android.content.IntentFilter; import android.net.ConnectivityManager; import android.os.Bundle; import android.os.Handler; -import android.os.IMountService; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; diff --git a/core/java/com/android/internal/app/UsbStorageActivity.java b/core/java/com/android/internal/app/UsbStorageActivity.java index 34ae2b4..991f04b 100644 --- a/core/java/com/android/internal/app/UsbStorageActivity.java +++ b/core/java/com/android/internal/app/UsbStorageActivity.java @@ -25,8 +25,9 @@ import android.content.IntentFilter; import android.os.Bundle; import android.os.Handler; import android.os.Environment; -import android.os.IMountService; -import android.os.MountServiceResultCode; +import android.os.storage.StorageManager; +import android.os.storage.StorageEventListener; +import android.os.storage.StorageResultCode; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; @@ -35,6 +36,7 @@ import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import android.view.View; +import android.util.Log; /** * This activity is shown to the user for him/her to enable USB mass storage @@ -42,11 +44,13 @@ import android.view.View; * dialog style. It will be launched from a notification. */ public class UsbStorageActivity extends Activity { + private static final String TAG = "UsbStorageActivity"; private Button mMountButton; private Button mUnmountButton; private TextView mBanner; private TextView mMessage; private ImageView mIcon; + private StorageManager mStorageManager = null; /** Used to detect when the USB cable is unplugged, so we can call finish() */ private BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() { @@ -57,11 +61,30 @@ public class UsbStorageActivity extends Activity { } } }; + + private StorageEventListener mStorageListener = new StorageEventListener() { + @Override + public void onStorageStateChanged(String path, String oldState, String newState) { + if (newState.equals(Environment.MEDIA_SHARED)) { + switchDisplay(true); + } else { + switchDisplay(false); + } + } + }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (mStorageManager == null) { + mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE); + if (mStorageManager == null) { + Log.w(TAG, "Failed to get StorageManager"); + } + mStorageManager.registerListener(mStorageListener); + } + setTitle(getString(com.android.internal.R.string.usb_storage_activity_title)); setContentView(com.android.internal.R.layout.usb_storage_activity); @@ -74,9 +97,11 @@ public class UsbStorageActivity extends Activity { mMountButton.setOnClickListener( new View.OnClickListener() { public void onClick(View v) { - mountAsUsbStorage(); - // TODO: replace with forthcoming MountService callbacks - switchDisplay(true); + int rc = mStorageManager.enableUsbMassStorage(); + if (rc != StorageResultCode.OperationSucceeded) { + Log.e(TAG, String.format("UMS enable failed (%d)", rc)); + showSharingError(); + } } }); @@ -84,9 +109,11 @@ public class UsbStorageActivity extends Activity { mUnmountButton.setOnClickListener( new View.OnClickListener() { public void onClick(View v) { - stopUsbStorage(); - // TODO: replace with forthcoming MountService callbacks - switchDisplay(false); + int rc = mStorageManager.disableUsbMassStorage(); + if (rc != StorageResultCode.OperationSucceeded) { + Log.e(TAG, String.format("UMS disable failed (%d)", rc)); + showStoppingError(); + } } }); } @@ -112,19 +139,11 @@ public class UsbStorageActivity extends Activity { super.onResume(); registerReceiver(mBatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); - - boolean umsOn = false; try { - IMountService mountService = IMountService.Stub.asInterface(ServiceManager - .getService("mount")); - if (mountService != null) { - umsOn = mountService.getVolumeShared( - Environment.getExternalStorageDirectory().getPath(), "ums"); - } - } catch (android.os.RemoteException exc) { - // pass + switchDisplay(mStorageManager.isUsbMassStorageEnabled()); + } catch (Exception ex) { + Log.e(TAG, "Failed to read UMS enable state", ex); } - switchDisplay(umsOn); } @Override @@ -134,42 +153,6 @@ public class UsbStorageActivity extends Activity { unregisterReceiver(mBatteryReceiver); } - private void mountAsUsbStorage() { - IMountService mountService = IMountService.Stub.asInterface(ServiceManager - .getService("mount")); - if (mountService == null) { - showSharingError(); - return; - } - - try { - if (mountService.shareVolume( - Environment.getExternalStorageDirectory().getPath(), "ums") != - MountServiceResultCode.OperationSucceeded) { - showSharingError(); - } - } catch (RemoteException e) { - showSharingError(); - } - } - - private void stopUsbStorage() { - IMountService mountService = IMountService.Stub.asInterface(ServiceManager - .getService("mount")); - if (mountService == null) { - showStoppingError(); - return; - } - - try { - mountService.unshareVolume( - Environment.getExternalStorageDirectory().getPath(), "ums"); - } catch (RemoteException e) { - showStoppingError(); - return; - } - } - private void handleBatteryChanged(Intent intent) { int pluggedType = intent.getIntExtra("plugged", 0); if (pluggedType == 0) { -- cgit v1.1