am f99e29a2: am f58f4b95: Merge "Multi-user MTP, handle secondary user boot." into jb-mr1-dev

* commit 'f99e29a2845a171e29ff7fbd879e4a71be43cd5b':
  Multi-user MTP, handle secondary user boot.
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 34b6a94..f035150 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -10,6 +10,8 @@
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
     <uses-permission android:name="android.permission.ACCESS_MTP" />
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
 
     <application android:process="android.process.media"
                  android:label="@string/app_label"
@@ -57,12 +59,15 @@
             </intent-filter>
         </service>
 
-        <receiver android:name="UsbReceiver">
+        <receiver android:name=".MtpReceiver">
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED" />
+            </intent-filter>
             <intent-filter>
                 <action android:name="android.hardware.usb.action.USB_STATE" />
             </intent-filter>
         </receiver>
- 
+
         <service android:name="MtpService" />
 
         <activity android:name="RingtonePickerActivity"
diff --git a/src/com/android/providers/media/MediaScannerReceiver.java b/src/com/android/providers/media/MediaScannerReceiver.java
index fe53a23..53eec55 100644
--- a/src/com/android/providers/media/MediaScannerReceiver.java
+++ b/src/com/android/providers/media/MediaScannerReceiver.java
@@ -17,28 +17,38 @@
 
 package com.android.providers.media;
 
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.BroadcastReceiver;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Environment;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
 import android.util.Log;
 
-import java.io.File;
-
-
-public class MediaScannerReceiver extends BroadcastReceiver
-{
+public class MediaScannerReceiver extends BroadcastReceiver {
     private final static String TAG = "MediaScannerReceiver";
 
     @Override
     public void onReceive(Context context, Intent intent) {
-        String action = intent.getAction();
-        Uri uri = intent.getData();
-        if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
-            // scan internal storage
+        final String action = intent.getAction();
+        final Uri uri = intent.getData();
+        if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
+            // Scan internal storage
             scan(context, MediaProvider.INTERNAL_VOLUME);
+
+            // Scan any available external storage
+            // TODO: switch to atomic fetching of volume state
+            final StorageManager sm = StorageManager.from(context);
+            for (StorageVolume volume : sm.getVolumeList()) {
+                final String state = sm.getVolumeState(volume.getPath());
+                if (Environment.MEDIA_MOUNTED.equals(state)
+                        || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
+                    scan(context, volume.getPath());
+                }
+            }
+
         } else {
             if (uri.getScheme().equals("file")) {
                 // handle intents related to external storage
@@ -46,10 +56,10 @@
                 String externalStoragePath = Environment.getExternalStorageDirectory().getPath();
 
                 Log.d(TAG, "action: " + action + " path: " + path);
-                if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
+                if (Intent.ACTION_MEDIA_MOUNTED.equals(action)) {
                     // scan whenever any volume is mounted
                     scan(context, MediaProvider.EXTERNAL_VOLUME);
-                } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE) &&
+                } else if (Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action) &&
                         path != null && path.startsWith(externalStoragePath + "/")) {
                     scanFile(context, path);
                 }
@@ -71,5 +81,3 @@
                 new Intent(context, MediaScannerService.class).putExtras(args));
     }    
 }
-
-
diff --git a/src/com/android/providers/media/UsbReceiver.java b/src/com/android/providers/media/MtpReceiver.java
similarity index 77%
rename from src/com/android/providers/media/UsbReceiver.java
rename to src/com/android/providers/media/MtpReceiver.java
index 7a39bc8..23d529b 100644
--- a/src/com/android/providers/media/UsbReceiver.java
+++ b/src/com/android/providers/media/MtpReceiver.java
@@ -16,22 +16,32 @@
 
 package com.android.providers.media;
 
-import android.content.Context;
-import android.content.ContentValues;
-import android.content.Intent;
 import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.hardware.usb.UsbManager;
 import android.net.Uri;
 import android.os.Bundle;
-import android.util.Log;
 
-
-public class UsbReceiver extends BroadcastReceiver
-{
+public class MtpReceiver extends BroadcastReceiver {
     private final static String TAG = "UsbReceiver";
 
     @Override
     public void onReceive(Context context, Intent intent) {
+        final String action = intent.getAction();
+        if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
+            final Intent usbState = context.registerReceiver(
+                    null, new IntentFilter(UsbManager.ACTION_USB_STATE));
+            if (usbState != null) {
+                handleUsbState(context, usbState);
+            }
+        } else if (UsbManager.ACTION_USB_STATE.equals(action)) {
+            handleUsbState(context, intent);
+        }
+    }
+
+    private void handleUsbState(Context context, Intent intent) {
         Bundle extras = intent.getExtras();
         boolean connected = extras.getBoolean(UsbManager.USB_CONFIGURED);
         boolean mtpEnabled = extras.getBoolean(UsbManager.USB_FUNCTION_MTP);
@@ -54,5 +64,3 @@
         }
     }
 }
-
-
diff --git a/src/com/android/providers/media/MtpService.java b/src/com/android/providers/media/MtpService.java
index 2d707b9..04033e9 100644
--- a/src/com/android/providers/media/MtpService.java
+++ b/src/com/android/providers/media/MtpService.java
@@ -16,6 +16,7 @@
 
 package com.android.providers.media;
 
+import android.app.ActivityManager;
 import android.app.KeyguardManager;
 import android.app.Service;
 import android.content.BroadcastReceiver;
@@ -28,6 +29,7 @@
 import android.mtp.MtpStorage;
 import android.os.Environment;
 import android.os.IBinder;
+import android.os.UserHandle;
 import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageVolume;
@@ -38,6 +40,7 @@
 
 public class MtpService extends Service {
     private static final String TAG = "MtpService";
+    private static final boolean LOGD = true;
 
     // We restrict PTP to these subdirectories
     private static final String[] PTP_DIRECTORIES = new String[] {
@@ -80,6 +83,7 @@
     };
 
     private final StorageEventListener mStorageEventListener = new StorageEventListener() {
+        @Override
         public void onStorageStateChanged(String path, String oldState, String newState) {
             synchronized (mBinder) {
                 Log.d(TAG, "onStorageStateChanged " + path + " " + oldState + " -> " + newState);
@@ -98,7 +102,8 @@
     private MtpDatabase mDatabase;
     private MtpServer mServer;
     private StorageManager mStorageManager;
-    private boolean mMtpDisabled; // true if MTP is disabled due to secure keyguard
+    /** Flag indicating if MTP is disabled due to keyguard */
+    private boolean mMtpDisabled;
     private boolean mPtpMode;
     private final HashMap<String, StorageVolume> mVolumeMap = new HashMap<String, StorageVolume>();
     private final HashMap<String, MtpStorage> mStorageMap = new HashMap<String, MtpStorage>();
@@ -106,14 +111,11 @@
 
     @Override
     public void onCreate() {
-        // lock MTP if the keyguard is locked and secure
-        KeyguardManager keyguardManager =
-                (KeyguardManager)getSystemService(Context.KEYGUARD_SERVICE);
-        mMtpDisabled = keyguardManager.isKeyguardLocked() && keyguardManager.isKeyguardSecure();
         registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_USER_PRESENT));
 
-        mStorageManager = (StorageManager)getSystemService(Context.STORAGE_SERVICE);
+        mStorageManager = StorageManager.from(this);
         synchronized (mBinder) {
+            updateDisabledStateLocked();
             mStorageManager.registerListener(mStorageEventListener);
             StorageVolume[] volumes = mStorageManager.getVolumeList();
             mVolumes = volumes;
@@ -121,7 +123,7 @@
                 String path = volumes[i].getPath();
                 String state = mStorageManager.getVolumeState(path);
                 if (Environment.MEDIA_MOUNTED.equals(state)) {
-                   volumeMountedLocked(path);
+                    volumeMountedLocked(path);
                 }
             }
         }
@@ -130,39 +132,64 @@
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
         synchronized (mBinder) {
-            if (mServer == null) {
-                mPtpMode = (intent == null ? false
-                        : intent.getBooleanExtra(UsbManager.USB_FUNCTION_PTP, false));
-                Log.d(TAG, "starting MTP server in " + (mPtpMode ? "PTP mode" : "MTP mode"));
-                String[] subdirs = null;
-                if (mPtpMode) {
-                    int count = PTP_DIRECTORIES.length;
-                    subdirs = new String[count];
-                    for (int i = 0; i < count; i++) {
-                        File file =
-                                Environment.getExternalStoragePublicDirectory(PTP_DIRECTORIES[i]);
-                        // make sure this directory exists
-                        file.mkdirs();
-                        subdirs[i] = file.getPath();
-                    }
+            updateDisabledStateLocked();
+            mPtpMode = (intent == null ? false
+                    : intent.getBooleanExtra(UsbManager.USB_FUNCTION_PTP, false));
+            String[] subdirs = null;
+            if (mPtpMode) {
+                int count = PTP_DIRECTORIES.length;
+                subdirs = new String[count];
+                for (int i = 0; i < count; i++) {
+                    File file =
+                            Environment.getExternalStoragePublicDirectory(PTP_DIRECTORIES[i]);
+                    // make sure this directory exists
+                    file.mkdirs();
+                    subdirs[i] = file.getPath();
                 }
-                final StorageVolume primary = StorageManager.getPrimaryVolume(mVolumes);
-                mDatabase = new MtpDatabase(this, MediaProvider.EXTERNAL_VOLUME,
-                        primary.getPath(), subdirs);
-                mServer = new MtpServer(mDatabase, mPtpMode);
-                if (!mMtpDisabled) {
-                    addStorageDevicesLocked();
-                }
-                mServer.start();
             }
+            final StorageVolume primary = StorageManager.getPrimaryVolume(mVolumes);
+            mDatabase = new MtpDatabase(this, MediaProvider.EXTERNAL_VOLUME,
+                    primary.getPath(), subdirs);
+            manageServiceLocked();
         }
 
         return START_STICKY;
     }
 
+    private void updateDisabledStateLocked() {
+        final boolean isCurrentUser = UserHandle.myUserId() == ActivityManager.getCurrentUser();
+        final KeyguardManager keyguardManager = (KeyguardManager) getSystemService(
+                Context.KEYGUARD_SERVICE);
+        mMtpDisabled = (keyguardManager.isKeyguardLocked() && keyguardManager.isKeyguardSecure())
+                || !isCurrentUser;
+        if (LOGD) {
+            Log.d(TAG, "updating state; isCurrentUser=" + isCurrentUser + ", mMtpLocked="
+                    + mMtpDisabled);
+        }
+    }
+
+    /**
+     * Manage {@link #mServer}, creating only when running as the current user.
+     */
+    private void manageServiceLocked() {
+        final boolean isCurrentUser = UserHandle.myUserId() == ActivityManager.getCurrentUser();
+        if (mServer == null && isCurrentUser) {
+            Log.d(TAG, "starting MTP server in " + (mPtpMode ? "PTP mode" : "MTP mode"));
+            mServer = new MtpServer(mDatabase, mPtpMode);
+            if (!mMtpDisabled) {
+                addStorageDevicesLocked();
+            }
+            mServer.start();
+        } else if (mServer != null && !isCurrentUser) {
+            Log.d(TAG, "no longer current user; shutting down MTP server");
+            // Internally, kernel will close our FD, and server thread will
+            // handle cleanup.
+            mServer = null;
+        }
+    }
+
     @Override
-    public void onDestroy()
-    {
+    public void onDestroy() {
         unregisterReceiver(mReceiver);
         mStorageManager.unregisterListener(mStorageEventListener);
     }
@@ -187,8 +214,7 @@
     };
 
     @Override
-    public IBinder onBind(Intent intent)
-    {
+    public IBinder onBind(Intent intent) {
         return mBinder;
     }
 
@@ -212,8 +238,8 @@
         MtpStorage storage = new MtpStorage(volume, getApplicationContext());
         String path = storage.getPath();
         mStorageMap.put(path, storage);
-        
-        Log.d(TAG, "addStorageLocked " + storage.getStorageId() + " " +path);
+
+        Log.d(TAG, "addStorageLocked " + storage.getStorageId() + " " + path);
         if (mDatabase != null) {
             mDatabase.addStorage(storage);
         }
@@ -238,4 +264,3 @@
         }
     }
 }
-