Merge "Internally use ImsException and rethrow as ServiceSpecificException"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1b2e99a..25018a3 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1249,6 +1249,8 @@
<br><br> - RTT calls are saved as a message transcript
<br> - RTT is not available for video calls</string>
+ <string name="no_rtt_when_roaming">Note: RTT is not available while roaming</string>
+
<!-- Service option entries. -->
<string-array name="tty_mode_entries">
<item>TTY Off</item>
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 8b74af4..4025bbb 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -20,7 +20,6 @@
import static android.service.carrier.CarrierService.ICarrierServiceWrapper.RESULT_ERROR;
import android.annotation.NonNull;
-import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -40,7 +39,6 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
-import android.os.UserHandle;
import android.preference.PreferenceManager;
import android.service.carrier.CarrierIdentifier;
import android.service.carrier.CarrierService;
@@ -514,7 +512,7 @@
pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
pkgFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
pkgFilter.addDataScheme("package");
- context.registerReceiverAsUser(mPackageReceiver, UserHandle.ALL, pkgFilter, null, null);
+ context.registerReceiver(mPackageReceiver, pkgFilter);
int numPhones = TelephonyManager.from(context).getPhoneCount();
mConfigFromDefaultApp = new PersistableBundle[numPhones];
@@ -592,7 +590,7 @@
}
intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, phoneId);
log("Broadcast CARRIER_CONFIG_CHANGED for phone " + phoneId);
- ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
+ mContext.sendBroadcast(intent);
mHasSentConfigChange[phoneId] = true;
}
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index fed41b0..04850f3 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -527,6 +527,9 @@
maybeTurnCellOn(context, isAirplaneNewlyOn);
break;
}
+ for (Phone phone : PhoneFactory.getPhones()) {
+ phone.getServiceStateTracker().onAirplaneModeChanged(isAirplaneNewlyOn);
+ }
}
/*
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index d546bf6..17067ec 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -1411,7 +1411,7 @@
// from the context of the phone app.
enforceCallPermission();
- if (mAppOps.noteOp(AppOpsManager.OP_CALL_PHONE, Binder.getCallingUid(), callingPackage)
+ if (mAppOps.noteOp(AppOpsManager.OPSTR_CALL_PHONE, Binder.getCallingUid(), callingPackage)
!= AppOpsManager.MODE_ALLOWED) {
return;
}
@@ -2025,14 +2025,18 @@
/**
* Returns the target SDK version number for a given package name.
*
+ * This call MUST be invoked before clearing the calling UID.
+ *
* @return target SDK if the package is found or INT_MAX.
*/
private int getTargetSdk(String packageName) {
try {
- final ApplicationInfo ai = mApp.getPackageManager().getApplicationInfo(
- packageName, 0);
+ final ApplicationInfo ai = mApp.getPackageManager().getApplicationInfoAsUser(
+ packageName, 0, UserHandle.getUserId(Binder.getCallingUid()));
if (ai != null) return ai.targetSdkVersion;
} catch (PackageManager.NameNotFoundException unexpected) {
+ loge("Failed to get package info for pkg="
+ + packageName + ", uid=" + Binder.getCallingUid());
}
return Integer.MAX_VALUE;
}
@@ -2046,7 +2050,7 @@
"getNeighboringCellInfo() is unavailable to callers targeting Q+ SDK levels.");
}
- if (mAppOps.noteOp(AppOpsManager.OP_NEIGHBORING_CELLS, Binder.getCallingUid(),
+ if (mAppOps.noteOp(AppOpsManager.OPSTR_NEIGHBORING_CELLS, Binder.getCallingUid(),
callingPackage) != AppOpsManager.MODE_ALLOWED) {
return null;
}
diff --git a/src/com/android/phone/settings/AccessibilitySettingsFragment.java b/src/com/android/phone/settings/AccessibilitySettingsFragment.java
index d540fba..3069091 100644
--- a/src/com/android/phone/settings/AccessibilitySettingsFragment.java
+++ b/src/com/android/phone/settings/AccessibilitySettingsFragment.java
@@ -28,11 +28,13 @@
import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.Log;
import com.android.ims.ImsManager;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.SubscriptionController;
import com.android.phone.PhoneGlobals;
import com.android.phone.R;
@@ -109,10 +111,14 @@
mButtonHac = null;
}
- if (PhoneGlobals.getInstance().phoneMgr
- .isRttSupported(SubscriptionManager.getDefaultVoiceSubscriptionId())) {
+ if (shouldShowRttSetting()) {
// TODO: this is going to be a on/off switch for now. Ask UX about how to integrate
// this settings with TTY
+ if (TelephonyManager.getDefault().isNetworkRoaming(
+ SubscriptionManager.getDefaultVoiceSubscriptionId())) {
+ mButtonRtt.setSummary(TextUtils.concat(getText(R.string.rtt_mode_summary), "\n",
+ getText(R.string.no_rtt_when_roaming)));
+ }
boolean rttOn = Settings.Secure.getInt(
mContext.getContentResolver(), Settings.Secure.RTT_CALLING_MODE, 0) != 0;
mButtonRtt.setChecked(rttOn);
@@ -192,6 +198,21 @@
return false;
}
+ private boolean shouldShowRttSetting() {
+ int subscriptionId = SubscriptionManager.getDefaultVoiceSubscriptionId();
+ if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID
+ || subscriptionId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
+ for (int subId : SubscriptionController.getInstance().getActiveSubIdList(true)) {
+ if (PhoneGlobals.getInstance().phoneMgr.isRttSupported(subId)) {
+ return true;
+ }
+ }
+ return false;
+ } else {
+ return PhoneGlobals.getInstance().phoneMgr.isRttSupported(subscriptionId);
+ }
+ }
+
/**
* Determines if the device supports TTY per carrier config.
* @return {@code true} if the carrier supports TTY, {@code false} otherwise.
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index 1f157e3..8ef0464 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -259,6 +259,8 @@
private boolean mCouldManageConference;
private FeatureFlagProxy mFeatureFlagProxy;
private boolean mIsEmulatingSinglePartyCall = false;
+ private boolean mIsUsingSimCallManager = false;
+
/**
* Where {@link #mIsEmulatingSinglePartyCall} is {@code true}, contains the
* {@link ConferenceParticipantConnection#getUserEntity()} and
@@ -616,6 +618,7 @@
private void updateManageConference() {
boolean couldManageConference = can(Connection.CAPABILITY_MANAGE_CONFERENCE);
boolean canManageConference = mFeatureFlagProxy.isUsingSinglePartyCallEmulation()
+ && mIsEmulatingSinglePartyCall
? mConferenceParticipantConnections.size() > 1
: mConferenceParticipantConnections.size() != 0;
Log.v(this, "updateManageConference was :%s is:%s", couldManageConference ? "Y" : "N",
@@ -675,6 +678,9 @@
mConferenceHostAddress = new Uri[hostAddresses.size()];
mConferenceHostAddress = hostAddresses.toArray(mConferenceHostAddress);
+
+ mIsUsingSimCallManager = mTelecomAccountRegistry.isUsingSimCallManager(
+ mConferenceHostPhoneAccountHandle);
}
mConferenceHost.addConnectionListener(mConferenceHostListener);
@@ -829,8 +835,18 @@
* 1. Tell telecom we're a conference again.
* 2. Restore {@link Connection#CAPABILITY_MANAGE_CONFERENCE} capability.
* 3. Null out the name/address.
+ *
+ * Note: Single party call emulation is disabled if the conference is taking place via a
+ * sim call manager. Emulating a single party call requires properties of the conference to be
+ * changed (connect time, address, conference state) which cannot be guaranteed to be relayed
+ * correctly by the sim call manager to Telecom.
*/
private void stopEmulatingSinglePartyCall() {
+ if (mIsUsingSimCallManager) {
+ Log.i(this, "stopEmulatingSinglePartyCall: using sim call manager; skip.");
+ return;
+ }
+
Log.i(this, "stopEmulatingSinglePartyCall: conference now has more than one"
+ " participant; make it look conference-like again.");
mIsEmulatingSinglePartyCall = false;
@@ -867,8 +883,18 @@
* 2. Tell telecom we're not a conference.
* 3. Remove {@link Connection#CAPABILITY_MANAGE_CONFERENCE} capability.
* 4. Set the name/address to that of the single participant.
+ *
+ * Note: Single party call emulation is disabled if the conference is taking place via a
+ * sim call manager. Emulating a single party call requires properties of the conference to be
+ * changed (connect time, address, conference state) which cannot be guaranteed to be relayed
+ * correctly by the sim call manager to Telecom.
*/
private void startEmulatingSinglePartyCall() {
+ if (mIsUsingSimCallManager) {
+ Log.i(this, "startEmulatingSinglePartyCall: using sim call manager; skip.");
+ return;
+ }
+
Log.i(this, "startEmulatingSinglePartyCall: conference has a single "
+ "participant; downgrade to single party call.");
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index b12fc06..3505fe7 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -98,6 +98,7 @@
private boolean mIsVideoConferencingSupported;
private boolean mIsMergeOfWifiCallsAllowedWhenVoWifiOff;
private boolean mIsManageImsConferenceCallSupported;
+ private boolean mIsUsingSimCallManager;
private boolean mIsShowPreciseFailedCause;
AccountEntry(Phone phone, boolean isEmergency, boolean isDummy) {
@@ -350,6 +351,7 @@
mIsMergeOfWifiCallsAllowedWhenVoWifiOff =
isCarrierMergeOfWifiCallsAllowedWhenVoWifiOff();
mIsManageImsConferenceCallSupported = isCarrierManageImsConferenceCallSupported();
+ mIsUsingSimCallManager = isCarrierUsingSimCallManager();
mIsShowPreciseFailedCause = isCarrierShowPreciseFailedCause();
if (isEmergency && mContext.getResources().getBoolean(
@@ -581,6 +583,19 @@
}
/**
+ * Determines from carrier config whether the carrier uses a sim call manager.
+ *
+ * @return {@code true} if the carrier uses a sim call manager,
+ * {@code false} otherwise.
+ */
+ private boolean isCarrierUsingSimCallManager() {
+ PersistableBundle b =
+ PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
+ return !TextUtils.isEmpty(
+ b.getString(CarrierConfigManager.KEY_DEFAULT_SIM_CALL_MANAGER_STRING));
+ }
+
+ /**
* Determines from carrier config whether showing percise call diconnect cause to user
* is supported.
*
@@ -731,6 +746,15 @@
}
/**
+ * Indicates whether this account uses a sim call manger.
+ * @return {@code true} if the account uses a sim call manager,
+ * {@code false} otherwise.
+ */
+ public boolean isUsingSimCallManager() {
+ return mIsUsingSimCallManager;
+ }
+
+ /**
* Indicates whether this account supports showing the precise call disconnect cause
* to user (i.e. conferencing).
* @return {@code true} if the account supports showing the precise call disconnect cause,
@@ -1003,7 +1027,7 @@
* @param handle The phone account handle to find the subscription address for.
* @return The address.
*/
- Uri getAddress(PhoneAccountHandle handle) {
+ public Uri getAddress(PhoneAccountHandle handle) {
synchronized (mAccountsLock) {
for (AccountEntry entry : mAccounts) {
if (entry.getPhoneAccountHandle().equals(handle)) {
@@ -1015,6 +1039,24 @@
}
/**
+ * Returns whethere a the subscription associated with a {@link PhoneAccountHandle} is using a
+ * sim call manager.
+ *
+ * @param handle The phone account handle to find the subscription address for.
+ * @return {@code true} if a sim call manager is in use, {@code false} otherwise.
+ */
+ public boolean isUsingSimCallManager(PhoneAccountHandle handle) {
+ synchronized (mAccountsLock) {
+ for (AccountEntry entry : mAccounts) {
+ if (entry.getPhoneAccountHandle().equals(handle)) {
+ return entry.isUsingSimCallManager();
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
* Sets up all the phone accounts for SIMs on first boot.
*/
public void setupOnBoot() {
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 632e9ac..7bb6b7d 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -2203,7 +2203,6 @@
boolean isIms = phone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS;
boolean isVoWifiEnabled = false;
if (isIms) {
- ImsPhone imsPhone = (ImsPhone) phone;
isVoWifiEnabled = ImsUtil.isWfcEnabled(phone.getContext(), phone.getPhoneId());
}
PhoneAccountHandle phoneAccountHandle = isIms ? PhoneUtils
diff --git a/tests/src/com/android/services/telephony/ImsConferenceTest.java b/tests/src/com/android/services/telephony/ImsConferenceTest.java
index 56a6240..909ab65 100644
--- a/tests/src/com/android/services/telephony/ImsConferenceTest.java
+++ b/tests/src/com/android/services/telephony/ImsConferenceTest.java
@@ -32,6 +32,7 @@
import android.os.Looper;
import android.telecom.ConferenceParticipant;
import android.telecom.Connection;
+import android.telecom.PhoneAccountHandle;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.internal.telephony.PhoneConstants;
@@ -53,9 +54,6 @@
@Mock
private TelecomAccountRegistry mMockTelecomAccountRegistry;
- @Mock
- private com.android.internal.telephony.Connection mOriginalConnection;
-
private TestTelephonyConnection mConferenceHost;
@Before
@@ -66,11 +64,16 @@
}
mConferenceHost = new TestTelephonyConnection();
mConferenceHost.setManageImsConferenceCallSupported(true);
+ when(mMockTelecomAccountRegistry.getAddress(any(PhoneAccountHandle.class)))
+ .thenReturn(null);
}
@Test
@SmallTest
public void testSinglePartyEmulation() {
+ when(mMockTelecomAccountRegistry.isUsingSimCallManager(any(PhoneAccountHandle.class)))
+ .thenReturn(false);
+
ImsConference imsConference = new ImsConference(mMockTelecomAccountRegistry,
mMockTelephonyConnectionServiceProxy, mConferenceHost,
null /* phoneAccountHandle */, () -> true /* featureFlagProxy */);
@@ -100,9 +103,51 @@
assertEquals(2, imsConference.getNumberOfParticipants());
}
+ /**
+ * Verify that we do not use single party emulation when a sim call manager is in use.
+ */
+ @Test
+ @SmallTest
+ public void testNoSinglePartyEmulationWithSimCallManager() {
+ // Make it look like there is a sim call manager in use.
+ when(mMockTelecomAccountRegistry.isUsingSimCallManager(
+ any(PhoneAccountHandle.class))).thenReturn(true);
+
+ ImsConference imsConference = new ImsConference(mMockTelecomAccountRegistry,
+ mMockTelephonyConnectionServiceProxy, mConferenceHost,
+ null /* phoneAccountHandle */, () -> true /* featureFlagProxy */);
+
+ ConferenceParticipant participant1 = new ConferenceParticipant(
+ Uri.parse("tel:6505551212"),
+ "A",
+ Uri.parse("sip:6505551212@testims.com"),
+ Connection.STATE_ACTIVE);
+ ConferenceParticipant participant2 = new ConferenceParticipant(
+ Uri.parse("tel:6505551213"),
+ "A",
+ Uri.parse("sip:6505551213@testims.com"),
+ Connection.STATE_ACTIVE);
+ imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
+ Arrays.asList(participant1, participant2));
+ assertEquals(2, imsConference.getNumberOfParticipants());
+
+ // Because we're not using single party emulation, should still be one participant.
+ imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
+ Arrays.asList(participant1));
+ assertEquals(1, imsConference.getNumberOfParticipants());
+
+ // Back to 2!
+ imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
+ Arrays.asList(participant1, participant2));
+ assertEquals(2, imsConference.getNumberOfParticipants());
+ }
+
@Test
@SmallTest
public void testNormalConference() {
+ when(mMockTelecomAccountRegistry.isUsingSimCallManager(any(PhoneAccountHandle.class)))
+ .thenReturn(false);
+
ImsConference imsConference = new ImsConference(mMockTelecomAccountRegistry,
mMockTelephonyConnectionServiceProxy, mConferenceHost,
null /* phoneAccountHandle */, () -> false /* featureFlagProxy */);
diff --git a/tests/src/com/android/services/telephony/TestTelephonyConnection.java b/tests/src/com/android/services/telephony/TestTelephonyConnection.java
index c064ef6..b6e4bf3 100644
--- a/tests/src/com/android/services/telephony/TestTelephonyConnection.java
+++ b/tests/src/com/android/services/telephony/TestTelephonyConnection.java
@@ -82,9 +82,11 @@
any(Connection.PostDialListener.class));
when(mMockPhone.getRingingCall()).thenReturn(mMockCall);
when(mMockPhone.getContext()).thenReturn(mMockContext);
+ when(mMockPhone.getCurrentSubscriberUris()).thenReturn(null);
when(mMockContext.getResources()).thenReturn(mMockResources);
when(mMockResources.getBoolean(anyInt())).thenReturn(false);
when(mMockPhone.getDefaultPhone()).thenReturn(mMockPhone);
+ when(mMockPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_IMS);
when(mMockCall.getState()).thenReturn(Call.State.ACTIVE);
when(mMockCall.getPhone()).thenReturn(mMockPhone);
}