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

Commit bbf30df1 authored by Jean-Michel Trivi's avatar Jean-Michel Trivi Committed by Android (Google) Code Review
Browse files

Merge "Audio focus: test APIs for focus injection" into sc-dev

parents 5d4effc2 28602096
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -1355,9 +1355,12 @@ package android.media {
  }

  public class AudioManager {
    method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int abandonAudioFocusForTest(@NonNull android.media.AudioFocusRequest, @NonNull String);
    method @Nullable public static android.media.AudioDeviceInfo getDeviceInfoFromType(int);
    method @IntRange(from=0) @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public long getFadeOutDurationOnFocusLossMillis(@NonNull android.media.AudioAttributes);
    method public boolean hasRegisteredDynamicPolicy();
    method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.QUERY_AUDIO_STATE}) public boolean isFullVolumeDevice();
    method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int requestAudioFocusForTest(@NonNull android.media.AudioFocusRequest, @NonNull String, int, int);
  }

  public static final class AudioRecord.MetricsConstants {
+78 −0
Original line number Diff line number Diff line
@@ -3811,6 +3811,14 @@ public class AudioManager {
     */
    @SystemApi
    public static final int AUDIOFOCUS_FLAG_LOCK     = 0x1 << 2;

    /**
     * @hide
     * flag set on test API calls,
     * see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)},
     * note that it isn't used in conjunction with other flags, it is passed as the single
     * value for flags */
    public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3;
    /** @hide */
    public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK
            | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS;
@@ -3970,6 +3978,76 @@ public class AudioManager {
        return requestAudioFocus(afr, ap);
    }

    /**
     * @hide
     * Test API to request audio focus for an arbitrary client operating from a (fake) given UID.
     * Used to simulate conditions of the test, not the behavior of the focus requester under test.
     * @param afr the parameters of the request
     * @param clientFakeId the identifier of the AudioManager the client would be requesting from
     * @param clientFakeUid the UID of the client, here an arbitrary int,
     *                      doesn't have to be a real UID
     * @param clientTargetSdk the target SDK used by the client
     * @return return code indicating status of the request
     */
    @TestApi
    @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
    public @FocusRequestResult int requestAudioFocusForTest(@NonNull AudioFocusRequest afr,
            @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk) {
        Objects.requireNonNull(afr);
        Objects.requireNonNull(clientFakeId);
        try {
            return getService().requestAudioFocusForTest(afr.getAudioAttributes(),
                    afr.getFocusGain(),
                    mICallBack,
                    mAudioFocusDispatcher,
                    clientFakeId, "com.android.test.fakeclient", clientFakeUid, clientTargetSdk);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * @hide
     * Test API to abandon audio focus for an arbitrary client.
     * Used to simulate conditions of the test, not the behavior of the focus requester under test.
     * @param afr the parameters used for the request
     * @param clientFakeId clientFakeId the identifier of the AudioManager from which the client
     *      would be requesting
     * @return return code indicating status of the request
     */
    @TestApi
    @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
    public @FocusRequestResult int abandonAudioFocusForTest(@NonNull AudioFocusRequest afr,
            @NonNull String clientFakeId) {
        Objects.requireNonNull(afr);
        Objects.requireNonNull(clientFakeId);
        try {
            return getService().abandonAudioFocusForTest(mAudioFocusDispatcher,
                    clientFakeId, afr.getAudioAttributes(), "com.android.test.fakeclient");
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * @hide
     * Return the duration of the fade out applied when a player of the given AudioAttributes
     * is losing audio focus
     * @param aa the AudioAttributes of the player losing focus with {@link #AUDIOFOCUS_LOSS}
     * @return a duration in ms, 0 indicates no fade out is applied
     */
    @TestApi
    @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
    public @IntRange(from = 0) long getFadeOutDurationOnFocusLossMillis(@NonNull AudioAttributes aa)
    {
        Objects.requireNonNull(aa);
        try {
            return getService().getFadeOutDurationOnFocusLossMillis(aa);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * @hide
     * Request or lock audio focus.
+9 −0
Original line number Diff line number Diff line
@@ -374,4 +374,13 @@ interface IAudioService {
    long getAdditionalOutputDeviceDelay(in AudioDeviceAttributes device);

    long getMaxAdditionalOutputDeviceDelay(in AudioDeviceAttributes device);

    int requestAudioFocusForTest(in AudioAttributes aa, int durationHint, IBinder cb,
            in IAudioFocusDispatcher fd, in String clientId, in String callingPackageName,
            int uid, int sdk);

    int abandonAudioFocusForTest(in IAudioFocusDispatcher fd, in String clientId,
            in AudioAttributes aa, in String callingPackageName);

    long getFadeOutDurationOnFocusLossMillis(in AudioAttributes aa);
}
+46 −1
Original line number Diff line number Diff line
@@ -7907,7 +7907,24 @@ public class AudioService extends IAudioService.Stub
        mmi.record();
        return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
                clientId, callingPackageName, flags, sdk,
                forceFocusDuckingForAccessibility(aa, durationHint, uid));
                forceFocusDuckingForAccessibility(aa, durationHint, uid), -1 /*testUid, ignored*/);
    }

    /** see {@link AudioManager#requestAudioFocusForTest(AudioFocusRequest, String, int, int)} */
    public int requestAudioFocusForTest(AudioAttributes aa, int durationHint, IBinder cb,
            IAudioFocusDispatcher fd, String clientId, String callingPackageName,
            int fakeUid, int sdk) {
        if (!enforceQueryAudioStateForTest("focus request")) {
            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
        }
        if (callingPackageName == null || clientId == null || aa == null) {
            final String reason = "Invalid null parameter to request audio focus";
            Log.e(TAG, reason);
            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
        }
        return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
                clientId, callingPackageName, AudioManager.AUDIOFOCUS_FLAG_TEST,
                sdk, false /*forceDuck*/, fakeUid);
    }

    public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa,
@@ -7927,6 +7944,15 @@ public class AudioService extends IAudioService.Stub
        return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa, callingPackageName);
    }

    /** see {@link AudioManager#abandonAudioFocusForTest(AudioFocusRequest, String)} */
    public int abandonAudioFocusForTest(IAudioFocusDispatcher fd, String clientId,
            AudioAttributes aa, String callingPackageName) {
        if (!enforceQueryAudioStateForTest("focus abandon")) {
            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
        }
        return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa, callingPackageName);
    }

    public void unregisterAudioFocusClient(String clientId) {
        new MediaMetrics.Item(mMetricsId + "focus")
                .set(MediaMetrics.Property.CLIENT_NAME, clientId)
@@ -7949,6 +7975,25 @@ public class AudioService extends IAudioService.Stub
        return mMediaFocusControl.hasAudioFocusUsers();
    }

    /** see {@link AudioManager#getFadeOutDurationOnFocusLossMillis(AudioAttributes)} */
    public long getFadeOutDurationOnFocusLossMillis(AudioAttributes aa) {
        if (!enforceQueryAudioStateForTest("fade out duration")) {
            return 0;
        }
        return mMediaFocusControl.getFadeOutDurationOnFocusLossMillis(aa);
    }

    private boolean enforceQueryAudioStateForTest(String mssg) {
        if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
                Manifest.permission.QUERY_AUDIO_STATE)) {
            final String reason = "Doesn't have QUERY_AUDIO_STATE permission for "
                    + mssg + " test API";
            Log.e(TAG, reason, new Exception());
            return false;
        }
        return true;
    }

    //==========================================================================================
    private boolean readCameraSoundForced() {
        return SystemProperties.getBoolean("audio.camerasound.force", false) ||
+10 −0
Original line number Diff line number Diff line
@@ -97,6 +97,16 @@ public final class FadeOutManager {
        return true;
    }

    static long getFadeOutDurationOnFocusLossMillis(AudioAttributes aa) {
        if (ArrayUtils.contains(UNFADEABLE_CONTENT_TYPES, aa.getContentType())) {
            return 0;
        }
        if (!ArrayUtils.contains(FADEABLE_USAGES, aa.getUsage())) {
            return 0;
        }
        return FADE_OUT_DURATION_MS;
    }

    /**
     * Map of uid (key) to faded out apps (value)
     */
Loading