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.
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..ad4cb105 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();
     }
 
 }