Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7919c2ac authored by Kevin Rocard's avatar Kevin Rocard
Browse files

Add application wide capture policy



Apps were previously forced to set their allowed capture policy from
either their manifest which is not flexible or from each track which is
a very fine grain but difficult when using libraries like exoplayer.

Thus add an application level policy set with AudioManager.

Test: atest android.media.cts.AudioPlaybackCaptureTest#testCaptureMediaUsage
Bug: 111453086
Change-Id: Id360f1c3f3157c60694c039e51ff16e71d8f93cd
Signed-off-by: default avatarKevin Rocard <krocard@google.com>
parent a3a4bbba
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -23270,6 +23270,7 @@ package android.media {
    method @Deprecated public boolean registerRemoteController(android.media.RemoteController);
    method @Deprecated public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int);
    method public int requestAudioFocus(@NonNull android.media.AudioFocusRequest);
    method public void setAllowedCapturePolicy(int);
    method @Deprecated public void setBluetoothA2dpOn(boolean);
    method public void setBluetoothScoOn(boolean);
    method public void setMicrophoneMute(boolean);
+6 −0
Original line number Diff line number Diff line
@@ -2229,6 +2229,11 @@ android_media_AudioSystem_isHapticPlaybackSupported(JNIEnv *env, jobject thiz)
    return AudioSystem::isHapticPlaybackSupported();
}

static jint
android_media_AudioSystem_setAllowedCapturePolicy(JNIEnv *env, jobject thiz, jint uid, jint flags) {
    return AudioSystem::setAllowedCapturePolicy(uid, flags);
}

// ----------------------------------------------------------------------------

static const JNINativeMethod gMethods[] = {
@@ -2304,6 +2309,7 @@ static const JNINativeMethod gMethods[] = {
    {"isHapticPlaybackSupported", "()Z", (void *)android_media_AudioSystem_isHapticPlaybackSupported},
    {"getHwOffloadEncodingFormatsSupportedForA2DP", "(Ljava/util/ArrayList;)I",
                    (void*)android_media_AudioSystem_getHwOffloadEncodingFormatsSupportedForA2DP},
    {"setAllowedCapturePolicy", "(II)I", (void *)android_media_AudioSystem_setAllowedCapturePolicy},
};

static const JNINativeMethod gEventHandlerMethods[] = {
+19 −14
Original line number Diff line number Diff line
@@ -709,20 +709,7 @@ public final class AudioAttributes implements Parcelable {
         * @throws IllegalArgumentException if the argument is not a valid value.
         */
        public @NonNull Builder setAllowedCapturePolicy(@CapturePolicy int capturePolicy) {
            switch (capturePolicy) {
                case ALLOW_CAPTURE_BY_NONE:
                    mFlags |= FLAG_NO_MEDIA_PROJECTION | FLAG_NO_SYSTEM_CAPTURE;
                    break;
                case ALLOW_CAPTURE_BY_SYSTEM:
                    mFlags |= FLAG_NO_MEDIA_PROJECTION;
                    mFlags &= ~FLAG_NO_SYSTEM_CAPTURE;
                    break;
                case ALLOW_CAPTURE_BY_ALL:
                    mFlags &= ~FLAG_NO_SYSTEM_CAPTURE & ~FLAG_NO_MEDIA_PROJECTION;
                    break;
                default:
                    throw new IllegalArgumentException("Unknown allow playback capture policy");
            }
            mFlags = capturePolicyToFlags(capturePolicy, mFlags);
            return this;
        }

@@ -1207,6 +1194,24 @@ public final class AudioAttributes implements Parcelable {
        }
    }

    static int capturePolicyToFlags(@CapturePolicy int capturePolicy, int flags) {
        switch (capturePolicy) {
            case ALLOW_CAPTURE_BY_NONE:
                flags |= FLAG_NO_MEDIA_PROJECTION | FLAG_NO_SYSTEM_CAPTURE;
                break;
            case ALLOW_CAPTURE_BY_SYSTEM:
                flags |= FLAG_NO_MEDIA_PROJECTION;
                flags &= ~FLAG_NO_SYSTEM_CAPTURE;
                break;
            case ALLOW_CAPTURE_BY_ALL:
                flags &= ~FLAG_NO_SYSTEM_CAPTURE & ~FLAG_NO_MEDIA_PROJECTION;
                break;
            default:
                throw new IllegalArgumentException("Unknown allow playback capture policy");
        }
        return flags;
    }

    /** @hide */
    @IntDef({
        USAGE_UNKNOWN,
+24 −0
Original line number Diff line number Diff line
@@ -1478,6 +1478,30 @@ public class AudioManager {
        }
     }

    /**
     * Specifying if this audio may or may not be captured by other apps or the system.
     *
     * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}.
     *
     * Note that each audio track can also set its policy, in which case the most
     * restrictive policy is always applied.
     *
     * @param capturePolicy one of
     *     {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
     *     {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
     *     {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
     * @throws IllegalArgumentException if the argument is not a valid value.
     */
    public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) {
        int flags = AudioAttributes.capturePolicyToFlags(capturePolicy, 0x0);
        // TODO: got trough AudioService and save a cache to restore in case of AP crash
        // TODO: also pass the package in case multiple packages have the same UID
        int result = AudioSystem.setAllowedCapturePolicy(Process.myUid(), flags);
        if (result != AudioSystem.AUDIO_STATUS_OK) {
            Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
        }
    }

    //====================================================================
    // Offload query
    /**
+9 −5
Original line number Diff line number Diff line
@@ -29,13 +29,17 @@ import com.android.internal.util.Preconditions;
 * Configuration for capturing audio played by other apps.
 *
 * Only the following audio can be captured:
 *  - usage MUST be UNKNOWN or GAME or MEDIA. All other usages CAN NOT be capturable.
 *  - audio attributes MUST NOT have the FLAG_NO_CAPTURE
 *  - usage MUST be {@link AudioAttributes#USAGE_UNKNOWN} or {@link AudioAttributes#USAGE_GAME}
 *    or {@link AudioAttributes#USAGE_MEDIA}. All other usages CAN NOT be captured.
 *  - audio attributes MUST have its ${@link AudioAttributes.Builder#setAllowedCapturePolicy}
 *    to {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}.
 *  - played by apps that MUST be in the same user profile as the capturing app
 *    (eg work profile can not capture user profile apps and vice-versa).
 *  - played by apps that MUST NOT have in their manifest.xml the application
 *    attribute android:allowAudioPlaybackCapture="false"
 *  - played by apps that MUST have a targetSdkVersion higher or equal to 29 (Q).
 *  - played by apps for which the attribute allowAudioPlaybackCapture in their manifest
 *    MUST either be:
 *      * set to "true"
 *      * not set, and their targetSdkVersion MUST be equal or higher to
 *        {@link android.os.Build.VERSION_CODES#Q}.
 *
 * <p>An example for creating a capture configuration for capturing all media playback:
 *
Loading