Add dialog to display storage users when enabling/disabling ums

Some error dialogs and related strings
MountService changes to follow unmount path when enabling ums.

Please note that MountService api setUmsEnabled does not return
error codes for now. This is a known limitation.
This commit is contained in:
Suchi Amalapurapu
2010-02-25 17:07:14 -08:00
parent 4c904a3bf3
commit 0eec21d97d
6 changed files with 183 additions and 97 deletions

View File

@@ -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"

View File

@@ -45,8 +45,10 @@ interface IMountService
/**
* 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)

View File

@@ -243,30 +243,24 @@ public class StorageManager
/**
* 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;
}
/**

View File

@@ -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. -->

View File

@@ -111,15 +111,18 @@ class MountService extends IMountService.Stub
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 @@ class MountService extends IMountService.Stub
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 @@ class MountService extends IMountService.Stub
}
case H_UNMOUNT_MS : {
UnmountCallBack ucb = (UnmountCallBack) msg.obj;
String path = ucb.path;
doUnmountVolume(path, true);
ucb.handleFinished();
break;
}
}
@@ -298,52 +319,18 @@ class MountService extends IMountService.Stub
}
}
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 @@ class MountService extends IMountService.Stub
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 @@ class MountService extends IMountService.Stub
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 @@ class MountService extends IMountService.Stub
* 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 @@ class MountService extends IMountService.Stub
}
}
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() {

View File

@@ -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 @@ import android.util.Log;
* 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 @@ public class UsbStorageActivity extends Activity {
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 @@ public class UsbStorageActivity extends Activity {
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 @@ public class UsbStorageActivity extends Activity {
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 @@ public class UsbStorageActivity extends Activity {
protected void onResume() {
super.onResume();
mStorageManager.registerListener(mStorageListener);
registerReceiver(mBatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
try {
switchDisplay(mStorageManager.isUsbMassStorageEnabled());
@@ -151,6 +138,9 @@ public class UsbStorageActivity extends Activity {
super.onPause();
unregisterReceiver(mBatteryReceiver);
if (mStorageManager == null && mStorageListener != null) {
mStorageManager.unregisterListener(mStorageListener);
}
}
private void handleBatteryChanged(Intent intent) {
@@ -160,15 +150,81 @@ public class UsbStorageActivity extends Activity {
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();
}
}