Add API to set context and session id to SoundPool.

Bug: 174876164
Bug: 261698699
Bug: 249777386
Test: atest SoundPoolTest
Change-Id: I3dbf0de523dc2047a5c90aabb502f3abb312ab2a
diff --git a/core/api/current.txt b/core/api/current.txt
index 9da95c0..0c8b010 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -24191,6 +24191,8 @@
     ctor public SoundPool.Builder();
     method public android.media.SoundPool build();
     method public android.media.SoundPool.Builder setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
+    method @NonNull public android.media.SoundPool.Builder setAudioSessionId(int);
+    method @NonNull public android.media.SoundPool.Builder setContext(@NonNull android.content.Context);
     method public android.media.SoundPool.Builder setMaxStreams(int) throws java.lang.IllegalArgumentException;
   }
 
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index dc09359..f33a744 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -16,6 +16,8 @@
 
 package android.media;
 
+import static android.media.AudioManager.AUDIO_SESSION_ID_GENERATE;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
@@ -29,6 +31,7 @@
 
 import java.io.File;
 import java.io.FileDescriptor;
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicReference;
 
 
@@ -146,12 +149,14 @@
      *     SoundPool instance
      */
     public SoundPool(int maxStreams, int streamType, int srcQuality) {
-        this(maxStreams,
-                new AudioAttributes.Builder().setInternalLegacyStreamType(streamType).build());
+        this(/*context=*/null, maxStreams,
+                new AudioAttributes.Builder().setInternalLegacyStreamType(streamType).build(),
+                AUDIO_SESSION_ID_GENERATE);
         PlayerBase.deprecateStreamTypeForPlayback(streamType, "SoundPool", "SoundPool()");
     }
 
-    private SoundPool(int maxStreams, AudioAttributes attributes) {
+    private SoundPool(@Nullable Context context, int maxStreams,
+            @NonNull AudioAttributes attributes, int sessionId) {
         super(attributes, AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL);
 
         // do native setup
@@ -160,8 +165,7 @@
         }
         mAttributes = attributes;
 
-        // FIXME: b/174876164 implement session id for soundpool
-        baseRegisterPlayer(AudioSystem.AUDIO_SESSION_ALLOCATE);
+        baseRegisterPlayer(resolvePlaybackSessionId(context, sessionId));
     }
 
     /**
@@ -555,6 +559,8 @@
     public static class Builder {
         private int mMaxStreams = 1;
         private AudioAttributes mAudioAttributes;
+        private Context mContext;
+        private int mSessionId = AUDIO_SESSION_ID_GENERATE;
 
         /**
          * Constructs a new Builder with the defaults format values.
@@ -596,12 +602,49 @@
             return this;
         }
 
+        /**
+         * Sets the session ID the {@link SoundPool} will be attached to.
+         *
+         * Note, that if there's a device specific session id associated with the context
+         * (see {@link Builder#setContext(Context)}), explicitly setting a session id using this
+         * method will override it.
+         *
+         * @param sessionId a strictly positive ID number retrieved from another player or
+         *   allocated by {@link AudioManager} via {@link AudioManager#generateAudioSessionId()},
+         *   or {@link AudioManager#AUDIO_SESSION_ID_GENERATE}.
+         * @return the same {@link Builder} instance
+         * @throws IllegalArgumentException when sessionId is invalid.
+         */
+        public @NonNull Builder setAudioSessionId(int sessionId) {
+            if ((sessionId != AUDIO_SESSION_ID_GENERATE) && (sessionId < 1)) {
+                throw new IllegalArgumentException("Invalid audio session ID " + sessionId);
+            }
+            mSessionId = sessionId;
+            return this;
+        }
+
+        /**
+         * Sets the context the SoundPool belongs to.
+         *
+         * The context will be used to pull information, such as
+         * {@link android.content.AttributionSource} and device specific audio session ids,
+         * which will be associated with the {@link SoundPool}. However, the context itself will
+         * not be retained by the {@link SoundPool} instance after initialization.
+         *
+         * @param context a non-null {@link Context} instance
+         * @return the same {@link Builder} instance.
+         */
+        public @NonNull Builder setContext(@NonNull Context context) {
+            mContext = Objects.requireNonNull(context);
+            return this;
+        }
+
         public SoundPool build() {
             if (mAudioAttributes == null) {
                 mAudioAttributes = new AudioAttributes.Builder()
                         .setUsage(AudioAttributes.USAGE_MEDIA).build();
             }
-            return new SoundPool(mMaxStreams, mAudioAttributes);
+            return new SoundPool(mContext, mMaxStreams, mAudioAttributes, mSessionId);
         }
     }
 }