UID mixing rule support both RECORDERS and PLAYERS mix type

Export API in AudioMixingRule#Builder to allow application specify the mix type when using UID mixing rule.

Bug: 169964607
Test: atest com.google.android.gts.audio.AudioHostTest, manual testing
Change-Id: Icf7c83f280aeec7b11aa3bc43fb31657c863e7fd
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index 1f07705..cb47ba2 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -291,7 +291,6 @@
         final int match_rule = rule & ~RULE_EXCLUSION_MASK;
         switch (match_rule) {
             case RULE_MATCH_ATTRIBUTE_USAGE:
-            case RULE_MATCH_UID:
             case RULE_MATCH_USERID:
                 return true;
             default:
@@ -299,6 +298,16 @@
         }
     }
 
+    private static boolean isRecorderRule(int rule) {
+        final int match_rule = rule & ~RULE_EXCLUSION_MASK;
+        switch (match_rule) {
+            case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     private static boolean isAudioAttributeRule(int match_rule) {
         switch(match_rule) {
             case RULE_MATCH_ATTRIBUTE_USAGE:
@@ -460,6 +469,23 @@
         }
 
         /**
+         * Set target mix type of the mixing rule.
+         *
+         * <p>Note: If the mix type was not specified, it will be decided automatically by mixing
+         * rule. For {@link #RULE_MATCH_UID}, the default type is {@link AudioMix#MIX_TYPE_PLAYERS}.
+         *
+         * @param mixType {@link AudioMix#MIX_TYPE_PLAYERS} or {@link AudioMix#MIX_TYPE_RECORDERS}
+         * @return the same Builder instance.
+         *
+         * @hide
+         */
+        public @NonNull Builder setTargetMixType(int mixType) {
+            mTargetMixType = mixType;
+            Log.i("AudioMixingRule", "Builder setTargetMixType " + mixType);
+            return this;
+        }
+
+        /**
          * Add or exclude a rule for the selection of which streams are mixed together.
          * Does error checking on the parameters.
          * @param rule
@@ -515,11 +541,15 @@
             if (mTargetMixType == AudioMix.MIX_TYPE_INVALID) {
                 if (isPlayerRule(rule)) {
                     mTargetMixType = AudioMix.MIX_TYPE_PLAYERS;
-                } else {
+                } else if (isRecorderRule(rule)) {
                     mTargetMixType = AudioMix.MIX_TYPE_RECORDERS;
+                } else {
+                    // For rules which are not player or recorder specific (e.g. RULE_MATCH_UID),
+                    // the default mix type is MIX_TYPE_PLAYERS.
+                    mTargetMixType = AudioMix.MIX_TYPE_PLAYERS;
                 }
-            } else if (((mTargetMixType == AudioMix.MIX_TYPE_PLAYERS) && !isPlayerRule(rule))
-                    || ((mTargetMixType == AudioMix.MIX_TYPE_RECORDERS) && isPlayerRule(rule)))
+            } else if ((isPlayerRule(rule) && (mTargetMixType != AudioMix.MIX_TYPE_PLAYERS))
+                    || (isRecorderRule(rule)) && (mTargetMixType != AudioMix.MIX_TYPE_RECORDERS))
             {
                 throw new IllegalArgumentException("Incompatible rule for mix");
             }
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index ede68bd..346edc3 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -100,6 +100,8 @@
             dest.writeBoolean(mix.getRule().allowPrivilegedMediaPlaybackCapture());
             // write voice communication capture allowed flag
             dest.writeBoolean(mix.getRule().voiceCommunicationCaptureAllowed());
+            // write specified mix type
+            dest.writeInt(mix.getRule().getTargetMixType());
             // write mix rules
             final ArrayList<AudioMixMatchCriterion> criteria = mix.getRule().getCriteria();
             dest.writeInt(criteria.size());
@@ -134,6 +136,8 @@
             ruleBuilder.allowPrivilegedPlaybackCapture(in.readBoolean());
             // read voice capture allowed flag
             ruleBuilder.voiceCommunicationCaptureAllowed(in.readBoolean());
+            // read specified mix type
+            ruleBuilder.setTargetMixType(in.readInt());
             // read mix rules
             int nbRules = in.readInt();
             for (int j = 0 ; j < nbRules ; j++) {
@@ -176,6 +180,8 @@
             textDump += "  allow voice communication capture="
                     + mix.getRule().voiceCommunicationCaptureAllowed() + "\n";
             // write mix rules
+            textDump += "  specified mix type="
+                    + mix.getRule().getTargetMixType() + "\n";
             final ArrayList<AudioMixMatchCriterion> criteria = mix.getRule().getCriteria();
             for (AudioMixMatchCriterion criterion : criteria) {
                 switch(criterion.mRule) {