VolumeShaper: Remove PlayerProxy constructor

Use of the VolumeShaper through PlayerProxy requires system ids,
which is different enough from PlayerBase that we don't allow
direct construction.

Test: Ducking
Bug: 31015569
Change-Id: Ia98ec5396047ae39e78237bb7e485d07f2eb1efd
diff --git a/media/java/android/media/VolumeShaper.java b/media/java/android/media/VolumeShaper.java
index 4a2c4d8..5b43136 100644
--- a/media/java/android/media/VolumeShaper.java
+++ b/media/java/android/media/VolumeShaper.java
@@ -38,8 +38,6 @@
     /* member variables */
     private int mId;
     private final WeakReference<PlayerBase> mWeakPlayerBase;
-    private final WeakReference<PlayerProxy> mWeakPlayerProxy;
-    private PlayerProxy mPlayerProxy;
 
     /**
      * Constructs a {@code VolumeShaper} from a {@link VolumeShaper.Configuration} and an
@@ -66,35 +64,6 @@
     /* package */ VolumeShaper(
             @NonNull Configuration configuration, @NonNull PlayerBase playerBase) {
         mWeakPlayerBase = new WeakReference<PlayerBase>(playerBase);
-        mPlayerProxy = null;
-        mWeakPlayerProxy = null;
-        mId = applyPlayer(configuration, new Operation.Builder().defer().build());
-    }
-
-    /**
-     * @hide
-     * Constructs a {@code VolumeShaper} from a {@link VolumeShaper.Configuration} and a
-     * {@code PlayerProxy} object.  The PlayerProxy object requires that the configuration
-     * be set with a system VolumeShaper id (this is a reserved value).
-     *
-     * @param configuration
-     * @param playerProxy
-     */
-    public VolumeShaper(
-            @NonNull Configuration configuration,
-            @NonNull PlayerProxy playerProxy,
-            boolean keepReference) {
-        if (configuration.getId() < 0) {
-            throw new IllegalArgumentException("playerProxy configuration id must be specified");
-        }
-        if (keepReference) {
-            mPlayerProxy = playerProxy;
-            mWeakPlayerProxy = null;
-        } else {
-            mWeakPlayerProxy = new WeakReference<PlayerProxy>(playerProxy);
-            mPlayerProxy = null;
-        }
-        mWeakPlayerBase = null;
         mId = applyPlayer(configuration, new Operation.Builder().defer().build());
     }
 
@@ -155,10 +124,6 @@
         if (mWeakPlayerBase != null) {
             mWeakPlayerBase.clear();
         }
-        if (mWeakPlayerProxy != null) {
-            mWeakPlayerProxy.clear();
-        }
-        mPlayerProxy = null;
     }
 
     @Override
@@ -177,20 +142,7 @@
             @NonNull VolumeShaper.Configuration configuration,
             @NonNull VolumeShaper.Operation operation) {
         final int id;
-        if (mPlayerProxy != null || mWeakPlayerProxy != null) {
-            // The PlayerProxy accepts only one way transactions so
-            // the Configuration must have an id set to one of the system
-            // ids (a positive value less than 16).
-            PlayerProxy player = mWeakPlayerProxy != null ? mWeakPlayerProxy.get() : mPlayerProxy;
-            if (player == null) {
-                throw new IllegalStateException("player deallocated");
-            }
-            id = configuration.getId();
-            if (id < 0) {
-                throw new IllegalArgumentException("proxy requires configuration with id");
-            }
-            player.applyVolumeShaper(configuration, operation);
-        } else if (mWeakPlayerBase != null) {
+        if (mWeakPlayerBase != null) {
             PlayerBase player = mWeakPlayerBase.get();
             if (player == null) {
                 throw new IllegalStateException("player deallocated");
@@ -220,9 +172,7 @@
      */
     private @NonNull VolumeShaper.State getStatePlayer(int id) {
         final VolumeShaper.State state;
-        if (mPlayerProxy != null || mWeakPlayerProxy != null) {
-            throw new IllegalStateException("getStatePlayer not permitted through proxy");
-        } else if (mWeakPlayerBase != null) {
+        if (mWeakPlayerBase != null) {
             PlayerBase player = mWeakPlayerBase.get();
             if (player == null) {
                 throw new IllegalStateException("player deallocated");
@@ -510,6 +460,7 @@
         };
 
         /**
+         * @hide
          * Constructs a volume shaper from an id.
          *
          * This is an opaque handle for controlling a {@code VolumeShaper} that has
@@ -522,7 +473,7 @@
          * @param id
          * @throws IllegalArgumentException if id is negative.
          */
-        private Configuration(int id) {
+        public Configuration(int id) {
             if (id < 0) {
                 throw new IllegalArgumentException("negative id " + id);
             }
@@ -1039,6 +990,13 @@
          */
         private static final int FLAG_DEFER = 1 << 3;
 
+        /**
+         * Use the id specified in the configuration, creating
+         * VolumeShaper as needed; the configuration should be
+         * TYPE_SCALE.
+         */
+        private static final int FLAG_CREATE_IF_NEEDED = 1 << 4;
+
         private static final int FLAG_PUBLIC_ALL = FLAG_REVERSE | FLAG_TERMINATE;
 
         private final int mFlags;
@@ -1175,6 +1133,17 @@
             }
 
             /**
+             * Use the id specified in the configuration, creating
+             * VolumeShaper as needed; the configuration should be
+             * TYPE_SCALE.
+             * @return the same Builder instance.
+             */
+            public @NonNull Builder createIfNeeded() {
+                mFlags |= FLAG_CREATE_IF_NEEDED;
+                return this;
+            }
+
+            /**
              * Sets the operation flag.  Do not call this directly but one of the
              * other builder methods.
              *
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index e8ff510..d648dd8 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -51,14 +51,36 @@
     private final static boolean DEBUG = false;
     private final static int VOLUME_SHAPER_SYSTEM_DUCK_ID = 1;
 
-    private ArrayList<PlayMonitorClient> mClients = new ArrayList<PlayMonitorClient>();
+    private final VolumeShaper.Configuration DUCK_VSHAPE =
+            new VolumeShaper.Configuration.Builder()
+                .setId(VOLUME_SHAPER_SYSTEM_DUCK_ID)
+                .setCurve(new float[] { 0.f, 1.f } /* times */,
+                    new float[] { 1.f, 0.2f } /* volumes */)
+                .setOptionFlags(VolumeShaper.Configuration.OPTION_FLAG_CLOCK_TIME)
+                .setDurationMs(MediaFocusControl.getFocusRampTimeMs(
+                    AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
+                    new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION)
+                            .build()))
+                .build();
+    private final VolumeShaper.Configuration DUCK_ID =
+            new VolumeShaper.Configuration(VOLUME_SHAPER_SYSTEM_DUCK_ID);
+    private final VolumeShaper.Operation PLAY_CREATE_IF_NEEDED =
+            new VolumeShaper.Operation.Builder(VolumeShaper.Operation.PLAY)
+                    .createIfNeeded()
+                    .build();
+    private final VolumeShaper.Operation TERMINATE =
+            new VolumeShaper.Operation.Builder()
+                    .terminate()
+                    .build();
+
+    private final ArrayList<PlayMonitorClient> mClients = new ArrayList<PlayMonitorClient>();
     // a public client is one that needs an anonymized version of the playback configurations, we
     // keep track of whether there is at least one to know when we need to create the list of
     // playback configurations that do not contain uid/pid/package name information.
     private boolean mHasPublicClients = false;
 
     private final Object mPlayerLock = new Object();
-    private HashMap<Integer, AudioPlaybackConfiguration> mPlayers =
+    private final HashMap<Integer, AudioPlaybackConfiguration> mPlayers =
             new HashMap<Integer, AudioPlaybackConfiguration>();
 
     PlaybackActivityMonitor() {
@@ -130,12 +152,10 @@
         synchronized(mPlayerLock) {
             final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
             if (checkConfigurationCaller(piid, apc, binderUid)) {
+                apc.getPlayerProxy().applyVolumeShaper(
+                        DUCK_ID,
+                        TERMINATE);
                 mPlayers.remove(new Integer(piid));
-                final VolumeShaper vs = mDuckVolumeShapers.get(new Integer(piid));
-                if (vs != null) {
-                    vs.release();
-                    mDuckVolumeShapers.remove(new Integer(piid));
-                }
             } else {
                 Log.e(TAG, "Error releasing player " + piid);
             }
@@ -252,20 +272,6 @@
     private final ArrayList<Integer> mDuckedPlayers = new ArrayList<Integer>();
     private final ArrayList<Integer> mMutedPlayers = new ArrayList<Integer>();
 
-    private final VolumeShaper.Configuration DUCK_VSHAPE =
-            new VolumeShaper.Configuration.Builder()
-                .setId(VOLUME_SHAPER_SYSTEM_DUCK_ID)
-                .setCurve(new float[] { 0.f, 1.f } /* times */,
-                    new float[] { 1.f, 0.2f } /* volumes */)
-                .setDurationMs(MediaFocusControl.getFocusRampTimeMs(
-                    AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
-                    new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION)
-                            .build()))
-                .build();
-
-    private final HashMap<Integer, VolumeShaper> mDuckVolumeShapers =
-            new HashMap<Integer, VolumeShaper>();
-
     @Override
     public boolean duckPlayers(FocusRequester winner, FocusRequester loser) {
         if (DEBUG) {
@@ -302,17 +308,9 @@
                     } else {
                         try {
                             if (DEBUG) { Log.v(TAG, "ducking player " + piid); }
-                            final VolumeShaper ducker;
-                            if (mDuckVolumeShapers.containsKey(new Integer(piid))) {
-                                ducker = mDuckVolumeShapers.get(new Integer(piid));
-                            } else {
-                                ducker = new VolumeShaper(
-                                        DUCK_VSHAPE,
-                                        apc.getPlayerProxy(),
-                                        true /* keepReference */);
-                                mDuckVolumeShapers.put(new Integer(piid), ducker);
-                            }
-                            ducker.apply(VolumeShaper.Operation.PLAY); // duck
+                            apc.getPlayerProxy().applyVolumeShaper(
+                                    DUCK_VSHAPE,
+                                    PLAY_CREATE_IF_NEEDED);
                             mDuckedPlayers.add(piid);
                         } catch (Exception e) {
                             Log.e(TAG, "Error ducking player " + piid, e);
@@ -341,10 +339,9 @@
                     try {
                         if (DEBUG) { Log.v(TAG, "unducking player" + piid); }
                         mDuckedPlayers.remove(new Integer(piid));
-                        if (mDuckVolumeShapers.containsKey(new Integer(piid))) {
-                            final VolumeShaper ducker = mDuckVolumeShapers.get(new Integer(piid));
-                            ducker.apply(VolumeShaper.Operation.REVERSE); // unduck
-                        }
+                        apc.getPlayerProxy().applyVolumeShaper(
+                                DUCK_ID,
+                                VolumeShaper.Operation.REVERSE);
                     } catch (Exception e) {
                         Log.e(TAG, "Error unducking player " + piid, e);
                     }