Merge "Added read phone state permission for getNetworkCountryIso"
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index c5b4875..18ff034 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -194,7 +194,7 @@
case EVENT_SYSTEM_UNLOCKED:
{
- for (int i = 0; i < TelephonyManager.from(mContext).getPhoneCount(); ++i) {
+ for (int i = 0; i < TelephonyManager.from(mContext).getMaxPhoneCount(); ++i) {
// When user unlock device, we should only try to send broadcast again if we
// have sent it before unlock. This will avoid we try to load carrier config
// when SIM is still loading when unlock happens.
@@ -211,7 +211,7 @@
// Only update if there are cached config removed to avoid updating config for
// unrelated packages.
if (clearCachedConfigForPackage(carrierPackageName)) {
- int numPhones = TelephonyManager.from(mContext).getPhoneCount();
+ int numPhones = TelephonyManager.from(mContext).getMaxPhoneCount();
for (int i = 0; i < numPhones; ++i) {
updateConfigForPhoneId(i);
}
@@ -523,7 +523,7 @@
pkgFilter.addDataScheme("package");
context.registerReceiver(mPackageReceiver, pkgFilter);
- int numPhones = TelephonyManager.from(context).getPhoneCount();
+ int numPhones = TelephonyManager.from(context).getMaxPhoneCount();
mConfigFromDefaultApp = new PersistableBundle[numPhones];
mConfigFromCarrierApp = new PersistableBundle[numPhones];
mOverrideConfigs = new PersistableBundle[numPhones];
@@ -566,6 +566,13 @@
configPackagename = mPlatformCarrierConfigPackage;
configToSend = mConfigFromDefaultApp[phoneId];
}
+
+ // mOverrideConfigs is for testing. And it will override current configs.
+ PersistableBundle config = mOverrideConfigs[phoneId];
+ if (config != null) {
+ configToSend.putAll(config);
+ }
+
mSubscriptionInfoUpdater.updateSubscriptionByCarrierConfigAndNotifyComplete(
phoneId, configPackagename, configToSend,
mHandler.obtainMessage(EVENT_SUBSCRIPTION_INFO_UPDATED, phoneId, -1));
diff --git a/src/com/android/phone/EmergencyCallbackModeExitDialog.java b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
index 2492f46..dcfa024 100644
--- a/src/com/android/phone/EmergencyCallbackModeExitDialog.java
+++ b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
@@ -68,6 +68,7 @@
private boolean mInEmergencyCall = false;
private static final int ECM_TIMER_RESET = 1;
private Phone mPhone = null;
+ private boolean mIsResumed = false;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -100,6 +101,18 @@
}
@Override
+ public void onResume() {
+ super.onResume();
+ mIsResumed = true;
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mIsResumed = false;
+ }
+
+ @Override
public void onDestroy() {
super.onDestroy();
try {
@@ -176,7 +189,7 @@
* Shows Emergency Callback Mode dialog and starts countdown timer
*/
private void showEmergencyCallbackModeExitDialog() {
- if (!this.isResumed()) {
+ if (!mIsResumed) {
Log.w(TAG, "Tried to show dialog, but activity was already finished");
return;
}
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 29fff0d..8094812 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -39,7 +39,6 @@
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.os.UpdateLock;
import android.os.UserManager;
import android.preference.PreferenceManager;
import android.provider.Settings;
@@ -187,8 +186,6 @@
private PowerManager.WakeLock mPartialWakeLock;
private KeyguardManager mKeyguardManager;
- private UpdateLock mUpdateLock;
-
private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private final LocalLog mDataRoamingNotifLog = new LocalLog(50);
@@ -347,12 +344,6 @@
mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
- // Get UpdateLock to suppress system-update related events (e.g. dialog show-up)
- // during phone calls.
- mUpdateLock = new UpdateLock("phone");
-
- if (DBG) Log.d(LOG_TAG, "onCreate: mUpdateLock: " + mUpdateLock);
-
// Create the CallerInfoCache singleton, which remembers custom ring tone and
// send-to-voicemail settings.
//
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index cd4509a..a847d66 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -61,6 +61,7 @@
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
+import android.telephony.Annotation.ApnType;
import android.telephony.CarrierConfigManager;
import android.telephony.CarrierRestrictionRules;
import android.telephony.CellInfo;
@@ -92,7 +93,6 @@
import android.telephony.VisualVoicemailSmsFilterSettings;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.data.ApnSetting;
-import android.telephony.data.ApnSetting.ApnType;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.gsm.GsmCellLocation;
import android.telephony.ims.ImsException;
@@ -2882,18 +2882,19 @@
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
}
- Binder.withCleanCallingIdentity(() -> {
- try {
- // TODO: Refactor to remove ImsManager dependence and query through ImsPhone.
- ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
- .removeRegistrationCallbackForSubscription(c, subId);
- } catch (ImsException e) {
- Log.i(LOG_TAG, "unregisterImsRegistrationCallback: " + subId
- + "is inactive, ignoring unregister.");
- // If the subscription is no longer active, just return, since the callback
- // will already have been removed internally.
- }
- });
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // TODO: Refactor to remove ImsManager dependence and query through ImsPhone.
+ ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
+ .removeRegistrationCallbackForSubscription(c, subId);
+ } catch (ImsException e) {
+ Log.i(LOG_TAG, "unregisterImsRegistrationCallback: " + subId
+ + "is inactive, ignoring unregister.");
+ // If the subscription is no longer active, just return, since the callback
+ // will already have been removed internally.
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
@Override
@@ -2915,22 +2916,23 @@
@Override
public void unregisterMmTelCapabilityCallback(int subId, IImsCapabilityCallback c) {
enforceReadPrivilegedPermission("unregisterMmTelCapabilityCallback");
-
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
}
- Binder.withCleanCallingIdentity(() -> {
- try {
- // TODO: Refactor to remove ImsManager dependence and query through ImsPhone.
- ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // TODO: Refactor to remove ImsManager dependence and query through ImsPhone.
+ ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
.removeCapabilitiesCallbackForSubscription(c, subId);
- } catch (ImsException e) {
- Log.i(LOG_TAG, "unregisterMmTelCapabilityCallback: " + subId
- + "is inactive, ignoring unregister.");
- // If the subscription is no longer active, just return, since the callback
- // will already have been removed internally.
- }
- });
+ } catch (ImsException e) {
+ Log.i(LOG_TAG, "unregisterMmTelCapabilityCallback: " + subId
+ + "is inactive, ignoring unregister.");
+ // If the subscription is no longer active, just return, since the callback
+ // will already have been removed internally.
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
@Override
diff --git a/src/com/android/services/telephony/EmergencyTonePlayer.java b/src/com/android/services/telephony/EmergencyTonePlayer.java
index 8e26349..431f8d7 100644
--- a/src/com/android/services/telephony/EmergencyTonePlayer.java
+++ b/src/com/android/services/telephony/EmergencyTonePlayer.java
@@ -23,7 +23,6 @@
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.ToneGenerator;
-import android.os.SystemVibrator;
import android.os.Vibrator;
import android.provider.Settings;
@@ -49,11 +48,9 @@
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
.build();
- // We don't rely on getSystemService(Context.VIBRATOR_SERVICE) to make sure that this vibrator
- // object will be isolated from others.
- private final Vibrator mVibrator = new SystemVibrator();
private final Context mContext;
private final AudioManager mAudioManager;
+ private final Vibrator mVibrator;
private ToneGenerator mToneGenerator;
private int mSavedInCallVolume;
@@ -62,6 +59,7 @@
EmergencyTonePlayer(Context context) {
mContext = context;
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
}
public void start() {
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index bf0374f..e14f422 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -847,7 +847,7 @@
// If the single party call emulation fature flag is enabled, we can potentially treat
// the conference as a single party call when there is just one participant.
if (mFeatureFlagProxy.isUsingSinglePartyCallEmulation()) {
- if (oldParticipantCount > 1 && newParticipantCount == 1) {
+ if (oldParticipantCount != 1 && newParticipantCount == 1) {
// If number of participants goes to 1, emulate a single party call.
startEmulatingSinglePartyCall();
} else if (mIsEmulatingSinglePartyCall && !isSinglePartyConference) {
@@ -1330,4 +1330,12 @@
return isMaximumConferenceSizeEnforced()
&& getNumberOfParticipants() >= getMaximumConferenceSize();
}
+
+ /**
+ * @return {@code True} if the ImsConference is emulating single party call.
+ */
+ @VisibleForTesting
+ public boolean isEmulatingSinglePartyCall() {
+ return mIsEmulatingSinglePartyCall;
+ }
}
diff --git a/src/com/android/services/telephony/RadioOnHelper.java b/src/com/android/services/telephony/RadioOnHelper.java
index 288c72c..85f94ab 100644
--- a/src/com/android/services/telephony/RadioOnHelper.java
+++ b/src/com/android/services/telephony/RadioOnHelper.java
@@ -53,7 +53,7 @@
return;
}
mListeners = new ArrayList<>(2);
- for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
+ for (int i = 0; i < TelephonyManager.getDefault().getMaxPhoneCount(); i++) {
mListeners.add(new RadioOnStateListener());
}
}
@@ -76,7 +76,7 @@
mCallback = callback;
mInProgressListeners.clear();
mIsRadioOnCallingEnabled = false;
- for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
+ for (int i = 0; i < TelephonyManager.getDefault().getMaxPhoneCount(); i++) {
Phone phone = PhoneFactory.getPhone(i);
if (phone == null) {
continue;
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 927b2c9..0e5a612 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -25,6 +25,9 @@
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
import android.provider.Settings;
import android.telecom.Conference;
import android.telecom.Connection;
@@ -176,6 +179,8 @@
// destroyed.
@VisibleForTesting
public Pair<WeakReference<TelephonyConnection>, Queue<Phone>> mEmergencyRetryCache;
+ private Handler mDdsSwitchHandler;
+ private HandlerThread mHandlerThread;
/**
* Keeps track of the status of a SIM slot.
@@ -329,11 +334,17 @@
IntentFilter intentFilter = new IntentFilter(
TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED);
registerReceiver(mTtyBroadcastReceiver, intentFilter);
+
+ mHandlerThread = new HandlerThread("DdsSwitchHandlerThread");
+ mHandlerThread.start();
+ Looper looper = mHandlerThread.getLooper();
+ mDdsSwitchHandler = new Handler(looper);
}
@Override
public boolean onUnbind(Intent intent) {
unregisterReceiver(mTtyBroadcastReceiver);
+ mHandlerThread.quitSafely();
return super.onUnbind(intent);
}
@@ -523,14 +534,14 @@
} else {
final Connection resultConnection = getTelephonyConnection(request, numberToDial,
true, handle, phone);
- CompletableFuture<Boolean> phoneFuture = delayDialForDdsSwitch(phone);
- phoneFuture.whenComplete((result, error) -> {
- if (error != null) {
- Log.w(this, "onCreateOutgoingConn - delayDialForDdsSwitch exception= "
- + error.getMessage());
+ mDdsSwitchHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ boolean result = delayDialForDdsSwitch(phone);
+ Log.i(this,
+ "onCreateOutgoingConn - delayDialForDdsSwitch result = " + result);
+ placeOutgoingConnection(request, resultConnection, phone);
}
- Log.i(this, "onCreateOutgoingConn - delayDialForDdsSwitch result = " + result);
- placeOutgoingConnection(request, resultConnection, phone);
});
return resultConnection;
}
@@ -604,14 +615,14 @@
adjustAndPlaceOutgoingConnection(phone, originalConnection, request, numberToDial,
handle, originalPhoneType, false);
} else {
- delayDialForDdsSwitch(phone).whenComplete((result, error) -> {
- if (error != null) {
- Log.w(this, "handleOnComplete - delayDialForDdsSwitch exception= "
- + error.getMessage());
+ mDdsSwitchHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ boolean result = delayDialForDdsSwitch(phone);
+ Log.i(this, "handleOnComplete - delayDialForDdsSwitch result = " + result);
+ adjustAndPlaceOutgoingConnection(phone, originalConnection, request,
+ numberToDial, handle, originalPhoneType, true);
}
- Log.i(this, "handleOnComplete - delayDialForDdsSwitch result = " + result);
- adjustAndPlaceOutgoingConnection(phone, originalConnection, request,
- numberToDial, handle, originalPhoneType, true);
});
}
@@ -1234,6 +1245,11 @@
com.android.internal.telephony.Connection originalConnection = null;
try {
if (phone != null) {
+ EmergencyNumber emergencyNumber =
+ phone.getEmergencyNumberTracker().getEmergencyNumber(number);
+ if (emergencyNumber != null) {
+ phone.notifyOutgoingEmergencyCall(emergencyNumber);
+ }
originalConnection = phone.dial(number, new ImsPhone.ImsDialArgs.Builder()
.setVideoState(videoState)
.setIntentExtras(extras)
@@ -1375,13 +1391,22 @@
return chosenPhone;
}
- private CompletableFuture<Boolean> delayDialForDdsSwitch(Phone phone) {
+ /**
+ * If needed, block until the the default data is is switched for outgoing emergency call, or
+ * timeout expires.
+ */
+ private boolean delayDialForDdsSwitch(Phone phone) {
if (phone == null) {
- return CompletableFuture.completedFuture(Boolean.TRUE);
+ return true;
}
- return possiblyOverrideDefaultDataForEmergencyCall(phone)
- .completeOnTimeout(false, DEFAULT_DATA_SWITCH_TIMEOUT_MS,
- TimeUnit.MILLISECONDS);
+ try {
+ return possiblyOverrideDefaultDataForEmergencyCall(phone).get(
+ DEFAULT_DATA_SWITCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+ Log.w(this, "onCreateOutgoingConn - delayDialForDdsSwitch exception= "
+ + e.getMessage());
+ return false;
+ }
}
/**
diff --git a/tests/src/com/android/services/telephony/ImsConferenceTest.java b/tests/src/com/android/services/telephony/ImsConferenceTest.java
index eaec5b6..6f8b3e8 100644
--- a/tests/src/com/android/services/telephony/ImsConferenceTest.java
+++ b/tests/src/com/android/services/telephony/ImsConferenceTest.java
@@ -16,19 +16,16 @@
package com.android.services.telephony;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.times;
-
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.net.Uri;
import android.os.Looper;
@@ -39,15 +36,10 @@
import android.telecom.PhoneAccountHandle;
import android.test.suitebuilder.annotation.SmallTest;
-import com.android.internal.telephony.PhoneConstants;
-
import org.junit.Before;
import org.junit.Test;
-
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
import java.util.Arrays;
@@ -362,6 +354,31 @@
}
/**
+ * Verify that the single party emulate correctly when the conference start with only
+ * one participant.
+ */
+ @Test
+ @SmallTest
+ public void testSinglePartyEmulationWithOneParticipantAtBeginning() {
+ when(mMockTelecomAccountRegistry.isUsingSimCallManager(any(PhoneAccountHandle.class)))
+ .thenReturn(false);
+
+ 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,
+ Call.Details.DIRECTION_INCOMING);
+ imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
+ Arrays.asList(participant1));
+ assertTrue(imsConference.isEmulatingSinglePartyCall());
+ }
+
+ /**
* Verify that we do not use single party emulation when a sim call manager is in use.
*/
@Test