Merge "Add single-package restore to Bmgr feature set"
diff --git a/api/current.xml b/api/current.xml
index 492bb34..394a68a 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -120110,7 +120110,7 @@
visibility="public"
>
<method name="disableUsbMassStorage"
- return="int"
+ return="void"
abstract="false"
native="false"
synchronized="false"
@@ -120121,7 +120121,7 @@
>
</method>
<method name="enableUsbMassStorage"
- return="int"
+ return="void"
abstract="false"
native="false"
synchronized="false"
diff --git a/core/java/android/os/storage/IMountService.aidl b/core/java/android/os/storage/IMountService.aidl
index 2b2dcf4..ad4cb10 100644
--- a/core/java/android/os/storage/IMountService.aidl
+++ b/core/java/android/os/storage/IMountService.aidl
@@ -45,8 +45,10 @@
/**
* Enables / disables USB mass storage.
+ * The caller should check actual status of enabling/disabling
+ * USB mass storage via StorageEventListener.
*/
- int setUsbMassStorageEnabled(boolean enable);
+ void setUsbMassStorageEnabled(boolean enable);
/**
* Returns true if a USB mass storage host is enabled (media is shared)
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index e421ea5..b49979c 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -243,30 +243,24 @@
/**
* Enables USB Mass Storage (UMS) on the device.
- * @return an integer value representing the outcome of the operation.
- * @see android.os.storage.StorageResultCode
*/
- public int enableUsbMassStorage() {
+ public void enableUsbMassStorage() {
try {
- return mMountService.setUsbMassStorageEnabled(true);
+ mMountService.setUsbMassStorageEnabled(true);
} catch (Exception ex) {
Log.e(TAG, "Failed to enable UMS", ex);
}
- return StorageResultCode.OperationFailedInternalError;
}
/**
* Disables USB Mass Storage (UMS) on the device.
- * @return an integer value representing the outcome of the operation.
- * @see android.os.storage.StorageResultCode
*/
- public int disableUsbMassStorage() {
+ public void disableUsbMassStorage() {
try {
- return mMountService.setUsbMassStorageEnabled(false);
+ mMountService.setUsbMassStorageEnabled(false);
} catch (Exception ex) {
Log.e(TAG, "Failed to disable UMS", ex);
}
- return StorageResultCode.OperationFailedInternalError;
}
/**
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b791bf8..b5c59c5 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2067,7 +2067,6 @@
<!-- See USB_STORAGE. This is the message. -->
<string name="usb_storage_notification_message">Select to copy files to/from your computer.</string>
-
<!-- USB_STORAGE_STOP: While USB storage is enabled, we show a notification dialog asking if he wants to stop. This is the title -->
<string name="usb_storage_stop_notification_title">Turn off USB storage</string>
<!-- See USB_STORAGE. This is the message. -->
@@ -2084,6 +2083,15 @@
<!-- See USB_STORAGE_STOP_DIALOG. If there was an error stopping, this is the text. -->
<string name="usb_storage_stop_error_message">There was a problem turning off USB storage. Check to make sure you have unmounted the USB host, then try again.</string>
+ <!-- USB_STORAGE_KILL_STORAGE_USERS dialog -->
+ <string name="dlg_confirm_kill_storage_users_title">Enable Mass Storage</string>
+ <!-- USB_STORAGE_KILL_STORAGE_USERS dialog message text -->
+ <string name="dlg_confirm_kill_storage_users_text">Some processes accessing data on sdcard will be killed. Do you want to continue?</string>
+ <!-- USB_STORAGE_ERROR dialog dialog-->
+ <string name="dlg_error_title">UMS operation failed</string>
+ <!-- USB_STORAGE_ERROR dialog ok button-->
+ <string name="dlg_ok">OK</string>
+
<!-- External media format dialog strings -->
<!-- This is the label for the activity, and should never be visible to the user. -->
<!-- See EXTMEDIA_FORMAT. EXTMEDIA_FORMAT_DIALOG: After the user selects the notification, a dialog is shown asking if he wants to format the SD card. This is the title. -->
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 4485c79..41f3850 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -111,15 +111,18 @@
private String mLegacyState = Environment.MEDIA_REMOVED;
private PackageManagerService mPms;
private boolean mUmsEnabling;
- private ArrayList<MountServiceBinderListener> mListeners;
+ // Used as a lock for methods that register/unregister listeners.
+ final private ArrayList<MountServiceBinderListener> mListeners =
+ new ArrayList<MountServiceBinderListener>();
private boolean mBooted = false;
private boolean mReady = false;
private boolean mSendUmsConnectedOnBoot = false;
/**
* Private hash of currently mounted secure containers.
+ * Used as a lock in methods to manipulate secure containers.
*/
- private HashSet<String> mAsecMountSet = new HashSet<String>();
+ final private HashSet<String> mAsecMountSet = new HashSet<String>();
private static final int H_UNMOUNT_PM_UPDATE = 1;
private static final int H_UNMOUNT_PM_DONE = 2;
@@ -148,6 +151,25 @@
this.path = path;
this.force = force;
}
+
+ void handleFinished() {
+ doUnmountVolume(path, true);
+ }
+ }
+
+ class UmsEnableCallBack extends UnmountCallBack {
+ String method;
+
+ UmsEnableCallBack(String path, String method, boolean force) {
+ super(path, force);
+ this.method = method;
+ }
+
+ @Override
+ void handleFinished() {
+ super.handleFinished();
+ doShareUnshareVolume(path, method, true);
+ }
}
final private Handler mHandler = new Handler() {
@@ -217,8 +239,7 @@
}
case H_UNMOUNT_MS : {
UnmountCallBack ucb = (UnmountCallBack) msg.obj;
- String path = ucb.path;
- doUnmountVolume(path, true);
+ ucb.handleFinished();
break;
}
}
@@ -298,52 +319,18 @@
}
}
- private int doShareUnshareVolume(String path, String method, boolean enable) {
- validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
-
+ private void doShareUnshareVolume(String path, String method, boolean enable) {
// TODO: Add support for multiple share methods
if (!method.equals("ums")) {
throw new IllegalArgumentException(String.format("Method %s not supported", method));
}
- /*
- * If the volume is mounted and we're enabling then unmount it
- */
- String vs = getVolumeState(path);
- if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
- mUmsEnabling = enable; // Override for isUsbMassStorageEnabled()
- int rc = doUnmountVolume(path, true);
- mUmsEnabling = false; // Clear override
- if (rc != StorageResultCode.OperationSucceeded) {
- Log.e(TAG, String.format("Failed to unmount before enabling UMS (%d)", rc));
- return rc;
- }
- }
-
try {
mConnector.doCommand(String.format(
"volume %sshare %s %s", (enable ? "" : "un"), path, method));
} catch (NativeDaemonConnectorException e) {
Log.e(TAG, "Failed to share/unshare", e);
- return StorageResultCode.OperationFailedInternalError;
}
-
- /*
- * If we disabled UMS then mount the volume
- */
- if (!enable) {
- if (doMountVolume(path) != StorageResultCode.OperationSucceeded) {
- Log.e(TAG, String.format(
- "Failed to remount %s after disabling share method %s", path, method));
- /*
- * Even though the mount failed, the unshare didn't so don't indicate an error.
- * The mountVolume() call will have set the storage state and sent the necessary
- * broadcasts.
- */
- }
- }
-
- return StorageResultCode.OperationSucceeded;
}
private void updatePublicVolumeState(String path, String state) {
@@ -547,7 +534,7 @@
if (!vs.equals(
Environment.MEDIA_BAD_REMOVAL) && !vs.equals(
Environment.MEDIA_NOFS) && !vs.equals(
- Environment.MEDIA_UNMOUNTABLE) && !mUmsEnabling) {
+ Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) {
updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
}
@@ -791,8 +778,6 @@
mContext.registerReceiver(mBroadcastReceiver,
new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
- mListeners = new ArrayList<MountServiceBinderListener>();
-
/*
* Vold does not run in the simulator, so pretend the connector thread
* ran and did its thing.
@@ -852,9 +837,7 @@
* the UMS host could have dirty FAT cache entries
* yet to flush.
*/
- if (setUsbMassStorageEnabled(false) != StorageResultCode.OperationSucceeded) {
- Log.e(TAG, "UMS disable on shutdown failed");
- }
+ setUsbMassStorageEnabled(false);
} else if (state.equals(Environment.MEDIA_CHECKING)) {
/*
* If the media is being checked, then we need to wait for
@@ -886,19 +869,62 @@
}
}
+ private boolean getUmsEnabling() {
+ synchronized (mListeners) {
+ return mUmsEnabling;
+ }
+ }
+
+ private void setUmsEnabling(boolean enable) {
+ synchronized (mListeners) {
+ mUmsEnabling = true;
+ }
+ }
+
public boolean isUsbMassStorageConnected() {
waitForReady();
- if (mUmsEnabling) {
+ if (getUmsEnabling()) {
return true;
}
return doGetShareMethodAvailable("ums");
}
- public int setUsbMassStorageEnabled(boolean enable) {
+ public void setUsbMassStorageEnabled(boolean enable) {
waitForReady();
+ validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
- return doShareUnshareVolume(Environment.getExternalStorageDirectory().getPath(), "ums", enable);
+ // TODO: Add support for multiple share methods
+
+ /*
+ * If the volume is mounted and we're enabling then unmount it
+ */
+ String path = Environment.getExternalStorageDirectory().getPath();
+ String vs = getVolumeState(path);
+ String method = "ums";
+ if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
+ // Override for isUsbMassStorageEnabled()
+ setUmsEnabling(enable);
+ UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true);
+ mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb));
+ // Clear override
+ setUmsEnabling(false);
+ }
+ /*
+ * If we disabled UMS then mount the volume
+ */
+ if (!enable) {
+ doShareUnshareVolume(path, method, enable);
+ if (doMountVolume(path) != StorageResultCode.OperationSucceeded) {
+ Log.e(TAG, "Failed to remount " + path +
+ " after disabling share method " + method);
+ /*
+ * Even though the mount failed, the unshare didn't so don't indicate an error.
+ * The mountVolume() call will have set the storage state and sent the necessary
+ * broadcasts.
+ */
+ }
+ }
}
public boolean isUsbMassStorageEnabled() {
diff --git a/services/java/com/android/server/status/UsbStorageActivity.java b/services/java/com/android/server/status/UsbStorageActivity.java
index 7a2a2d6..c1c8c22 100644
--- a/services/java/com/android/server/status/UsbStorageActivity.java
+++ b/services/java/com/android/server/status/UsbStorageActivity.java
@@ -16,25 +16,27 @@
package com.android.server.status;
+import com.android.internal.R;
import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.DialogInterface.OnCancelListener;
import android.os.Bundle;
-import android.os.Handler;
import android.os.Environment;
+import android.os.IBinder;
+import android.os.storage.IMountService;
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;
import android.widget.ImageView;
import android.widget.Button;
import android.widget.TextView;
-import android.widget.Toast;
import android.view.View;
import android.util.Log;
@@ -43,7 +45,8 @@
* on-demand (that is, when the USB cable is connected). It uses the alert
* dialog style. It will be launched from a notification.
*/
-public class UsbStorageActivity extends Activity {
+public class UsbStorageActivity extends Activity
+ implements View.OnClickListener, OnCancelListener {
private static final String TAG = "UsbStorageActivity";
private Button mMountButton;
private Button mUnmountButton;
@@ -51,6 +54,9 @@
private TextView mMessage;
private ImageView mIcon;
private StorageManager mStorageManager = null;
+ private static final int DLG_CONFIRM_KILL_STORAGE_USERS = 1;
+ private static final int DLG_ERROR_SHARING = 2;
+ static final boolean localLOGV = false;
/** Used to detect when the USB cable is unplugged, so we can call finish() */
private BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() {
@@ -82,7 +88,6 @@
if (mStorageManager == null) {
Log.w(TAG, "Failed to get StorageManager");
}
- mStorageManager.registerListener(mStorageListener);
}
setTitle(getString(com.android.internal.R.string.usb_storage_activity_title));
@@ -94,28 +99,9 @@
mMessage = (TextView) findViewById(com.android.internal.R.id.message);
mMountButton = (Button) findViewById(com.android.internal.R.id.mount_button);
- mMountButton.setOnClickListener(
- new View.OnClickListener() {
- public void onClick(View v) {
- int rc = mStorageManager.enableUsbMassStorage();
- if (rc != StorageResultCode.OperationSucceeded) {
- Log.e(TAG, String.format("UMS enable failed (%d)", rc));
- showSharingError();
- }
- }
- });
-
+ mMountButton.setOnClickListener(this);
mUnmountButton = (Button) findViewById(com.android.internal.R.id.unmount_button);
- mUnmountButton.setOnClickListener(
- new View.OnClickListener() {
- public void onClick(View v) {
- int rc = mStorageManager.disableUsbMassStorage();
- if (rc != StorageResultCode.OperationSucceeded) {
- Log.e(TAG, String.format("UMS disable failed (%d)", rc));
- showStoppingError();
- }
- }
- });
+ mUnmountButton.setOnClickListener(this);
}
private void switchDisplay(boolean usbStorageInUse) {
@@ -138,6 +124,7 @@
protected void onResume() {
super.onResume();
+ mStorageManager.registerListener(mStorageListener);
registerReceiver(mBatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
try {
switchDisplay(mStorageManager.isUsbMassStorageEnabled());
@@ -151,6 +138,9 @@
super.onPause();
unregisterReceiver(mBatteryReceiver);
+ if (mStorageManager == null && mStorageListener != null) {
+ mStorageManager.unregisterListener(mStorageListener);
+ }
}
private void handleBatteryChanged(Intent intent) {
@@ -160,15 +150,81 @@
finish();
}
}
-
- private void showSharingError() {
- Toast.makeText(this, com.android.internal.R.string.usb_storage_error_message,
- Toast.LENGTH_LONG).show();
+
+ private IMountService getMountService() {
+ IBinder service = ServiceManager.getService("mount");
+ if (service != null) {
+ return IMountService.Stub.asInterface(service);
+ }
+ return null;
}
-
- private void showStoppingError() {
- Toast.makeText(this, com.android.internal.R.string.usb_storage_stop_error_message,
- Toast.LENGTH_LONG).show();
+
+ @Override
+ public Dialog onCreateDialog(int id, Bundle args) {
+ switch (id) {
+ case DLG_CONFIRM_KILL_STORAGE_USERS:
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.dlg_confirm_kill_storage_users_title)
+ .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ mStorageManager.enableUsbMassStorage();
+ }})
+ .setNegativeButton(R.string.cancel, null)
+ .setMessage(R.string.dlg_confirm_kill_storage_users_text)
+ .setOnCancelListener(this)
+ .create();
+ case DLG_ERROR_SHARING:
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.dlg_error_title)
+ .setNeutralButton(R.string.dlg_ok, null)
+ .setMessage(R.string.usb_storage_error_message)
+ .setOnCancelListener(this)
+ .create();
+ }
+ return null;
+ }
+
+ private void showDialogInner(int id) {
+ removeDialog(id);
+ showDialog(id);
+ }
+
+ private void checkStorageUsers() {
+ IMountService ims = getMountService();
+ if (ims == null) {
+ // Display error dialog
+ showDialogInner(DLG_ERROR_SHARING);
+ }
+ String path = Environment.getExternalStorageDirectory().getPath();
+ int stUsers[] = null;
+ try {
+ if (localLOGV) Log.i(TAG, "Checking getStorageUsers");
+ stUsers = ims.getStorageUsers(path);
+ } catch (RemoteException e) {
+ showDialogInner(DLG_ERROR_SHARING);
+ }
+ if (stUsers != null && stUsers.length > 0) {
+ // Display dialog to user
+ showDialogInner(DLG_CONFIRM_KILL_STORAGE_USERS);
+ } else {
+ if (localLOGV) Log.i(TAG, "Enabling UMS");
+ mStorageManager.enableUsbMassStorage();
+ }
+ }
+
+ public void onClick(View v) {
+ Log.i(TAG, "Clicked button");
+ if (v == mMountButton) {
+ // Check for list of storage users and display dialog if needed.
+ checkStorageUsers();
+ } else if (v == mUnmountButton) {
+ if (localLOGV) Log.i(TAG, "Disabling UMS");
+ mStorageManager.disableUsbMassStorage();
+ }
+ }
+
+ public void onCancel(DialogInterface dialog) {
+ finish();
}
}