Merge "Fix speakerphone logic when connecting/disconnecting dock." into tm-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a3c75a6..d376b6a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -263,7 +263,7 @@
<activity android:name=".RespondViaSmsSettings"
android:label="@string/respond_via_sms_setting_title"
android:configChanges="orientation|screenSize|keyboardHidden"
- android:theme="@style/Theme.Telecom.DialerSettings"
+ android:theme="@style/CallSettingsWithoutDividerTheme"
android:process=":ui"
android:exported="true">
<intent-filter>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 5ba0a3f..64dfabd 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -92,4 +92,9 @@
<item name="android:lineSpacingExtra">@dimen/blocked_numbers_secondary_line_spacing</item>
<item name="android:capitalize">sentences</item>
</style>
+
+ <style name="CallSettingsWithoutDividerTheme" parent="Theme.Telecom.DialerSettings">
+ <item name="android:listDivider">@null</item>
+ </style>
+
</resources>
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 9d6dd07..5a01be7 100755
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -3987,6 +3987,19 @@
return false;
}
+ /**
+ * Determines if there are any ongoing self managed calls for the given package/user.
+ * @param packageName The package name to check.
+ * @param userHandle The userhandle to check.
+ * @return {@code true} if the app has ongoing calls, or {@code false} otherwise.
+ */
+ public boolean isInSelfManagedCall(String packageName, UserHandle userHandle) {
+ return mCalls.stream().anyMatch(
+ c -> c.isSelfManaged()
+ && c.getTargetPhoneAccount().getComponentName().getPackageName().equals(packageName)
+ && c.getTargetPhoneAccount().getUserHandle().equals(userHandle));
+ }
+
@VisibleForTesting
public int getNumCallsWithState(final boolean isSelfManaged, Call excludeCall,
PhoneAccountHandle phoneAccountHandle, int... states) {
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 6e952e3..ec87555 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -944,6 +944,15 @@
}
};
+ private final BroadcastReceiver mUserAddedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
+ restrictPhoneCallOps();
+ }
+ }
+ };
+
private final SystemStateListener mSystemStateListener = new SystemStateListener() {
@Override
public void onCarModeChanged(int priority, String packageName, boolean isCarMode) {
@@ -1052,6 +1061,7 @@
mSystemStateHelper.addListener(mSystemStateListener);
mClockProxy = clockProxy;
restrictPhoneCallOps();
+ mContext.registerReceiver(mUserAddedReceiver, new IntentFilter(Intent.ACTION_USER_ADDED));
}
private void restrictPhoneCallOps() {
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index e65a651..9597403 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -47,6 +47,7 @@
import android.telecom.PhoneAccountHandle;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
+import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -1413,7 +1414,7 @@
public final UserHandle userHandle;
- public final PhoneAccountHandle phoneAccountHandle;
+ public PhoneAccountHandle phoneAccountHandle;
public final String groupId;
@@ -1555,6 +1556,7 @@
XmlPullParser parser = Xml.resolvePullParser(is);
parser.nextTag();
mState = readFromXml(parser, mContext);
+ migratePhoneAccountHandle(mState);
versionChanged = mState.versionNumber < EXPECTED_STATE_VERSION;
} catch (IOException | XmlPullParserException e) {
@@ -1599,6 +1601,50 @@
return s != null ? s : new State();
}
+ /**
+ * Try to migrate the ID of default phone account handle from IccId to SubId.
+ */
+ @VisibleForTesting
+ public void migratePhoneAccountHandle(State state) {
+ if (mSubscriptionManager == null) {
+ return;
+ }
+ // Use getAllSubscirptionInfoList() to get the mapping between iccId and subId
+ // from the subscription database
+ List<SubscriptionInfo> subscriptionInfos = mSubscriptionManager
+ .getAllSubscriptionInfoList();
+ Map<UserHandle, DefaultPhoneAccountHandle> defaultPhoneAccountHandles
+ = state.defaultOutgoingAccountHandles;
+ for (Map.Entry<UserHandle, DefaultPhoneAccountHandle> entry
+ : defaultPhoneAccountHandles.entrySet()) {
+ DefaultPhoneAccountHandle defaultPhoneAccountHandle = entry.getValue();
+
+ // Migrate Telephony PhoneAccountHandle only
+ String telephonyComponentName =
+ "com.android.phone/com.android.services.telephony.TelephonyConnectionService";
+ if (!defaultPhoneAccountHandle.phoneAccountHandle.getComponentName()
+ .flattenToString().equals(telephonyComponentName)) {
+ continue;
+ }
+ // Migrate from IccId to SubId
+ for (SubscriptionInfo subscriptionInfo : subscriptionInfos) {
+ String phoneAccountHandleId = defaultPhoneAccountHandle.phoneAccountHandle.getId();
+ // Some phone account handle would store phone account handle id with the IccId
+ // string plus "F", and the getIccId() returns IccId string itself without "F",
+ // so here need to use "startsWith" to match.
+ if (phoneAccountHandleId != null && phoneAccountHandleId.startsWith(
+ subscriptionInfo.getIccId())) {
+ Log.i(this, "Found subscription ID to migrate: "
+ + subscriptionInfo.getSubscriptionId());
+ defaultPhoneAccountHandle.phoneAccountHandle = new PhoneAccountHandle(
+ defaultPhoneAccountHandle.phoneAccountHandle.getComponentName(),
+ Integer.toString(subscriptionInfo.getSubscriptionId()));
+ break;
+ }
+ }
+ }
+ }
+
////////////////////////////////////////////////////////////////////////////////////////////////
//
// XML serialization
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 455fe85..5684612 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -530,12 +530,6 @@
try {
Log.startSession("TSI.rPA");
synchronized (mLock) {
- if (!((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE))
- .isVoiceCapable()) {
- Log.w(this,
- "registerPhoneAccount not allowed on non-voice capable device.");
- return;
- }
try {
enforcePhoneAccountModificationForPackage(
account.getAccountHandle().getComponentName().getPackageName());
@@ -2093,6 +2087,39 @@
Log.endSession();
}
}
+
+ /**
+ * Determines whether there are any ongoing {@link PhoneAccount#CAPABILITY_SELF_MANAGED}
+ * calls for a given {@code packageName} and {@code userHandle}.
+ *
+ * @param packageName the package name of the app to check calls for.
+ * @param userHandle the user handle on which to check for calls.
+ * @param callingPackage The caller's package name.
+ * @return {@code true} if there are ongoing calls, {@code false} otherwise.
+ */
+ @Override
+ public boolean isInSelfManagedCall(String packageName, UserHandle userHandle,
+ String callingPackage) {
+ try {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Only the system can call this API");
+ }
+ mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
+ "READ_PRIVILEGED_PHONE_STATE required.");
+
+ Log.startSession("TSI.iISMC", Log.getPackageAbbreviation(callingPackage));
+ synchronized (mLock) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ return mCallsManager.isInSelfManagedCall(packageName, userHandle);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
};
/**
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
index 2785739..e5706d2 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
@@ -382,16 +382,8 @@
}
public void disconnectAudio() {
- if (mBluetoothAdapter != null) {
- for (BluetoothDevice device: mBluetoothAdapter.getActiveDevices(
- BluetoothProfile.HEARING_AID)) {
- if (device != null) {
- mBluetoothAdapter.removeActiveDevice(BluetoothAdapter.ACTIVE_DEVICE_ALL);
- }
- }
- disconnectSco();
- clearLeAudioCommunicationDevice();
- }
+ disconnectSco();
+ clearLeAudioCommunicationDevice();
}
public void disconnectSco() {
diff --git a/src/com/android/server/telecom/components/UserCallIntentProcessor.java b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
index ae76708..cad7b4c 100755
--- a/src/com/android/server/telecom/components/UserCallIntentProcessor.java
+++ b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
@@ -80,11 +80,6 @@
*/
public void processIntent(Intent intent, String callingPackageName,
boolean canCallNonEmergency, boolean isLocalInvocation) {
- // Ensure call intents are not processed on devices that are not capable of calling.
- if (!isVoiceCapable()) {
- return;
- }
-
String action = intent.getAction();
if (Intent.ACTION_CALL.equals(action) ||
@@ -160,16 +155,6 @@
}
/**
- * Returns whether the device is voice-capable (e.g. a phone vs a tablet).
- *
- * @return {@code True} if the device is voice-capable.
- */
- private boolean isVoiceCapable() {
- return ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE))
- .isVoiceCapable();
- }
-
- /**
* Potentially trampolines the intent to Telecom via TelecomServiceImpl.
* If the caller is local to the Telecom service, we send the intent to Telecom without
* sending it through TelecomServiceImpl.
diff --git a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
index 03a5b43..6b97f97 100644
--- a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
+++ b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
@@ -268,7 +268,9 @@
createClearMissedCallsPendingIntent(userHandle))
.putExtra(TelecomManager.EXTRA_NOTIFICATION_COUNT, missedCallCount)
.putExtra(TelecomManager.EXTRA_NOTIFICATION_PHONE_NUMBER,
- callInfo == null ? null : callInfo.getPhoneNumber());
+ callInfo == null ? null : callInfo.getPhoneNumber())
+ .putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+ callInfo == null ? null : callInfo.getPhoneAccountHandle());
if (missedCallCount == 1 && callInfo != null) {
final Uri handleUri = callInfo.getHandle();
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java b/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
index f011f0c..a9851bf 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
@@ -367,7 +367,6 @@
.thenReturn(Arrays.asList(device2, null));
mBluetoothDeviceManager.disconnectAudio();
- verify(mAdapter).removeActiveDevice(BluetoothAdapter.ACTIVE_DEVICE_ALL);
verify(mBluetoothHeadset).disconnectAudio();
}
diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
index da72933..6fd8334 100644
--- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
@@ -1625,6 +1625,57 @@
verify(callSpy, never()).setDisconnectCause(any(DisconnectCause.class));
}
+ @Test
+ public void testIsInSelfManagedCallOnlyManaged() {
+ Call managedCall = createCall(SIM_1_HANDLE, CallState.ACTIVE);
+ managedCall.setIsSelfManaged(false);
+ mCallsManager.addCall(managedCall);
+
+ // Certainly nothing from the self managed handle.
+ assertFalse(mCallsManager.isInSelfManagedCall(
+ SELF_MANAGED_HANDLE.getComponentName().getPackageName(),
+ SELF_MANAGED_HANDLE.getUserHandle()));
+ // And nothing in a random other package.
+ assertFalse(mCallsManager.isInSelfManagedCall(
+ "com.foo",
+ SELF_MANAGED_HANDLE.getUserHandle()));
+ // And this method is only checking self managed not managed.
+ assertFalse(mCallsManager.isInSelfManagedCall(
+ SIM_1_HANDLE.getComponentName().getPackageName(),
+ SELF_MANAGED_HANDLE.getUserHandle()));
+ }
+
+ @Test
+ public void testIsInSelfManagedCallOnlySelfManaged() {
+ Call selfManagedCall = createCall(SELF_MANAGED_HANDLE, CallState.ACTIVE);
+ selfManagedCall.setIsSelfManaged(true);
+ mCallsManager.addCall(selfManagedCall);
+
+ assertTrue(mCallsManager.isInSelfManagedCall(
+ SELF_MANAGED_HANDLE.getComponentName().getPackageName(),
+ SELF_MANAGED_HANDLE.getUserHandle()));
+ assertFalse(mCallsManager.isInSelfManagedCall(
+ "com.foo",
+ SELF_MANAGED_HANDLE.getUserHandle()));
+ assertFalse(mCallsManager.isInSelfManagedCall(
+ SIM_1_HANDLE.getComponentName().getPackageName(),
+ SELF_MANAGED_HANDLE.getUserHandle()));
+
+ Call managedCall = createCall(SIM_1_HANDLE, CallState.ACTIVE);
+ managedCall.setIsSelfManaged(false);
+ mCallsManager.addCall(managedCall);
+
+ // Still not including managed
+ assertFalse(mCallsManager.isInSelfManagedCall(
+ SIM_1_HANDLE.getComponentName().getPackageName(),
+ SELF_MANAGED_HANDLE.getUserHandle()));
+
+ // Also shouldn't be something in another user's version of the same package.
+ assertFalse(mCallsManager.isInSelfManagedCall(
+ SELF_MANAGED_HANDLE.getComponentName().getPackageName(),
+ new UserHandle(90210)));
+ }
+
private Call addSpyCall() {
return addSpyCall(SIM_2_HANDLE, CallState.ACTIVE);
}
diff --git a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
index 47a6177..023b368 100644
--- a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
@@ -540,7 +540,7 @@
private final NotificationManager mNotificationManager = mock(NotificationManager.class);
private final UserManager mUserManager = mock(UserManager.class);
private final StatusBarManager mStatusBarManager = mock(StatusBarManager.class);
- private final SubscriptionManager mSubscriptionManager = mock(SubscriptionManager.class);
+ private SubscriptionManager mSubscriptionManager = mock(SubscriptionManager.class);
private final CarrierConfigManager mCarrierConfigManager = mock(CarrierConfigManager.class);
private final CountryDetector mCountryDetector = mock(CountryDetector.class);
private final Map<String, IContentProvider> mIContentProviderByUri = new HashMap<>();
@@ -735,6 +735,10 @@
mTelecomManager = telecomManager;
}
+ public void setSubscriptionManager(SubscriptionManager subscriptionManager) {
+ mSubscriptionManager = subscriptionManager;
+ }
+
public TelephonyManager getTelephonyManager() {
return mTelephonyManager;
}
diff --git a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
index 8cdb66e..ffa08e2 100644
--- a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
+++ b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
@@ -51,6 +51,8 @@
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.test.suitebuilder.annotation.MediumTest;
import android.util.Xml;
@@ -83,6 +85,7 @@
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -98,6 +101,7 @@
private final String COMPONENT_NAME = "com.android.server.telecom.tests.MockConnectionService";
private final TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() { };
private PhoneAccountRegistrar mRegistrar;
+ @Mock private SubscriptionManager mSubscriptionManager;
@Mock private TelecomManager mTelecomManager;
@Mock private DefaultDialerCache mDefaultDialerCache;
@Mock private AppLabelProxy mAppLabelProxy;
@@ -108,6 +112,7 @@
super.setUp();
MockitoAnnotations.initMocks(this);
mComponentContextFixture.setTelecomManager(mTelecomManager);
+ mComponentContextFixture.setSubscriptionManager(mSubscriptionManager);
new File(
mComponentContextFixture.getTestDouble().getApplicationContext().getFilesDir(),
FILE_NAME)
@@ -1226,6 +1231,29 @@
clearInvocations(mComponentContextFixture.getTelephonyManager());
}
+ /**
+ * Test PhoneAccountHandle Migration Logic.
+ */
+ @Test
+ public void testPhoneAccountMigration() throws Exception {
+ PhoneAccountRegistrar.State testState = makeQuickStateWithTelephonyPhoneAccountHandle();
+ final int mTestPhoneAccountHandleSubIdInt = 123;
+ // Mock SubscriptionManager
+ SubscriptionInfo subscriptionInfo = new SubscriptionInfo(
+ mTestPhoneAccountHandleSubIdInt, "id0", 1, "a", "b", 1, 1, "test",
+ 1, null, null, null, null, false, null, null);
+ List<SubscriptionInfo> subscriptionInfoList = new ArrayList<>();
+ subscriptionInfoList.add(subscriptionInfo);
+ when(mSubscriptionManager.getAllSubscriptionInfoList()).thenReturn(subscriptionInfoList);
+ mRegistrar.migratePhoneAccountHandle(testState);
+ Collection<DefaultPhoneAccountHandle> defaultPhoneAccountHandles
+ = testState.defaultOutgoingAccountHandles.values();
+ DefaultPhoneAccountHandle defaultPhoneAccountHandle
+ = defaultPhoneAccountHandles.iterator().next();
+ assertEquals(Integer.toString(mTestPhoneAccountHandleSubIdInt),
+ defaultPhoneAccountHandle.phoneAccountHandle.getId());
+ }
+
private static ComponentName makeQuickConnectionServiceComponentName() {
return new ComponentName(
"com.android.server.telecom.tests",
@@ -1447,6 +1475,25 @@
}
}
+ private PhoneAccountRegistrar.State makeQuickStateWithTelephonyPhoneAccountHandle() {
+ PhoneAccountRegistrar.State s = new PhoneAccountRegistrar.State();
+ s.accounts.add(makeQuickAccount("id0", 0));
+ s.accounts.add(makeQuickAccount("id1", 1));
+ s.accounts.add(makeQuickAccount("id2", 2));
+ PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle(new ComponentName(
+ "com.android.phone",
+ "com.android.services.telephony.TelephonyConnectionService"), "id0");
+ UserHandle userHandle = phoneAccountHandle.getUserHandle();
+ when(UserManager.get(mContext).getSerialNumberForUser(userHandle))
+ .thenReturn(0L);
+ when(UserManager.get(mContext).getUserForSerialNumber(0L))
+ .thenReturn(userHandle);
+ s.defaultOutgoingAccountHandles
+ .put(userHandle, new DefaultPhoneAccountHandle(userHandle, phoneAccountHandle,
+ "testGroup"));
+ return s;
+ }
+
private PhoneAccountRegistrar.State makeQuickState() {
PhoneAccountRegistrar.State s = new PhoneAccountRegistrar.State();
s.accounts.add(makeQuickAccount("id0", 0));
diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
index b4f0c4b..210f80e 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
@@ -199,10 +199,6 @@
super.setUp();
mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
- TelephonyManager mockTelephonyManager =
- (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
- 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),
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index 0991f36..d6ff196 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -573,9 +573,6 @@
com.android.server.telecom.R.string.incall_default_class,
mInCallServiceComponentNameX.getClassName());
- doReturn(true).when(mComponentContextFixture.getTelephonyManager())
- .isVoiceCapable();
-
mInCallServiceFixtureX = new InCallServiceFixture();
mInCallServiceFixtureY = new InCallServiceFixture();