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
diff --git a/src/com/android/server/telecom/AsyncRingtonePlayer.java b/src/com/android/server/telecom/AsyncRingtonePlayer.java
index 912305b..3b5e342 100644
--- a/src/com/android/server/telecom/AsyncRingtonePlayer.java
+++ b/src/com/android/server/telecom/AsyncRingtonePlayer.java
@@ -26,6 +26,8 @@
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 @@
* 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 @@
* 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 @@
return;
}
Ringtone ringtone = null;
+ Uri ringtoneUri = null;
boolean hasStopped = false;
try {
try {
@@ -236,7 +242,11 @@
} 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 @@
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 @@
Log.i(this, "Play ringtone, looping.");
} finally {
removePendingRingingReadyLatch(ringingReadyLatch);
- ringtoneConsumer.accept(ringtone, hasStopped);
+ ringtoneConsumer.accept(new Pair(ringtoneUri, ringtone), hasStopped);
}
} finally {
Log.cancelSubsession(session);
diff --git a/src/com/android/server/telecom/Ringer.java b/src/com/android/server/telecom/Ringer.java
index 3ec4ebe..e148ef5 100644
--- a/src/com/android/server/telecom/Ringer.java
+++ b/src/com/android/server/telecom/Ringer.java
@@ -44,6 +44,7 @@
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 @@
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 @@
// 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 @@
if (DEBUG_RINGER) {
Log.d(this, "Using ringtone defined vibration effect.");
}
- vibrationEffect = getVibrationEffectForRingtone(ringtone);
+ vibrationEffect = getVibrationEffectForRingtone(ringtoneUri);
} else {
vibrationEffect = mDefaultVibrationEffect;
}
@@ -477,10 +487,10 @@
}
};
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 @@
}
}
- private VibrationEffect getVibrationEffectForRingtone(@NonNull Ringtone ringtone) {
- Uri ringtoneUri = ringtone.getUri();
+ private VibrationEffect getVibrationEffectForRingtone(Uri ringtoneUri) {
if (ringtoneUri == null) {
return mDefaultVibrationEffect;
}
diff --git a/src/com/android/server/telecom/RingtoneFactory.java b/src/com/android/server/telecom/RingtoneFactory.java
index 6bcfb4c..0e0b99f 100644
--- a/src/com/android/server/telecom/RingtoneFactory.java
+++ b/src/com/android/server/telecom/RingtoneFactory.java
@@ -34,6 +34,7 @@
import com.android.internal.annotations.VisibleForTesting;
import android.telecom.CallerInfo;
+import android.util.Pair;
import java.util.List;
@@ -53,18 +54,7 @@
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 @@
}
}
- 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 @@
/** 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(
@@ -138,12 +129,12 @@
AudioAttributes audioAttrs = getDefaultRingtoneAudioAttributes(
/* hapticChannelsMuted */ false);
Ringtone ringtone = RingtoneManager.getRingtone(
- mContext, ringtoneUri, /* volumeShaperConfig */ null, audioAttrs);
+ mContext, ringtoneUri, /* volumeShaperConfig */ null, audioAttrs);
if (ringtone != null) {
// Make sure the sound is muted.
ringtone.setVolume(0);
}
- return ringtone;
+ return new Pair(ringtoneUri, ringtone);
}
private Context getWorkProfileContextForUser(UserHandle userHandle) {
diff --git a/tests/src/com/android/server/telecom/tests/RingerTest.java b/tests/src/com/android/server/telecom/tests/RingerTest.java
index a0ec267..1215fd3 100644
--- a/tests/src/com/android/server/telecom/tests/RingerTest.java
+++ b/tests/src/com/android/server/telecom/tests/RingerTest.java
@@ -59,6 +59,7 @@
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 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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
} 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 @@
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;
}