Snap for 12385180 from 5977d4b00851037568a5b84daf015605e429a3e0 to 24Q4-release
Change-Id: Ibfe6da56e0383782db9c58541326fa17834c99c5
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index ea3dbab..53ef07e 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -2994,8 +2994,11 @@
public boolean needMobileRadioShutdown() {
enforceReadPrivilegedPermission("needMobileRadioShutdown");
- enforceTelephonyFeatureWithException(getCurrentPackageName(),
- PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS, "needMobileRadioShutdown");
+ if (!mApp.getResources().getBoolean(
+ com.android.internal.R.bool.config_force_phone_globals_creation)) {
+ enforceTelephonyFeatureWithException(getCurrentPackageName(),
+ PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS, "needMobileRadioShutdown");
+ }
/*
* If any of the Radios are available, it will need to be
@@ -7631,8 +7634,12 @@
public int getCarrierPrivilegeStatusForUid(int subId, int uid) {
enforceReadPrivilegedPermission("getCarrierPrivilegeStatusForUid");
- enforceTelephonyFeatureWithException(getCurrentPackageName(),
- PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION, "getCarrierPrivilegeStatusForUid");
+ if (!mApp.getResources().getBoolean(
+ com.android.internal.R.bool.config_force_phone_globals_creation)) {
+ enforceTelephonyFeatureWithException(getCurrentPackageName(),
+ PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION,
+ "getCarrierPrivilegeStatusForUid");
+ }
return getCarrierPrivilegeStatusForUidWithPermission(subId, uid);
}
@@ -7917,8 +7924,11 @@
return null;
}
- enforceTelephonyFeatureWithException(callingPackage,
- PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION, "getLine1NumberForDisplay");
+ if (!mApp.getResources().getBoolean(
+ com.android.internal.R.bool.config_force_phone_globals_creation)) {
+ enforceTelephonyFeatureWithException(callingPackage,
+ PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION, "getLine1NumberForDisplay");
+ }
final long identity = Binder.clearCallingIdentity();
try {
@@ -10400,8 +10410,11 @@
mApp, defaultPhone.getSubId(), "isEmergencyNumber(Potential)");
}
- enforceTelephonyFeatureWithException(getCurrentPackageName(),
- PackageManager.FEATURE_TELEPHONY_CALLING, "isEmergencyNumber");
+ if (!mApp.getResources().getBoolean(
+ com.android.internal.R.bool.config_force_phone_globals_creation)) {
+ enforceTelephonyFeatureWithException(getCurrentPackageName(),
+ PackageManager.FEATURE_TELEPHONY_CALLING, "isEmergencyNumber");
+ }
final long identity = Binder.clearCallingIdentity();
try {
diff --git a/src/com/android/services/telephony/PstnIncomingCallNotifier.java b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
index d58c211..3b74c6f 100644
--- a/src/com/android/services/telephony/PstnIncomingCallNotifier.java
+++ b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
@@ -82,30 +82,7 @@
/**
* Used to listen to events from {@link #mPhone}.
*/
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch(msg.what) {
- case EVENT_NEW_RINGING_CONNECTION:
- handleNewRingingConnection((AsyncResult) msg.obj);
- break;
- case EVENT_CDMA_CALL_WAITING:
- handleCdmaCallWaiting((AsyncResult) msg.obj);
- break;
- case EVENT_UNKNOWN_CONNECTION:
- handleNewUnknownConnection((AsyncResult) msg.obj);
- break;
- default:
- break;
- }
- }
-
- @Override
- public String toString() {
- return String.format("[PstnIncomingCallNotifierHandler; phoneId=[%s]",
- getPhoneIdAsString());
- }
- };
+ private final Handler mHandler;
/**
* Persists the specified parameters and starts listening to phone events.
@@ -118,6 +95,30 @@
}
mPhone = phone;
+ mHandler = new Handler(phone.getLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch(msg.what) {
+ case EVENT_NEW_RINGING_CONNECTION:
+ handleNewRingingConnection((AsyncResult) msg.obj);
+ break;
+ case EVENT_CDMA_CALL_WAITING:
+ handleCdmaCallWaiting((AsyncResult) msg.obj);
+ break;
+ case EVENT_UNKNOWN_CONNECTION:
+ handleNewUnknownConnection((AsyncResult) msg.obj);
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format("[PstnIncomingCallNotifierHandler; phoneId=[%s]",
+ getPhoneIdAsString());
+ }
+ };
registerForNotifications();
}
diff --git a/src/com/android/services/telephony/PstnPhoneCapabilitiesNotifier.java b/src/com/android/services/telephony/PstnPhoneCapabilitiesNotifier.java
index 4038dd1..e91af83 100644
--- a/src/com/android/services/telephony/PstnPhoneCapabilitiesNotifier.java
+++ b/src/com/android/services/telephony/PstnPhoneCapabilitiesNotifier.java
@@ -39,18 +39,7 @@
private final Phone mPhone;
private final Listener mListener;
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case EVENT_VIDEO_CAPABILITIES_CHANGED:
- handleVideoCapabilitesChanged((AsyncResult) msg.obj);
- break;
- default:
- break;
- }
- }
- };
+ private final Handler mHandler;
/*package*/
PstnPhoneCapabilitiesNotifier(Phone phone, Listener listener) {
@@ -59,6 +48,18 @@
}
mPhone = phone;
+ mHandler = new Handler(phone.getLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_VIDEO_CAPABILITIES_CHANGED:
+ handleVideoCapabilitesChanged((AsyncResult) msg.obj);
+ break;
+ default:
+ break;
+ }
+ }
+ };
mListener = listener;
registerForNotifications();
diff --git a/tests/src/com/android/services/telephony/TelecomAccountRegistryTest.java b/tests/src/com/android/services/telephony/TelecomAccountRegistryTest.java
new file mode 100644
index 0000000..13166a6
--- /dev/null
+++ b/tests/src/com/android/services/telephony/TelecomAccountRegistryTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.services.telephony;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.PersistableBundle;
+import android.os.UserHandle;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.telecom.PhoneAccount;
+import android.telecom.TelecomManager;
+import android.telephony.CarrierConfigManager;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+import android.telephony.TelephonyCallback;
+import android.telephony.TelephonyManager;
+import android.telephony.ims.ImsManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.TelephonyTestBase;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.flags.Flags;
+import com.android.phone.PhoneGlobals;
+import com.android.phone.PhoneInterfaceManager;
+import com.android.phone.R;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class TelecomAccountRegistryTest extends TelephonyTestBase {
+
+ private static final String TAG = "TelecomAccountRegistryTest";
+ private static final int TEST_SUB_ID = 1;
+
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ // We need more functions that what TelephonyTestBase.mContext supports.
+ // Use a local mocked Context to make life easier.
+ @Mock Context mMockedContext;
+ @Mock TelecomManager mTelecomManager;
+ @Mock TelephonyManager mTelephonyManager;
+ @Mock ImsManager mImsManager;
+ @Mock SubscriptionManager mSubscriptionManager;
+ @Mock ContentProvider mContentProvider;
+ @Mock PhoneGlobals mPhoneGlobals;
+ @Mock Phone mPhone;
+ @Mock Resources mResources;
+ @Mock Drawable mDrawable;
+ @Mock PhoneInterfaceManager mPhoneInterfaceManager;
+
+ private TelecomAccountRegistry mTelecomAccountRegistry;
+
+ private OnSubscriptionsChangedListener mOnSubscriptionsChangedListener;
+ private TelephonyCallback mTelephonyCallback;
+ private BroadcastReceiver mUserSwitchedAndConfigChangedReceiver;
+ private BroadcastReceiver mLocaleChangedBroadcastReceiver;
+ private ContentResolver mContentResolver;
+ private Phone[] mPhones;
+ private TestableLooper mTestableLooper;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ mSetFlagsRule.disableFlags(Flags.FLAG_DELAY_PHONE_ACCOUNT_REGISTRATION);
+ MockitoAnnotations.initMocks(this);
+
+ mPhones = new Phone[]{mPhone};
+ replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
+ replaceInstance(PhoneGlobals.class, "sMe", null, mPhoneGlobals);
+ replaceInstance(PhoneInterfaceManager.class, "sInstance", null, mPhoneInterfaceManager);
+ when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM);
+ when(mPhone.getContext()).thenReturn(mMockedContext);
+ when(mPhone.getSubId()).thenReturn(TEST_SUB_ID);
+ when(mPhoneInterfaceManager.isRttEnabled(anyInt())).thenReturn(false);
+
+ when(mMockedContext.getResources()).thenReturn(mResources);
+ // Enable PSTN PhoneAccount which can place emergency call by default
+ when(mResources.getBoolean(R.bool.config_pstn_phone_accounts_enabled)).thenReturn(true);
+ when(mResources.getBoolean(R.bool.config_pstnCanPlaceEmergencyCalls)).thenReturn(true);
+ when(mResources.getDrawable(anyInt(), any())).thenReturn(mDrawable);
+ when(mDrawable.getIntrinsicWidth()).thenReturn(5);
+ when(mDrawable.getIntrinsicHeight()).thenReturn(5);
+
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putBoolean(CarrierConfigManager.KEY_SUPPORT_IMS_CONFERENCE_CALL_BOOL, false);
+ bundle.putIntArray(CarrierConfigManager.KEY_CELLULAR_SERVICE_CAPABILITIES_INT_ARRAY,
+ new int[]{
+ SubscriptionManager.SERVICE_CAPABILITY_VOICE,
+ SubscriptionManager.SERVICE_CAPABILITY_SMS,
+ SubscriptionManager.SERVICE_CAPABILITY_DATA
+ });
+ when(mPhoneGlobals.getCarrierConfigForSubId(anyInt())).thenReturn(bundle);
+
+ // Mock system services used by TelecomAccountRegistry
+ when(mMockedContext.getSystemServiceName(TelecomManager.class))
+ .thenReturn(Context.TELECOM_SERVICE);
+ when(mMockedContext.getSystemService(TelecomManager.class))
+ .thenReturn(mTelecomManager);
+ when(mMockedContext.getSystemServiceName(TelephonyManager.class))
+ .thenReturn(Context.TELEPHONY_SERVICE);
+ when(mMockedContext.getSystemService(TelephonyManager.class))
+ .thenReturn(mTelephonyManager);
+ when(mMockedContext.getSystemServiceName(ImsManager.class))
+ .thenReturn(Context.TELEPHONY_IMS_SERVICE);
+ when(mMockedContext.getSystemService(ImsManager.class))
+ .thenReturn(mImsManager);
+ when(mMockedContext.getSystemServiceName(SubscriptionManager.class))
+ .thenReturn(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+ when(mMockedContext.getSystemService(SubscriptionManager.class))
+ .thenReturn(mSubscriptionManager);
+
+ // Use mocked ContentProvider since we can't really mock ContentResolver
+ mContentResolver = ContentResolver.wrap(mContentProvider);
+ when(mMockedContext.getContentResolver()).thenReturn(mContentResolver);
+
+ mTestableLooper = TestableLooper.get(this);
+ when(mMockedContext.getMainLooper()).thenReturn(mTestableLooper.getLooper());
+ mTelecomAccountRegistry = new TelecomAccountRegistry(mMockedContext);
+ mTelecomAccountRegistry.setupOnBoot();
+
+ // Capture OnSubscriptionsChangedListener
+ ArgumentCaptor<OnSubscriptionsChangedListener> subChangeListenerCaptor =
+ ArgumentCaptor.forClass(OnSubscriptionsChangedListener.class);
+ verify(mSubscriptionManager).addOnSubscriptionsChangedListener(
+ subChangeListenerCaptor.capture());
+ mOnSubscriptionsChangedListener = subChangeListenerCaptor.getValue();
+
+ // Capture TelephonyCallback
+ ArgumentCaptor<TelephonyCallback> telephonyCallbackArgumentCaptor =
+ ArgumentCaptor.forClass(TelephonyCallback.class);
+ verify(mTelephonyManager).registerTelephonyCallback(anyInt(), any(),
+ telephonyCallbackArgumentCaptor.capture());
+ mTelephonyCallback = telephonyCallbackArgumentCaptor.getValue();
+
+ // Capture BroadcastReceivers
+ ArgumentCaptor<BroadcastReceiver> broadcastReceiverArgumentCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mMockedContext, times(2)).registerReceiver(broadcastReceiverArgumentCaptor.capture(),
+ any());
+ mUserSwitchedAndConfigChangedReceiver =
+ broadcastReceiverArgumentCaptor.getAllValues().get(0);
+ mLocaleChangedBroadcastReceiver = broadcastReceiverArgumentCaptor.getAllValues().get(1);
+
+ mTestableLooper.processAllMessages();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void userSwitched_withPSTNAccount_shouldRegisterPSTNAccount() {
+ onUserSwitched(UserHandle.CURRENT);
+
+ PhoneAccount phoneAccount = verifyAndCaptureRegisteredPhoneAccount();
+
+ assertThat(phoneAccount.hasCapabilities(
+ PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)).isTrue();
+ assertThat(phoneAccount.hasCapabilities(
+ PhoneAccount.CAPABILITY_CALL_PROVIDER)).isTrue();
+ assertThat(phoneAccount.hasCapabilities(
+ PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)).isTrue();
+ }
+
+ @Test
+ public void onLocaleChanged_withPSTNAccountDisabled_shouldRegisterEmergencyOnlyAccount() {
+ when(mResources.getBoolean(R.bool.config_pstn_phone_accounts_enabled)).thenReturn(false);
+ when(mResources.getBoolean(
+ R.bool.config_emergency_account_emergency_calls_only)).thenReturn(true);
+ onLocaleChanged();
+
+ PhoneAccount phoneAccount = verifyAndCaptureRegisteredPhoneAccount();
+
+ assertThat(phoneAccount.hasCapabilities(
+ PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY)).isTrue();
+ }
+
+ private PhoneAccount verifyAndCaptureRegisteredPhoneAccount() {
+ ArgumentCaptor<PhoneAccount> phoneAccountArgumentCaptor =
+ ArgumentCaptor.forClass(PhoneAccount.class);
+ verify(mTelecomManager, atLeastOnce()).registerPhoneAccount(
+ phoneAccountArgumentCaptor.capture());
+ return phoneAccountArgumentCaptor.getValue();
+ }
+
+ private void onUserSwitched(UserHandle userHandle) {
+ Log.d(TAG, "Broadcast ACTION_USER_SWITCHED...");
+ Intent intent = new Intent(Intent.ACTION_USER_SWITCHED);
+ intent.putExtra(Intent.EXTRA_USER, userHandle);
+ mUserSwitchedAndConfigChangedReceiver.onReceive(mMockedContext, intent);
+ mTestableLooper.processAllMessages();
+ }
+
+ private void onCarrierConfigChanged(int subId) {
+ Log.d(TAG, "Broadcast ACTION_CARRIER_CONFIG_CHANGED...");
+ Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+ intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
+ mUserSwitchedAndConfigChangedReceiver.onReceive(mMockedContext, intent);
+ mTestableLooper.processAllMessages();
+ }
+
+ private void onSubscriptionsChanged() {
+ Log.d(TAG, "Change subscriptions...");
+ mOnSubscriptionsChangedListener.onSubscriptionsChanged();
+ }
+
+ private void onAddSubscriptionListenerFailed() {
+ Log.d(TAG, "Add subscription listener failed...");
+ mOnSubscriptionsChangedListener.onAddListenerFailed();
+ }
+
+ private void onServiceStateChanged(ServiceState serviceState) {
+ if (mTelephonyCallback instanceof TelephonyCallback.ServiceStateListener) {
+ TelephonyCallback.ServiceStateListener listener =
+ (TelephonyCallback.ServiceStateListener) mTelephonyCallback;
+ listener.onServiceStateChanged(serviceState);
+ }
+ }
+
+ private void onActiveDataSubscriptionIdChanged(int subId) {
+ if (mTelephonyCallback instanceof TelephonyCallback.ActiveDataSubscriptionIdListener) {
+ TelephonyCallback.ActiveDataSubscriptionIdListener listener =
+ (TelephonyCallback.ActiveDataSubscriptionIdListener) mTelephonyCallback;
+ listener.onActiveDataSubscriptionIdChanged(subId);
+ }
+ }
+
+ private void onLocaleChanged() {
+ Log.d(TAG, "Broadcast ACTION_LOCALE_CHANGED...");
+ Intent intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
+ mLocaleChangedBroadcastReceiver.onReceive(mMockedContext, intent);
+ }
+
+ private void onNetworkCountryChanged() {
+ Log.d(TAG, "Broadcast ACTION_NETWORK_COUNTRY_CHANGED...");
+ Intent intent = new Intent(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED);
+ mLocaleChangedBroadcastReceiver.onReceive(mMockedContext, intent);
+ }
+}