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);
+    }
+}