Merge "Only log unique mime types." into sc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 336e8eb..d57a013 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -89,10 +89,6 @@
                 <data android:scheme="package" />
             </intent-filter>
             <intent-filter>
-                <action android:name="android.intent.action.MEDIA_MOUNTED" />
-                <data android:scheme="file" />
-            </intent-filter>
-            <intent-filter>
                 <action android:name="android.intent.action.MEDIA_SCANNER_SCAN_FILE" />
                 <data android:scheme="file" />
             </intent-filter>
diff --git a/src/com/android/providers/media/MediaService.java b/src/com/android/providers/media/MediaService.java
index 5e3e10f..bc7330a 100644
--- a/src/com/android/providers/media/MediaService.java
+++ b/src/com/android/providers/media/MediaService.java
@@ -29,6 +29,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Trace;
+import android.os.UserHandle;
 import android.os.storage.StorageVolume;
 import android.provider.MediaStore;
 import android.util.Log;
@@ -43,6 +44,21 @@
 public class MediaService extends JobIntentService {
     private static final int JOB_ID = -300;
 
+    private static final String ACTION_SCAN_VOLUME
+            = "com.android.providers.media.action.SCAN_VOLUME";
+
+    private static final String EXTRA_MEDIAVOLUME = "MediaVolume";
+
+    private static final String EXTRA_SCAN_REASON = "scan_reason";
+
+
+    public static void queueVolumeScan(Context context, MediaVolume volume, int reason) {
+        Intent intent = new Intent(ACTION_SCAN_VOLUME);
+        intent.putExtra(EXTRA_MEDIAVOLUME, volume) ;
+        intent.putExtra(EXTRA_SCAN_REASON, reason);
+        enqueueWork(context, intent);
+    }
+
     public static void enqueueWork(Context context, Intent work) {
         enqueueWork(context, MediaService.class, JOB_ID, work);
     }
@@ -69,8 +85,10 @@
                     onScanFile(this, intent.getData());
                     break;
                 }
-                case Intent.ACTION_MEDIA_MOUNTED: {
-                    onScanVolume(this, intent, REASON_MOUNTED);
+                case ACTION_SCAN_VOLUME: {
+                    final MediaVolume volume = intent.getParcelableExtra(EXTRA_MEDIAVOLUME);
+                    int reason = intent.getIntExtra(EXTRA_SCAN_REASON, REASON_DEMAND);
+                    onScanVolume(this, volume, reason);
                     break;
                 }
                 default: {
@@ -116,6 +134,11 @@
     public static void onScanVolume(Context context, MediaVolume volume, int reason)
             throws IOException {
         final String volumeName = volume.getName();
+        UserHandle owner = volume.getUser();
+        if (owner == null) {
+            // Can happen for the internal volume
+            owner = context.getUser();
+        }
         // If we're about to scan any external storage, scan internal first
         // to ensure that we have ringtones ready to roll before a possibly very
         // long external storage scan
@@ -129,7 +152,7 @@
         // in the situation where a volume is ejected mid-scan
         final Uri broadcastUri;
         if (!MediaStore.VOLUME_INTERNAL.equals(volumeName)) {
-            broadcastUri = Uri.fromFile(FileUtils.getVolumePath(context, volumeName));
+            broadcastUri = Uri.fromFile(volume.getPath());
         } else {
             broadcastUri = null;
         }
@@ -146,20 +169,24 @@
             Uri scanUri = resolver.insert(MediaStore.getMediaScannerUri(), values);
 
             if (broadcastUri != null) {
-                context.sendBroadcast(
-                        new Intent(Intent.ACTION_MEDIA_SCANNER_STARTED, broadcastUri));
+                context.sendBroadcastAsUser(
+                        new Intent(Intent.ACTION_MEDIA_SCANNER_STARTED, broadcastUri), owner);
             }
 
-            for (File dir : FileUtils.getVolumeScanPaths(context, volumeName)) {
-                provider.scanDirectory(dir, reason);
+            if (MediaStore.VOLUME_INTERNAL.equals(volumeName)) {
+                for (File dir : FileUtils.getVolumeScanPaths(context, volumeName)) {
+                    provider.scanDirectory(dir, reason);
+                }
+            } else {
+                provider.scanDirectory(volume.getPath(), reason);
             }
 
             resolver.delete(scanUri, null, null);
 
         } finally {
             if (broadcastUri != null) {
-                context.sendBroadcast(
-                        new Intent(Intent.ACTION_MEDIA_SCANNER_FINISHED, broadcastUri));
+                context.sendBroadcastAsUser(
+                        new Intent(Intent.ACTION_MEDIA_SCANNER_FINISHED, broadcastUri), owner);
             }
         }
     }
diff --git a/src/com/android/providers/media/MediaVolume.java b/src/com/android/providers/media/MediaVolume.java
index 577a040..461f67d 100644
--- a/src/com/android/providers/media/MediaVolume.java
+++ b/src/com/android/providers/media/MediaVolume.java
@@ -16,6 +16,8 @@
 
 package com.android.providers.media;
 
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.UserHandle;
 import android.os.storage.StorageVolume;
 import android.provider.MediaStore;
@@ -37,7 +39,7 @@
  * In addition to that, we keep the path and ID of the volume cached in here as well
  * for easy access.
  */
-public final class MediaVolume {
+public final class MediaVolume implements Parcelable {
     /**
      * Name of the volume.
      */
@@ -81,6 +83,13 @@
         this.mId = id;
     }
 
+    private MediaVolume (Parcel in) {
+        this.mName = in.readString();
+        this.mUser = in.readParcelable(null);
+        this.mPath  = new File(in.readString());
+        this.mId = in.readString();
+    }
+
     @Override
     public boolean equals(Object obj) {
         if (this == obj) return true;
@@ -115,4 +124,30 @@
 
         return new MediaVolume(name, null, null, null);
     }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mName);
+        dest.writeParcelable(mUser, flags);
+        dest.writeString(mPath.toString());
+        dest.writeString(mId);
+    }
+
+    public static final @android.annotation.NonNull Creator<MediaVolume> CREATOR
+            = new Creator<MediaVolume>() {
+        @Override
+        public MediaVolume createFromParcel(Parcel in) {
+            return new MediaVolume(in);
+        }
+
+        @Override
+        public MediaVolume[] newArray(int size) {
+            return new MediaVolume[size];
+        }
+    };
 }
diff --git a/src/com/android/providers/media/fuse/ExternalStorageServiceImpl.java b/src/com/android/providers/media/fuse/ExternalStorageServiceImpl.java
index 612889d..1f8f3cd 100644
--- a/src/com/android/providers/media/fuse/ExternalStorageServiceImpl.java
+++ b/src/com/android/providers/media/fuse/ExternalStorageServiceImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.providers.media.fuse;
 
+import static com.android.providers.media.scan.MediaScanner.REASON_MOUNTED;
+
 import android.annotation.BytesLong;
 import android.content.ContentProviderClient;
 import android.os.Environment;
@@ -30,6 +32,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.providers.media.MediaProvider;
+import com.android.providers.media.MediaService;
 import com.android.providers.media.MediaVolume;
 
 import java.io.File;
@@ -83,8 +86,9 @@
 
         switch(vol.getState()) {
             case Environment.MEDIA_MOUNTED:
-                mediaProvider.attachVolume(MediaVolume.fromStorageVolume(vol),
-                        /* validate */ false);
+                MediaVolume volume = MediaVolume.fromStorageVolume(vol);
+                mediaProvider.attachVolume(volume, /* validate */ false);
+                MediaService.queueVolumeScan(mediaProvider.getContext(), volume, REASON_MOUNTED);
                 break;
             case Environment.MEDIA_UNMOUNTED:
             case Environment.MEDIA_EJECTING:
diff --git a/src/com/android/providers/media/util/FileUtils.java b/src/com/android/providers/media/util/FileUtils.java
index 47e1559..a6311bd 100644
--- a/src/com/android/providers/media/util/FileUtils.java
+++ b/src/com/android/providers/media/util/FileUtils.java
@@ -1022,7 +1022,7 @@
      * Regex that matches user-ids under well-known storage paths.
      */
     private static final Pattern PATTERN_USER_ID = Pattern.compile(
-            "(?i)^/storage/emulated/([0-9]+)/");
+            "(?i)^/storage/emulated/([0-9]+)");
 
     private static final String CAMERA_RELATIVE_PATH =
             String.format("%s/%s/", Environment.DIRECTORY_DCIM, "Camera");