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

Commit 0b0ce23f authored by Pranav Madapurmath's avatar Pranav Madapurmath
Browse files

Resolve Ringer#getUri Telecom usages

As part of mainline prep, resolve the Telecom references to
Ringtone#getUri (hidden). This is primarily used for logging so we can
remove these references. In the case of finding the vibration effect
associated with the Uri, this can be referenced from the uri determined
in RingtoneFactory#getHapticOnlyRingtone or RingtoneFactory#getRingtone.

Bug: 307815630
Bug: 311773409
Test: atest TelecomUnitTests
Change-Id: I1e6019156513f0821aa162efc412acff20962ab6
parent 11318e56
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;
    }