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

Commit b817d2ac authored by Pranav Madapurmath's avatar Pranav Madapurmath Committed by Android (Google) Code Review
Browse files

Merge "Resolve Ringer#getUri Telecom usages" into main

parents 424be624 0b0ce23f
Loading
Loading
Loading
Loading
+19 −10
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ import android.os.HandlerThread;
import android.os.Message;
import android.telecom.Log;
import android.telecom.Logging.Session;
import android.util.Pair;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.Preconditions;
@@ -81,16 +83,17 @@ public class AsyncRingtonePlayer {
     * If {@link VolumeShaper.Configuration} is specified, it is applied to the ringtone to change
     * the volume of the ringtone as it plays.
     *
     * @param ringtoneSupplier The {@link Ringtone} factory.
     * @param ringtoneInfoSupplier The {@link Ringtone} factory.
     * @param ringtoneConsumer The {@link Ringtone} post-creation callback (to start the vibration).
     * @param isHfpDeviceConnected True if there is a HFP BT device connected, false otherwise.
     */
    public void play(@NonNull Supplier<Ringtone> ringtoneSupplier,
            BiConsumer<Ringtone, Boolean> ringtoneConsumer,  boolean isHfpDeviceConnected) {
    public void play(@NonNull Supplier<Pair<Uri, Ringtone>> ringtoneInfoSupplier,
            BiConsumer<Pair<Uri, Ringtone>, Boolean> ringtoneConsumer,
            boolean isHfpDeviceConnected) {
        Log.d(this, "Posting play.");
        mIsPlaying = true;
        SomeArgs args = SomeArgs.obtain();
        args.arg1 = ringtoneSupplier;
        args.arg1 = ringtoneInfoSupplier;
        args.arg2 = ringtoneConsumer;
        args.arg3 = Log.createSubsession();
        args.arg4 = prepareRingingReadyLatch(isHfpDeviceConnected);
@@ -209,8 +212,10 @@ public class AsyncRingtonePlayer {
     * Starts the actual playback of the ringtone. Executes on ringtone-thread.
     */
    private void handlePlay(SomeArgs args) {
        Supplier<Ringtone> ringtoneSupplier = (Supplier<Ringtone>) args.arg1;
        BiConsumer<Ringtone, Boolean> ringtoneConsumer = (BiConsumer<Ringtone, Boolean>) args.arg2;
        Supplier<Pair<Uri, Ringtone>> ringtoneInfoSupplier =
                (Supplier<Pair<Uri, Ringtone>>) args.arg1;
        BiConsumer<Pair<Uri, Ringtone>, Boolean> ringtoneConsumer =
                (BiConsumer<Pair<Uri, Ringtone>, Boolean>) args.arg2;
        Session session = (Session) args.arg3;
        CountDownLatch ringingReadyLatch = (CountDownLatch) args.arg4;
        args.recycle();
@@ -226,6 +231,7 @@ public class AsyncRingtonePlayer {
                return;
            }
            Ringtone ringtone = null;
            Uri ringtoneUri = null;
            boolean hasStopped = false;
            try {
                try {
@@ -236,7 +242,11 @@ public class AsyncRingtonePlayer {
                } catch (InterruptedException e) {
                    Log.w(this, "handlePlay: latch exception: " + e);
                }
                ringtone = ringtoneSupplier.get();
                if (ringtoneInfoSupplier != null && ringtoneInfoSupplier.get() != null) {
                    ringtoneUri = ringtoneInfoSupplier.get().first;
                    ringtone = ringtoneInfoSupplier.get().second;
                }

                // Ringtone supply can be slow or stop command could have been issued while waiting
                // for BT to move to CONNECTED state. Re-check for stop event.
                if (mHandler.hasMessages(EVENT_STOP)) {
@@ -253,8 +263,7 @@ public class AsyncRingtonePlayer {
                    Log.w(this, "No ringtone was found bail out from playing.");
                    return;
                }
                Uri uri = mRingtone.getUri();
                String uriString = (uri != null ? uri.toSafeString() : "");
                String uriString = ringtoneUri != null ? ringtoneUri.toSafeString() : "";
                Log.i(this, "handlePlay: Play ringtone. Uri: " + uriString);
                mRingtone.setLooping(true);
                if (mRingtone.isPlaying()) {
@@ -265,7 +274,7 @@ public class AsyncRingtonePlayer {
                Log.i(this, "Play ringtone, looping.");
            } finally {
                removePendingRingingReadyLatch(ringingReadyLatch);
                ringtoneConsumer.accept(ringtone, hasStopped);
                ringtoneConsumer.accept(new Pair(ringtoneUri, ringtone), hasStopped);
            }
        } finally {
            Log.cancelSubsession(session);
+21 −12
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import android.os.vibrator.persistence.ParsedVibration;
import android.os.vibrator.persistence.VibrationXmlParser;
import android.telecom.Log;
import android.telecom.TelecomManager;
import android.util.Pair;
import android.view.accessibility.AccessibilityManager;

import com.android.internal.annotations.VisibleForTesting;
@@ -413,18 +414,18 @@ public class Ringer {
                        isVibratorEnabled, mIsHapticPlaybackSupportedByDevice);
            }
            // Defer ringtone creation to the async player thread.
            Supplier<Ringtone> ringtoneSupplier;
            Supplier<Pair<Uri, Ringtone>> ringtoneInfoSupplier;
            final boolean finalHapticChannelsMuted = hapticChannelsMuted;
            if (isHapticOnly) {
                if (hapticChannelsMuted) {
                    Log.i(this,
                            "want haptic only ringtone but haptics are muted, skip ringtone play");
                    ringtoneSupplier = null;
                    ringtoneInfoSupplier = null;
                } else {
                    ringtoneSupplier = mRingtoneFactory::getHapticOnlyRingtone;
                    ringtoneInfoSupplier = mRingtoneFactory::getHapticOnlyRingtone;
                }
            } else {
                ringtoneSupplier = () -> mRingtoneFactory.getRingtone(
                ringtoneInfoSupplier = () -> mRingtoneFactory.getRingtone(
                        foregroundCall, mVolumeShaperConfig, finalHapticChannelsMuted);
            }

@@ -447,9 +448,18 @@ public class Ringer {
            // if the loaded ringtone is null. However if a stop event arrives before the ringtone
            // creation finishes, then this consumer can be skipped.
            final boolean finalUseCustomVibrationEffect = useCustomVibrationEffect;
            BiConsumer<Ringtone, Boolean> afterRingtoneLogic =
                    (Ringtone ringtone, Boolean stopped) -> {
            BiConsumer<Pair<Uri, Ringtone>, Boolean> afterRingtoneLogic =
                    (Pair<Uri, Ringtone> ringtoneInfo, Boolean stopped) -> {
                try {
                    Uri ringtoneUri = null;
                    Ringtone ringtone = null;
                    if (ringtoneInfo != null) {
                        ringtoneUri = ringtoneInfo.first;
                        ringtone = ringtoneInfo.second;
                    } else {
                        Log.w(this, "The ringtone could not be loaded.");
                    }

                    if (stopped.booleanValue() || !vibratorReserved) {
                        // don't start vibration if the ringing is already abandoned, or the
                        // vibrator wasn't reserved. This still triggers the mBlockOnRingingFuture.
@@ -460,7 +470,7 @@ public class Ringer {
                        if (DEBUG_RINGER) {
                            Log.d(this, "Using ringtone defined vibration effect.");
                        }
                        vibrationEffect = getVibrationEffectForRingtone(ringtone);
                        vibrationEffect = getVibrationEffectForRingtone(ringtoneUri);
                    } else {
                        vibrationEffect = mDefaultVibrationEffect;
                    }
@@ -477,10 +487,10 @@ public class Ringer {
                }
            };
            deferBlockOnRingingFuture = true;  // Run in vibrationLogic.
            if (ringtoneSupplier != null) {
                mRingtonePlayer.play(ringtoneSupplier, afterRingtoneLogic, isHfpDeviceAttached);
            if (ringtoneInfoSupplier != null) {
                mRingtonePlayer.play(ringtoneInfoSupplier, afterRingtoneLogic, isHfpDeviceAttached);
            } else {
                afterRingtoneLogic.accept(/* ringtone= */ null, /* stopped= */ false);
                afterRingtoneLogic.accept(/* ringtoneUri, ringtone = */ null, /* stopped= */ false);
            }

            // shouldAcquireAudioFocus is meant to be true, but that check is deferred to here
@@ -542,8 +552,7 @@ public class Ringer {
        }
    }

    private VibrationEffect getVibrationEffectForRingtone(@NonNull Ringtone ringtone) {
        Uri ringtoneUri = ringtone.getUri();
    private VibrationEffect getVibrationEffectForRingtone(Uri ringtoneUri) {
        if (ringtoneUri == null) {
            return mDefaultVibrationEffect;
        }
+9 −18
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.text.TextUtils;

import com.android.internal.annotations.VisibleForTesting;
import android.telecom.CallerInfo;
import android.util.Pair;

import java.util.List;

@@ -53,18 +54,7 @@ public class RingtoneFactory {
        mCallsManager = callsManager;
    }

    /**
     * Determines if a ringtone has haptic channels.
     * @param ringtone The ringtone URI.
     * @return {@code true} if there is a haptic channel, {@code false} otherwise.
     */
    public boolean hasHapticChannels(Ringtone ringtone) {
        boolean hasHapticChannels = RingtoneManager.hasHapticChannels(ringtone.getUri());
        Log.i(this, "hasHapticChannels %s -> %b", ringtone.getUri(), hasHapticChannels);
        return hasHapticChannels;
    }

    public Ringtone getRingtone(Call incomingCall,
    public Pair<Uri, Ringtone> getRingtone(Call incomingCall,
            @Nullable VolumeShaper.Configuration volumeShaperConfig, boolean hapticChannelsMuted) {
        // Initializing ringtones on the main thread can deadlock
        ThreadUtil.checkNotOnMainThread();
@@ -106,18 +96,19 @@ public class RingtoneFactory {
                }
            }

            if (defaultRingtoneUri == null) {
            ringtoneUri = defaultRingtoneUri;
            if (ringtoneUri == null) {
                return null;
            }

            try {
                ringtone = RingtoneManager.getRingtone(
                        contextToUse, defaultRingtoneUri, volumeShaperConfig, audioAttrs);
                        contextToUse, ringtoneUri, volumeShaperConfig, audioAttrs);
            } catch (Exception e) {
                Log.e(this, e, "getRingtone: exception while getting ringtone.");
            }
        }
        return ringtone;
        return new Pair(ringtoneUri, ringtone);
    }

    private AudioAttributes getDefaultRingtoneAudioAttributes(boolean hapticChannelsMuted) {
@@ -130,7 +121,7 @@ public class RingtoneFactory {

    /** Returns a ringtone to be used when ringer is not audible for the incoming call. */
    @Nullable
    public Ringtone getHapticOnlyRingtone() {
    public Pair<Uri, Ringtone> getHapticOnlyRingtone() {
        // Initializing ringtones on the main thread can deadlock
        ThreadUtil.checkNotOnMainThread();
        Uri ringtoneUri = Uri.parse("file://" + mContext.getString(
@@ -143,7 +134,7 @@ public class RingtoneFactory {
            // Make sure the sound is muted.
            ringtone.setVolume(0);
        }
        return ringtone;
        return new Pair(ringtoneUri, ringtone);
    }

    private Context getWorkProfileContextForUser(UserHandle userHandle) {
+16 −13
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.util.Pair;

import androidx.test.filters.SmallTest;

@@ -83,6 +84,7 @@ import org.mockito.Spy;

import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;

@RunWith(JUnit4.class)
public class RingerTest extends TelecomTestCase {
@@ -144,7 +146,6 @@ public class RingerTest extends TelecomTestCase {
        mockNotificationManager =mContext.getSystemService(NotificationManager.class);
        when(mockTonePlayer.startTone()).thenReturn(true);
        when(mockNotificationManager.matchesCallFilter(any(Uri.class))).thenReturn(true);
        when(mockRingtoneFactory.hasHapticChannels(any(Ringtone.class))).thenReturn(false);
        when(mockCall1.getState()).thenReturn(CallState.RINGING);
        when(mockCall2.getState()).thenReturn(CallState.RINGING);
        when(mockCall1.getAssociatedUser()).thenReturn(PA_HANDLE.getUserHandle());
@@ -426,7 +427,7 @@ public class RingerTest extends TelecomTestCase {
        // Pretend we're using audio coupled haptics.
        setIsUsingHaptics(mockRingtone, true);
        assertTrue(startRingingAndWaitForAsync(mockCall1, false));
        verify(mockRingtoneFactory, times(1))
        verify(mockRingtoneFactory, atLeastOnce())
            .getRingtone(any(Call.class), nullable(VolumeShaper.Configuration.class), anyBoolean());
        verifyNoMoreInteractions(mockRingtoneFactory);
        verify(mockTonePlayer).stopTone();
@@ -468,14 +469,14 @@ public class RingerTest extends TelecomTestCase {

        mRingerUnderTest.startCallWaiting(mockCall1);
        when(mockRingtoneFactory.getRingtone(any(Call.class), eq(null), anyBoolean()))
            .thenReturn(mockRingtone);
            .thenReturn(new Pair(FAKE_RINGTONE_URI, mockRingtone));
        when(mockAudioManager.getRingerMode()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
        when(mockAudioManager.getStreamVolume(AudioManager.STREAM_RING)).thenReturn(0);
        enableVibrationWhenRinging();
        assertFalse(startRingingAndWaitForAsync(mockCall2, false));
        verify(mockTonePlayer).stopTone();
        // Try to play a silent haptics ringtone
        verify(mockRingtoneFactory, times(1)).getHapticOnlyRingtone();
        verify(mockRingtoneFactory, atLeastOnce()).getHapticOnlyRingtone();
        verifyNoMoreInteractions(mockRingtoneFactory);
        verify(mockRingtone).play();

@@ -514,7 +515,7 @@ public class RingerTest extends TelecomTestCase {
        enableVibrationWhenRinging();
        assertFalse(startRingingAndWaitForAsync(mockCall2, false));

        verify(mockRingtoneFactory, times(1)).getHapticOnlyRingtone();
        verify(mockRingtoneFactory, atLeastOnce()).getHapticOnlyRingtone();
        verifyNoMoreInteractions(mockRingtoneFactory);
        verify(mockTonePlayer).stopTone();
        // Try to play a silent haptics ringtone
@@ -534,7 +535,7 @@ public class RingerTest extends TelecomTestCase {
        enableVibrationWhenRinging();
        assertTrue(startRingingAndWaitForAsync(mockCall2, false));
        verify(mockTonePlayer).stopTone();
        verify(mockRingtoneFactory, times(1))
        verify(mockRingtoneFactory, atLeastOnce())
            .getRingtone(any(Call.class), isNull(), anyBoolean());
        verifyNoMoreInteractions(mockRingtoneFactory);
        verify(mockRingtone).play();
@@ -551,7 +552,7 @@ public class RingerTest extends TelecomTestCase {
        ensureRingerIsAudible();
        enableVibrationOnlyWhenNotRinging();
        assertTrue(startRingingAndWaitForAsync(mockCall2, false));
        verify(mockRingtoneFactory, times(1))
        verify(mockRingtoneFactory, atLeastOnce())
            .getRingtone(any(Call.class), nullable(VolumeShaper.Configuration.class), anyBoolean());
        verifyNoMoreInteractions(mockRingtoneFactory);
        verify(mockTonePlayer).stopTone();
@@ -570,7 +571,7 @@ public class RingerTest extends TelecomTestCase {
        enableRampingRinger();
        enableVibrationWhenRinging();
        assertTrue(startRingingAndWaitForAsync(mockCall2, false));
        verify(mockRingtoneFactory, times(1))
        verify(mockRingtoneFactory, atLeastOnce())
            .getRingtone(any(Call.class), nullable(VolumeShaper.Configuration.class), anyBoolean());
        verifyNoMoreInteractions(mockRingtoneFactory);
        verify(mockTonePlayer).stopTone();
@@ -602,7 +603,7 @@ public class RingerTest extends TelecomTestCase {
        when(mockAudioManager.getStreamVolume(AudioManager.STREAM_RING)).thenReturn(100);
        enableVibrationWhenRinging();
        assertTrue(startRingingAndWaitForAsync(mockCall2, true));
        verify(mockRingtoneFactory, times(1))
        verify(mockRingtoneFactory, atLeastOnce())
            .getRingtone(any(Call.class), isNull(), anyBoolean());
        verifyNoMoreInteractions(mockRingtoneFactory);
        verify(mockTonePlayer).stopTone();
@@ -623,7 +624,7 @@ public class RingerTest extends TelecomTestCase {

        asyncRingtonePlayer.updateBtActiveState(true);
        mRingCompletionFuture.get();
        verify(mockRingtoneFactory, times(1))
        verify(mockRingtoneFactory, atLeastOnce())
                .getRingtone(any(Call.class), nullable(VolumeShaper.Configuration.class),
                        anyBoolean());
        verifyNoMoreInteractions(mockRingtoneFactory);
@@ -753,7 +754,7 @@ public class RingerTest extends TelecomTestCase {
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                    return mockRingtone;
                    return new Pair(FAKE_RINGTONE_URI, mockRingtone);
                });
        // Start call waiting to make sure that it doesn't stop when we start ringing
        enableVibrationWhenRinging();
@@ -832,10 +833,12 @@ public class RingerTest extends TelecomTestCase {

    private Ringtone ensureRingtoneMocked() {
        Ringtone mockRingtone = mock(Ringtone.class);
        Pair<Uri, Ringtone> ringtoneInfo = new Pair(
                FAKE_RINGTONE_URI, mockRingtone);
        when(mockRingtoneFactory.getRingtone(
                any(Call.class), nullable(VolumeShaper.Configuration.class), anyBoolean()))
                .thenReturn(mockRingtone);
        when(mockRingtoneFactory.getHapticOnlyRingtone()).thenReturn(mockRingtone);
                .thenReturn(ringtoneInfo);
        when(mockRingtoneFactory.getHapticOnlyRingtone()).thenReturn(ringtoneInfo);
        return mockRingtone;
    }