Merge "Remove BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS for ConnectionService bind." into qt-dev am: f44200a565 am: 43be434335 am: 8fcb7fa2f4 am: 2d2dc88e8a am: a9d89f3ca5 am: 946f77ccd0 am: 6bfe5a3221
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/services/Telecomm/+/16576060
Change-Id: Ifc23d879953e9efc9210058f7acbbecbb3ea6449
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c38fa4e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.idea
+*.iml
diff --git a/src/com/android/server/telecom/AsyncRingtonePlayer.java b/src/com/android/server/telecom/AsyncRingtonePlayer.java
index bf2472f..d7786e1 100644
--- a/src/com/android/server/telecom/AsyncRingtonePlayer.java
+++ b/src/com/android/server/telecom/AsyncRingtonePlayer.java
@@ -77,8 +77,10 @@
* {@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 @@
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,30 +155,33 @@
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;
}
-
- return;
}
ThreadUtil.checkNotOnMainThread();
@@ -189,34 +195,30 @@
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.
- if (mHapticsFuture != null && !mHapticsFuture.isDone()) {
- boolean hasHaptics = factory.hasHapticChannels(mRingtone);
- Log.i(this, "handlePlay: hasHaptics=%b, isVibrationEnabled=%b", hasHaptics,
- isVibrationEnabled);
- SystemSettingsUtil systemSettingsUtil = new SystemSettingsUtil();
- if (hasHaptics && (volumeShaperConfig == null
- || systemSettingsUtil.enableAudioCoupledVibrationForRampingRinger())) {
- AudioAttributes attributes = mRingtone.getAudioAttributes();
- Log.d(this, "handlePlay: %s haptic channel",
- (isVibrationEnabled ? "unmuting" : "muting"));
- mRingtone.setAudioAttributes(
- new AudioAttributes.Builder(attributes)
- .setHapticChannelsMuted(!isVibrationEnabled)
- .build());
- }
- mHapticsFuture.complete(hasHaptics);
- mHapticsFuture = null;
+ // 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.
+ if (mHapticsFuture != null && !mHapticsFuture.isDone()) {
+ boolean hasHaptics = factory.hasHapticChannels(mRingtone);
+ Log.i(this, "handlePlay: hasHaptics=%b, isVibrationEnabled=%b", hasHaptics,
+ isVibrationEnabled);
+ SystemSettingsUtil systemSettingsUtil = new SystemSettingsUtil();
+ if (hasHaptics && (volumeShaperConfig == null
+ || systemSettingsUtil.enableAudioCoupledVibrationForRampingRinger())) {
+ AudioAttributes attributes = mRingtone.getAudioAttributes();
+ Log.d(this, "handlePlay: %s haptic channel",
+ (isVibrationEnabled ? "unmuting" : "muting"));
+ mRingtone.setAudioAttributes(
+ new AudioAttributes.Builder(attributes)
+ .setHapticChannelsMuted(!isVibrationEnabled)
+ .build());
}
+ completeHapticFuture(hasHaptics);
}
mRingtone.setLooping(true);
@@ -259,4 +261,11 @@
public boolean isPlaying() {
return mRingtone != null;
}
+
+ private void completeHapticFuture(boolean ringtoneHasHaptics) {
+ if (mHapticsFuture != null) {
+ mHapticsFuture.complete(ringtoneHasHaptics);
+ mHapticsFuture = null;
+ }
+ }
}
diff --git a/src/com/android/server/telecom/Ringer.java b/src/com/android/server/telecom/Ringer.java
index 91276de..6c9b1cc 100644
--- a/src/com/android/server/telecom/Ringer.java
+++ b/src/com/android/server/telecom/Ringer.java
@@ -280,25 +280,33 @@
}
if (mVolumeShaperConfig == null) {
float silencePoint = (float) (RAMPING_RINGER_VIBRATION_DURATION)
- / (float) (RAMPING_RINGER_VIBRATION_DURATION + RAMPING_RINGER_DURATION);
+ / (float) (RAMPING_RINGER_VIBRATION_DURATION + RAMPING_RINGER_DURATION);
mVolumeShaperConfig = new VolumeShaper.Configuration.Builder()
- .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)
- .build();
+ .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)
+ .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;
}
diff --git a/src/com/android/server/telecom/RingtoneFactory.java b/src/com/android/server/telecom/RingtoneFactory.java
index 6a121f7..b1846fe 100644
--- a/src/com/android/server/telecom/RingtoneFactory.java
+++ b/src/com/android/server/telecom/RingtoneFactory.java
@@ -109,6 +109,27 @@
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)
@@ -118,10 +139,6 @@
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).
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 8d6e324..620378b 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -284,7 +284,7 @@
public List<PhoneAccountHandle> getPhoneAccountsForPackage(String packageName) {
//TODO: Deprecate this in S
try {
- enforceCallingPackage(packageName);
+ enforceCallingPackage(packageName, "getPhoneAccountsForPackage");
} catch (SecurityException se1) {
EventLog.writeEvent(0x534e4554, "153995334", Binder.getCallingUid(),
"getPhoneAccountsForPackage: invalid calling package");
@@ -319,6 +319,13 @@
@Override
public PhoneAccount getPhoneAccount(PhoneAccountHandle accountHandle,
String callingPackage) {
+ try {
+ enforceCallingPackage(callingPackage, "getPhoneAccount");
+ } catch (SecurityException se) {
+ EventLog.writeEvent(0x534e4554, "196406138", Binder.getCallingUid(),
+ "getPhoneAccount: invalid calling package");
+ throw se;
+ }
synchronized (mLock) {
final UserHandle callingUserHandle = Binder.getCallingUserHandle();
if (CompatChanges.isChangeEnabled(
@@ -852,7 +859,7 @@
public boolean hasManageOngoingCallsPermission(String callingPackage) {
try {
Log.startSession("TSI.hMOCP");
- enforceCallingPackage(callingPackage);
+ enforceCallingPackage(callingPackage, "hasManageOngoingCallsPermission");
return PermissionChecker.checkPermissionForDataDeliveryFromDataSource(
mContext, Manifest.permission.MANAGE_ONGOING_CALLS,
Binder.getCallingPid(),
@@ -1464,7 +1471,7 @@
String callingFeatureId) {
try {
Log.startSession("TSI.pC", Log.getPackageAbbreviation(callingPackage));
- enforceCallingPackage(callingPackage);
+ enforceCallingPackage(callingPackage, "placeCall");
PhoneAccountHandle phoneAccountHandle = null;
boolean clearPhoneAccountHandleExtra = false;
@@ -2229,7 +2236,7 @@
// feature is enabled ...
enforceConnectionServiceFeature();
// ... and the PhoneAccounts they refer to are for their own package.
- enforceCallingPackage(packageName);
+ enforceCallingPackage(packageName, "enforcePhoneAccountModificationForPackage");
}
}
@@ -2245,8 +2252,22 @@
}
}
- private void enforceCallingPackage(String packageName) {
- mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
+ private void enforceCallingPackage(String packageName, String message) {
+ int packageUid = -1;
+ int callingUid = Binder.getCallingUid();
+ PackageManager pm = mContext.createContextAsUser(
+ UserHandle.getUserHandleForUid(callingUid), 0).getPackageManager();
+ if (pm != null) {
+ try {
+ packageUid = pm.getPackageUid(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ // packageUid is -1
+ }
+ }
+ if (packageUid != callingUid && callingUid != Process.ROOT_UID) {
+ throw new SecurityException(message + ": Package " + packageName
+ + " does not belong to " + callingUid);
+ }
}
private void enforceConnectionServiceFeature() {
diff --git a/src/com/android/server/telecom/TtyManager.java b/src/com/android/server/telecom/TtyManager.java
index f1b74a4..10e3348 100644
--- a/src/com/android/server/telecom/TtyManager.java
+++ b/src/com/android/server/telecom/TtyManager.java
@@ -84,7 +84,8 @@
mCurrentTtyMode = newTtyMode;
Intent ttyModeChanged = new Intent(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
ttyModeChanged.putExtra(TelecomManager.EXTRA_CURRENT_TTY_MODE, mCurrentTtyMode);
- mContext.sendBroadcastAsUser(ttyModeChanged, UserHandle.ALL);
+ mContext.sendBroadcastAsUser(ttyModeChanged, UserHandle.ALL,
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
updateAudioTtyMode();
}
diff --git a/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java b/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
index 4a308e0..0c30a16 100644
--- a/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
+++ b/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
@@ -313,11 +313,15 @@
private void bindCallScreeningService(
CompletableFuture<CallFilteringResult> resultFuture) {
- mConnection = new CallScreeningServiceConnection(resultFuture);
+ CallScreeningServiceConnection connection = new CallScreeningServiceConnection(
+ resultFuture);
if (!CallScreeningServiceHelper.bindCallScreeningService(mContext,
- mCallsManager.getCurrentUserHandle(), mPackageName, mConnection)) {
+ mCallsManager.getCurrentUserHandle(), mPackageName, connection)) {
Log.i(this, "Call screening service binding failed.");
resultFuture.complete(mPriorStageResult);
+ mConnection = null;
+ } else {
+ mConnection = connection;
}
}
diff --git a/tests/src/com/android/server/telecom/tests/BasicCallTests.java b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
index a3b8654..058eb12 100644
--- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
@@ -26,6 +26,7 @@
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
@@ -35,10 +36,13 @@
import android.content.Context;
import android.content.IContentProvider;
+import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.net.Uri;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Process;
+import android.os.UserHandle;
import android.provider.BlockedNumberContract;
import android.telecom.Call;
import android.telecom.CallAudioState;
@@ -85,10 +89,15 @@
private static final String TEST_BUNDLE_KEY = "android.telecom.extra.TEST";
private static final String TEST_EVENT = "android.telecom.event.TEST";
+ private PackageManager mPackageManager;
+
@Override
@Before
public void setUp() throws Exception {
super.setUp();
+ doReturn(mContext).when(mContext).createContextAsUser(any(UserHandle.class), anyInt());
+ mPackageManager = mContext.getPackageManager();
+ when(mPackageManager.getPackageUid(anyString(), eq(0))).thenReturn(Binder.getCallingUid());
}
@Override
diff --git a/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java b/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
index 68caf67..9ff9986 100644
--- a/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
@@ -62,6 +62,7 @@
import org.mockito.Mock;
import java.util.Collections;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
@@ -229,12 +230,30 @@
CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, PKG_NAME,
CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
mAppLabelProxy, mParcelableCallUtilsConverter);
- filter.startFilterLookup(inputResult);
+ CompletableFuture<CallFilteringResult> result = filter.startFilterLookup(inputResult)
+ .toCompletableFuture();
+
+ assertEquals(result.isDone(), false);
+
filter.unbindCallScreeningService();
}
@SmallTest
@Test
+ public void testBindingFailed() {
+ // Use an empty package name here, which fails in the bindCallScreeningService.
+ CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, "",
+ CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
+ mAppLabelProxy, mParcelableCallUtilsConverter);
+
+ CompletableFuture<CallFilteringResult> result = filter.startFilterLookup(inputResult)
+ .toCompletableFuture();
+
+ assertEquals(result.isDone(), true);
+ }
+
+ @SmallTest
+ @Test
public void testAllowCall() throws Exception {
CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, PKG_NAME,
CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
diff --git a/tests/src/com/android/server/telecom/tests/MissedInformationTest.java b/tests/src/com/android/server/telecom/tests/MissedInformationTest.java
index a8e1c5f..e6cd986 100644
--- a/tests/src/com/android/server/telecom/tests/MissedInformationTest.java
+++ b/tests/src/com/android/server/telecom/tests/MissedInformationTest.java
@@ -26,6 +26,9 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
@@ -36,8 +39,11 @@
import android.content.ContentValues;
import android.content.IContentProvider;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.net.Uri;
+import android.os.Binder;
import android.os.Bundle;
+import android.os.UserHandle;
import android.provider.CallLog;
import android.telecom.DisconnectCause;
import android.telecom.TelecomManager;
@@ -73,6 +79,7 @@
@Mock Call mIncomingCall;
private CallsManager mCallsManager;
private CallIntentProcessor.AdapterImpl mAdapter;
+ private PackageManager mPackageManager;
@Override
@Before
@@ -85,6 +92,9 @@
when(mContentProvider.call(any(String.class), any(String.class),
any(String.class), any(Bundle.class))).thenReturn(new Bundle());
doReturn(mContentResolver).when(mSpyContext).getContentResolver();
+ doReturn(mContext).when(mContext).createContextAsUser(any(UserHandle.class), anyInt());
+ mPackageManager = mContext.getPackageManager();
+ when(mPackageManager.getPackageUid(anyString(), eq(0))).thenReturn(Binder.getCallingUid());
}
@Override
diff --git a/tests/src/com/android/server/telecom/tests/RingerTest.java b/tests/src/com/android/server/telecom/tests/RingerTest.java
index 0e93481..00456e2 100644
--- a/tests/src/com/android/server/telecom/tests/RingerTest.java
+++ b/tests/src/com/android/server/telecom/tests/RingerTest.java
@@ -149,7 +149,8 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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,21 +308,44 @@
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 {
enableVibrationWhenRinging();
Ringtone mockRingtone = mock(Ringtone.class);
@@ -329,7 +355,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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));
}
diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
index 3cec50b..5c131c8 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
@@ -102,6 +102,7 @@
public class TelecomServiceImplTest extends TelecomTestCase {
public static final String TEST_PACKAGE = "com.test";
+ public static final String PACKAGE_NAME = "test";
public static class CallIntentProcessAdapterFake implements CallIntentProcessor.Adapter {
@Override
@@ -180,15 +181,17 @@
private static final UserHandle USER_HANDLE_16 = new UserHandle(16);
private static final UserHandle USER_HANDLE_17 = new UserHandle(17);
private static final PhoneAccountHandle TEL_PA_HANDLE_16 = new PhoneAccountHandle(
- new ComponentName("test", "telComponentName"), "0", USER_HANDLE_16);
+ new ComponentName(PACKAGE_NAME, "telComponentName"), "0", USER_HANDLE_16);
private static final PhoneAccountHandle SIP_PA_HANDLE_17 = new PhoneAccountHandle(
- new ComponentName("test", "sipComponentName"), "1", USER_HANDLE_17);
+ new ComponentName(PACKAGE_NAME, "sipComponentName"), "1", USER_HANDLE_17);
private static final PhoneAccountHandle TEL_PA_HANDLE_CURRENT = new PhoneAccountHandle(
- new ComponentName("test", "telComponentName"), "2", Binder.getCallingUserHandle());
+ new ComponentName(PACKAGE_NAME, "telComponentName"), "2",
+ Binder.getCallingUserHandle());
private static final PhoneAccountHandle SIP_PA_HANDLE_CURRENT = new PhoneAccountHandle(
- new ComponentName("test", "sipComponentName"), "3", Binder.getCallingUserHandle());
- private static final ComponentName THIRD_PARTY_CALL_SCREENING = new ComponentName("com.android" +
- ".thirdparty", "com.android.thirdparty.callscreeningserviceimpl");
+ new ComponentName(PACKAGE_NAME, "sipComponentName"), "3",
+ Binder.getCallingUserHandle());
+ private static final ComponentName THIRD_PARTY_CALL_SCREENING = new ComponentName(
+ "com.android.thirdparty", "com.android.thirdparty.callscreeningserviceimpl");
@Override
@Before
@@ -201,6 +204,7 @@
when(mockTelephonyManager.isVoiceCapable()).thenReturn(true);
doReturn(mContext).when(mContext).getApplicationContext();
+ doReturn(mContext).when(mContext).createContextAsUser(any(UserHandle.class), anyInt());
doNothing().when(mContext).sendBroadcastAsUser(any(Intent.class), any(UserHandle.class),
anyString());
doAnswer(invocation -> {
@@ -237,6 +241,7 @@
.thenReturn(true);
mPackageManager = mContext.getPackageManager();
+ when(mPackageManager.getPackageUid(anyString(), eq(0))).thenReturn(Binder.getCallingUid());
}
@Override
@@ -458,12 +463,18 @@
@SmallTest
@Test
- public void testGetPhoneAccount() throws RemoteException {
+ public void testGetPhoneAccount() throws Exception {
makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_16, SIP_PA_HANDLE_17);
assertEquals(TEL_PA_HANDLE_16, mTSIBinder.getPhoneAccount(TEL_PA_HANDLE_16,
mContext.getPackageName()).getAccountHandle());
assertEquals(SIP_PA_HANDLE_17, mTSIBinder.getPhoneAccount(SIP_PA_HANDLE_17,
mContext.getPackageName()).getAccountHandle());
+ try {
+ // Try to call the method without using the caller's package name
+ mTSIBinder.getPhoneAccount(TEL_PA_HANDLE_16, null);
+ fail("Should have thrown a SecurityException");
+ } catch (SecurityException expected) {
+ }
}
@SmallTest