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

Commit 576eca7c authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Update default vibration to use OGG haptic file" into sc-v2-dev

parents 86c52a45 56ebc519
Loading
Loading
Loading
Loading

.gitignore

0 → 100644
+2 −0
Original line number Diff line number Diff line
.idea
*.iml
+50 −41
Original line number Diff line number Diff line
@@ -77,8 +77,10 @@ public class AsyncRingtonePlayer {
     *         {@code False} indicates that a haptic track is NOT present on the ringtone;
     *         in this case the default vibration in {@link Ringer} should be trigger if needed.
     */
    public @NonNull CompletableFuture<Boolean> play(RingtoneFactory factory, Call incomingCall,
            @Nullable VolumeShaper.Configuration volumeShaperConfig, boolean isVibrationEnabled) {
    public @NonNull
    CompletableFuture<Boolean> play(RingtoneFactory factory, Call incomingCall,
            @Nullable VolumeShaper.Configuration volumeShaperConfig, boolean isRingerAudible,
            boolean isVibrationEnabled) {
        Log.d(this, "Posting play.");
        if (mHapticsFuture == null) {
            mHapticsFuture = new CompletableFuture<>();
@@ -88,7 +90,8 @@ public class AsyncRingtonePlayer {
        args.arg2 = incomingCall;
        args.arg3 = volumeShaperConfig;
        args.arg4 = isVibrationEnabled;
        args.arg5 = Log.createSubsession();
        args.arg5 = isRingerAudible;
        args.arg6 = Log.createSubsession();
        postMessage(EVENT_PLAY, true /* shouldCreateHandler */, args);
        return mHapticsFuture;
    }
@@ -152,31 +155,34 @@ public class AsyncRingtonePlayer {
        Call incomingCall = (Call) args.arg2;
        VolumeShaper.Configuration volumeShaperConfig = (VolumeShaper.Configuration) args.arg3;
        boolean isVibrationEnabled = (boolean) args.arg4;
        Session session = (Session) args.arg5;
        boolean isRingerAudible = (boolean) args.arg5;
        Session session = (Session) args.arg6;
        args.recycle();

        Log.continueSession(session, "ARP.hP");
        try {
            // don't bother with any of this if there is an EVENT_STOP waiting.
            if (mHandler.hasMessages(EVENT_STOP)) {
                if (mHapticsFuture != null) {
                    mHapticsFuture.complete(false /* ringtoneHasHaptics */);
                    mHapticsFuture = null;
                }
                completeHapticFuture(false /* ringtoneHasHaptics */);
                return;
            }

            // If the Ringtone Uri is EMPTY, then the "None" Ringtone has been selected. Do not play
            // anything.
            if (Uri.EMPTY.equals(incomingCall.getRingtone())) {
                mRingtone = null;
                if (mHapticsFuture != null) {
                    mHapticsFuture.complete(false /* ringtoneHasHaptics */);
                    mHapticsFuture = null;
            // If the Ringtone Uri is EMPTY, then the "None" Ringtone has been selected.
            // If ringer is not audible for this call, then the phone is in "Vibrate" mode.
            // Use haptic-only ringtone or do not play anything.
            if (!isRingerAudible || Uri.EMPTY.equals(incomingCall.getRingtone())) {
                if (isVibrationEnabled) {
                    mRingtone = factory.getHapticOnlyRingtone();
                    if (mRingtone == null) {
                        completeHapticFuture(false /* ringtoneHasHaptics */);
                        return;
                    }

                } else {
                    mRingtone = null;
                    completeHapticFuture(false /* ringtoneHasHaptics */);
                    return;
                }
            }

            ThreadUtil.checkNotOnMainThread();
            Log.i(this, "handlePlay: Play ringtone.");
@@ -189,16 +195,14 @@ public class AsyncRingtonePlayer {
                            ringtoneUri.toSafeString();
                    Log.addEvent(null, LogUtils.Events.ERROR_LOG, "Failed to get ringtone from " +
                            "factory. Skipping ringing. Uri was: " + ringtoneUriString);
                    if (mHapticsFuture != null) {
                        mHapticsFuture.complete(false /* ringtoneHasHaptics */);
                        mHapticsFuture = null;
                    }
                    completeHapticFuture(false /* ringtoneHasHaptics */);
                    return;
                }
            }

            // With the ringtone to play now known, we can determine if it has haptic channels or
                // not; we will complete the haptics future so the default vibration code in Ringer
                // can know whether to trigger the vibrator.
            // not; we will complete the haptics future so the default vibration code in Ringer can
            // know whether to trigger the vibrator.
            if (mHapticsFuture != null && !mHapticsFuture.isDone()) {
                boolean hasHaptics = factory.hasHapticChannels(mRingtone);
                Log.i(this, "handlePlay: hasHaptics=%b, isVibrationEnabled=%b", hasHaptics,
@@ -214,9 +218,7 @@ public class AsyncRingtonePlayer {
                                    .setHapticChannelsMuted(!isVibrationEnabled)
                                    .build());
                }
                    mHapticsFuture.complete(hasHaptics);
                    mHapticsFuture = null;
                }
                completeHapticFuture(hasHaptics);
            }

            mRingtone.setLooping(true);
@@ -259,4 +261,11 @@ public class AsyncRingtonePlayer {
    public boolean isPlaying() {
        return mRingtone != null;
    }

    private void completeHapticFuture(boolean ringtoneHasHaptics) {
        if (mHapticsFuture != null) {
            mHapticsFuture.complete(ringtoneHasHaptics);
            mHapticsFuture = null;
        }
    }
}
+16 −8
Original line number Diff line number Diff line
@@ -282,23 +282,31 @@ public class Ringer {
                    float silencePoint = (float) (RAMPING_RINGER_VIBRATION_DURATION)
                            / (float) (RAMPING_RINGER_VIBRATION_DURATION + RAMPING_RINGER_DURATION);
                    mVolumeShaperConfig = new VolumeShaper.Configuration.Builder()
                        .setDuration(RAMPING_RINGER_VIBRATION_DURATION + RAMPING_RINGER_DURATION)
                            .setDuration(
                                    RAMPING_RINGER_VIBRATION_DURATION + RAMPING_RINGER_DURATION)
                            .setCurve(new float[]{0.f, silencePoint + EPSILON /*keep monotonicity*/,
                                    1.f}, new float[]{0.f, 0.f, 1.f})
                        .setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
                            .setInterpolatorType(
                                    VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
                            .build();
                }
                hapticsFuture = mRingtonePlayer.play(mRingtoneFactory, foregroundCall,
                        mVolumeShaperConfig, isVibratorEnabled);
                        mVolumeShaperConfig, attributes.isRingerAudible(), isVibratorEnabled);
            } else {
                // Ramping ringtone is not enabled.
                hapticsFuture = mRingtonePlayer.play(mRingtoneFactory, foregroundCall, null,
                        isVibratorEnabled);
                        attributes.isRingerAudible(), isVibratorEnabled);
                effect = getVibrationEffectForCall(mRingtoneFactory, foregroundCall);
            }
        } else {
            Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Inaudible: "
                    + attributes.getInaudibleReason());
            if (isVibratorEnabled && mIsHapticPlaybackSupportedByDevice) {
                // Attempt to run the attentional haptic ringtone first and fallback to the default
                // vibration effect if hapticFuture is completed with false.
                hapticsFuture = mRingtonePlayer.play(mRingtoneFactory, foregroundCall, null,
                        attributes.isRingerAudible(), isVibratorEnabled);
            }
            effect = mDefaultVibrationEffect;
        }

+21 −4
Original line number Diff line number Diff line
@@ -103,6 +103,27 @@ public class RingtoneFactory {
                Log.e(this, npe, "getRingtone: NPE while getting ringtone.");
            }
        }
        return setRingtoneAudioAttributes(ringtone);
    }

    public Ringtone getRingtone(Call incomingCall) {
        return getRingtone(incomingCall, null);
    }

    /** Returns a ringtone to be used when ringer is not audible for the incoming call. */
    @Nullable
    public Ringtone getHapticOnlyRingtone() {
        Uri ringtoneUri = Uri.parse("file://" + mContext.getString(
                com.android.internal.R.string.config_defaultRingtoneVibrationSound));
        Ringtone ringtone = RingtoneManager.getRingtone(mContext, ringtoneUri, null);
        if (ringtone != null) {
            // Make sure the sound is muted.
            ringtone.setVolume(0);
        }
        return setRingtoneAudioAttributes(ringtone);
    }

    private Ringtone setRingtoneAudioAttributes(Ringtone ringtone) {
        if (ringtone != null) {
            ringtone.setAudioAttributes(new AudioAttributes.Builder()
                    .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
@@ -112,10 +133,6 @@ public class RingtoneFactory {
        return ringtone;
    }

    public Ringtone getRingtone(Call incomingCall) {
        return getRingtone(incomingCall, null);
    }

    private Context getWorkProfileContextForUser(UserHandle userHandle) {
        // UserManager.getEnabledProfiles returns the enabled profiles along with the user's handle
        // itself (so we must filter out the user).
+46 −20
Original line number Diff line number Diff line
@@ -149,7 +149,8 @@ public class RingerTest extends TelecomTestCase {
        when(notificationManager.matchesCallFilter(any(Bundle.class))).thenReturn(true);
        when(mockRingtoneFactory.hasHapticChannels(any(Ringtone.class))).thenReturn(false);
        when(mockRingtonePlayer.play(any(RingtoneFactory.class), any(Call.class),
                nullable(VolumeShaper.Configuration.class), anyBoolean())).thenReturn(mFuture);
                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean()))
                .thenReturn(mFuture);
        mRingerUnderTest = new Ringer(mockPlayerFactory, mContext, mockSystemSettingsUtil,
                mockRingtonePlayer, mockRingtoneFactory, mockVibrator, spyVibrationEffectProxy,
                mockInCallController);
@@ -174,7 +175,7 @@ public class RingerTest extends TelecomTestCase {
        assertFalse(mRingerUnderTest.startRinging(mockCall2, false));
        verify(mockTonePlayer, never()).stopTone();
        verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
                eq(null), eq(false));
                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean());
        verify(mockVibrator, never())
                .vibrate(any(VibrationEffect.class), any(AudioAttributes.class));
    }
@@ -192,7 +193,7 @@ public class RingerTest extends TelecomTestCase {
        assertFalse(mRingerUnderTest.startRinging(mockCall2, false));
        verify(mockTonePlayer, never()).stopTone();
        verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
                any(VolumeShaper.Configuration.class), anyBoolean());
                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean());
        verify(mockVibrator, never())
                .vibrate(any(VibrationEffect.class), any(AudioAttributes.class));
    }
@@ -208,7 +209,7 @@ public class RingerTest extends TelecomTestCase {
        mRingCompletionFuture.get();
        verify(mockTonePlayer, never()).stopTone();
        verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
                any(VolumeShaper.Configuration.class), anyBoolean());
                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean());
        verify(mockVibrator, never())
                .vibrate(any(VibrationEffect.class), any(AudioAttributes.class));
    }
@@ -225,7 +226,7 @@ public class RingerTest extends TelecomTestCase {
        mRingCompletionFuture.get();
        verify(mockTonePlayer, never()).stopTone();
        verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
                any(VolumeShaper.Configuration.class), anyBoolean());
                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean());
        verify(mockVibrator, never())
                .vibrate(any(VibrationEffect.class), any(AudioAttributes.class));
    }
@@ -241,7 +242,7 @@ public class RingerTest extends TelecomTestCase {
        assertTrue(mRingerUnderTest.startRinging(mockCall2, true));
        verify(mockTonePlayer, never()).stopTone();
        verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
                any(VolumeShaper.Configuration.class), anyBoolean());
                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean());
        verify(mockVibrator, never())
                .vibrate(any(VibrationEffect.class), any(AudioAttributes.class));
    }
@@ -260,7 +261,7 @@ public class RingerTest extends TelecomTestCase {
        assertFalse(mRingerUnderTest.startRinging(mockCall2, false));
        verify(mockTonePlayer).stopTone();
        verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
                any(VolumeShaper.Configuration.class), anyBoolean());
                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean());
        verify(mockVibrator, never())
                .vibrate(any(VibrationEffect.class), any(AudioAttributes.class));
    }
@@ -276,8 +277,8 @@ public class RingerTest extends TelecomTestCase {
        assertTrue(mRingerUnderTest.startRinging(mockCall2, false));
        mRingCompletionFuture.get();
        verify(mockTonePlayer).stopTone();
        verify(mockRingtonePlayer).play(
                any(RingtoneFactory.class), any(Call.class), isNull(), eq(true));
        verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class), isNull(),
                eq(true) /* isRingerAudible */, eq(true) /* isVibrationEnabled */);
        verify(mockVibrator, never()).vibrate(any(VibrationEffect.class),
                any(AudioAttributes.class));
    }
@@ -293,8 +294,10 @@ public class RingerTest extends TelecomTestCase {
        assertFalse(mRingerUnderTest.startRinging(mockCall2, false));
        mRingCompletionFuture.get();
        verify(mockTonePlayer).stopTone();
        verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
                any(VolumeShaper.Configuration.class), anyBoolean());
        // Try to play a silent haptics ringtone
        verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class), isNull(),
                eq(false) /* isRingerAudible */, eq(true) /* isVibrationEnabled */);
        // Play default vibration when future completes with no audio coupled haptics
        verify(mockVibrator).vibrate(eq(mRingerUnderTest.mDefaultVibrationEffect),
                any(AudioAttributes.class));
    }
@@ -305,19 +308,42 @@ public class RingerTest extends TelecomTestCase {
        mRingerUnderTest.startCallWaiting(mockCall1);
        Ringtone mockRingtone = mock(Ringtone.class);
        when(mockRingtoneFactory.getRingtone(any(Call.class))).thenReturn(mockRingtone);
        when(mockAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
        when(mockAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
        when(mockAudioManager.getStreamVolume(AudioManager.STREAM_RING)).thenReturn(0);
        mFuture.complete(false); // not using audio coupled haptics
        enableVibrationWhenRinging();
        assertFalse(mRingerUnderTest.startRinging(mockCall2, false));
        mRingCompletionFuture.get();
        verify(mockTonePlayer).stopTone();
        verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
                any(VolumeShaper.Configuration.class), anyBoolean());
        // Try to play a silent haptics ringtone
        verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class), isNull(),
                eq(false) /* isRingerAudible */, eq(true) /* isVibrationEnabled */);
        // Play default vibration when future completes with no audio coupled haptics
        verify(mockVibrator).vibrate(eq(mRingerUnderTest.mDefaultVibrationEffect),
                any(AudioAttributes.class));
    }

    @SmallTest
    @Test
    public void testAudioCoupledHapticsForSilentRingtone() throws Exception {
        mRingerUnderTest.startCallWaiting(mockCall1);
        Ringtone mockRingtone = mock(Ringtone.class);
        when(mockRingtoneFactory.getRingtone(any(Call.class))).thenReturn(mockRingtone);
        when(mockAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
        when(mockAudioManager.getStreamVolume(AudioManager.STREAM_RING)).thenReturn(0);
        mFuture.complete(true); // using audio coupled haptics
        enableVibrationWhenRinging();
        assertFalse(mRingerUnderTest.startRinging(mockCall2, false));
        mRingCompletionFuture.get();
        verify(mockTonePlayer).stopTone();
        // Try to play a silent haptics ringtone
        verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class), isNull(),
                eq(false) /* isRingerAudible */, eq(true) /* isVibrationEnabled */);
        // Skip vibration for audio coupled haptics
        verify(mockVibrator, never()).vibrate(any(VibrationEffect.class),
                any(AudioAttributes.class));
    }

    @SmallTest
    @Test
    public void testStopRingingBeforeHapticsLookupComplete() throws Exception {
@@ -329,7 +355,7 @@ public class RingerTest extends TelecomTestCase {
        mRingerUnderTest.startRinging(mockCall1, false);
        // Make sure we haven't started the vibrator yet, but have started ringing.
        verify(mockRingtonePlayer).play(nullable(RingtoneFactory.class), nullable(Call.class),
                nullable(VolumeShaper.Configuration.class), anyBoolean());
                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean());
        verify(mockVibrator, never()).vibrate(nullable(VibrationEffect.class),
                nullable(AudioAttributes.class));
        // Simulate something stopping the ringer
@@ -357,7 +383,7 @@ public class RingerTest extends TelecomTestCase {
        mRingCompletionFuture.get();
        verify(mockTonePlayer).stopTone();
        verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class), eq(null),
                eq(true));
                eq(true) /* isRingerAudible */, eq(true) /* isVibrationEnabled */);
        verify(mockVibrator).vibrate(eq(spyVibrationEffectProxy.get(FAKE_RINGTONE_URI, mContext)),
                any(AudioAttributes.class));
    }
@@ -373,7 +399,7 @@ public class RingerTest extends TelecomTestCase {
        mRingCompletionFuture.get();
        verify(mockTonePlayer).stopTone();
        verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class), eq(null),
                eq(false));
                eq(true) /* isRingerAudible */, eq(false) /* isVibrationEnabled */);
        verify(mockVibrator, never())
                .vibrate(any(VibrationEffect.class), any(AudioAttributes.class));
    }
@@ -391,7 +417,7 @@ public class RingerTest extends TelecomTestCase {
        verify(mockTonePlayer).stopTone();
        verify(mockRingtonePlayer).play(
            any(RingtoneFactory.class), any(Call.class), any(VolumeShaper.Configuration.class),
                eq(true));
                eq(true) /* isRingerAudible */, eq(true) /* isVibrationEnabled */);
    }

    @SmallTest
@@ -408,7 +434,7 @@ public class RingerTest extends TelecomTestCase {
        mRingCompletionFuture.get();
        verify(mockTonePlayer).stopTone();
        verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
                any(VolumeShaper.Configuration.class), anyBoolean());
                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean());
        verify(mockVibrator, never())
                .vibrate(any(VibrationEffect.class), any(AudioAttributes.class));
    }
@@ -426,7 +452,7 @@ public class RingerTest extends TelecomTestCase {
        mRingCompletionFuture.get();
        verify(mockTonePlayer).stopTone();
        verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
                any(VolumeShaper.Configuration.class), anyBoolean());
                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean());
        verify(mockVibrator, never())
                .vibrate(any(VibrationEffect.class), any(AudioAttributes.class));
    }