Merge "SystemAPI RoleManager.getFinancialSms"
diff --git a/jarjar-rules-shared.txt b/jarjar-rules-shared.txt
index 45be9f5..6312825 100644
--- a/jarjar-rules-shared.txt
+++ b/jarjar-rules-shared.txt
@@ -4,7 +4,6 @@
 rule android.util.LocalLog* com.android.internal.telephony.LocalLog@1
 rule android.util.TimeUtils* com.android.internal.telephony.TimeUtils@1
 rule com.android.internal.os.SomeArgs* com.android.internal.telephony.SomeArgs@1
-rule com.android.internal.util.ArrayUtils* com.android.internal.telephony.ArrayUtils@1
 rule com.android.internal.util.FastXmlSerializer* com.android.internal.telephony.FastXmlSerializer@1
 rule com.android.internal.util.HexDump* com.android.internal.telephony.HexDump@1
 rule com.android.internal.util.IndentingPrintWriter* com.android.internal.telephony.IndentingPrintWriter@1
diff --git a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
index 66a86e6..7e3979e 100644
--- a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
+++ b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
@@ -41,6 +41,7 @@
 import android.provider.Telephony;
 import android.telephony.CarrierConfigManager;
 import android.telephony.Rlog;
+import android.telephony.SmsCbMessage;
 import android.telephony.SmsManager;
 import android.telephony.SmsMessage;
 import android.telephony.SubscriptionManager;
@@ -901,9 +902,9 @@
         mContext.enforceCallingPermission("android.permission.RECEIVE_EMERGENCY_BROADCAST",
                 "enabling cell broadcast range [" + startMessageId + "-" + endMessageId + "]. "
                         + "ranType=" + ranType);
-        if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_GSM) {
+        if (ranType == SmsCbMessage.MESSAGE_FORMAT_3GPP) {
             return enableGsmBroadcastRange(startMessageId, endMessageId);
-        } else if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA) {
+        } else if (ranType == SmsCbMessage.MESSAGE_FORMAT_3GPP2) {
             return enableCdmaBroadcastRange(startMessageId, endMessageId);
         } else {
             throw new IllegalArgumentException("Not a supported RAN Type");
@@ -914,9 +915,9 @@
         mContext.enforceCallingPermission("android.permission.RECEIVE_EMERGENCY_BROADCAST",
                 "disabling cell broadcast range [" + startMessageId + "-" + endMessageId
                         + "]. ranType=" + ranType);
-        if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_GSM ) {
+        if (ranType == SmsCbMessage.MESSAGE_FORMAT_3GPP) {
             return disableGsmBroadcastRange(startMessageId, endMessageId);
-        } else if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA)  {
+        } else if (ranType == SmsCbMessage.MESSAGE_FORMAT_3GPP2)  {
             return disableCdmaBroadcastRange(startMessageId, endMessageId);
         } else {
             throw new IllegalArgumentException("Not a supported RAN Type");
diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java
index 273951d..1ebea33 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -3055,12 +3055,6 @@
             throw new IllegalArgumentException("Invalid groupUuid");
         }
 
-        // TODO: Revisit whether we need this restriction in R. There's no technical need for it,
-        // but we don't want to change the API behavior at this time.
-        if (getSubscriptionsInGroup(groupUuid, callingPackage).isEmpty()) {
-            throw new IllegalArgumentException("Cannot add subscriptions to a non-existent group!");
-        }
-
         // Makes sure calling package matches caller UID.
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
         // If it doesn't have modify phone state permission, or carrier privilege permission,
diff --git a/src/java/com/android/internal/telephony/cat/CatCmdMessage.java b/src/java/com/android/internal/telephony/cat/CatCmdMessage.java
index 313e56f..0033fff 100644
--- a/src/java/com/android/internal/telephony/cat/CatCmdMessage.java
+++ b/src/java/com/android/internal/telephony/cat/CatCmdMessage.java
@@ -138,10 +138,10 @@
     }
 
     public CatCmdMessage(Parcel in) {
-        mCmdDet = in.readParcelable(null);
-        mTextMsg = in.readParcelable(null);
-        mMenu = in.readParcelable(null);
-        mInput = in.readParcelable(null);
+        mCmdDet = in.readParcelable(CommandDetails.class.getClassLoader());
+        mTextMsg = in.readParcelable(TextMessage.class.getClassLoader());
+        mMenu = in.readParcelable(Menu.class.getClassLoader());
+        mInput = in.readParcelable(Input.class.getClassLoader());
         mLoadIconFailed = (in.readByte() == 1);
         switch (getCmdType()) {
         case LAUNCH_BROWSER:
@@ -150,12 +150,12 @@
             mBrowserSettings.mode = LaunchBrowserMode.values()[in.readInt()];
             break;
         case PLAY_TONE:
-            mToneSettings = in.readParcelable(null);
+            mToneSettings = in.readParcelable(ToneSettings.class.getClassLoader());
             break;
         case SET_UP_CALL:
             mCallSettings = new CallSettings();
-            mCallSettings.confirmMsg = in.readParcelable(null);
-            mCallSettings.callMsg = in.readParcelable(null);
+            mCallSettings.confirmMsg = in.readParcelable(TextMessage.class.getClassLoader());
+            mCallSettings.callMsg = in.readParcelable(TextMessage.class.getClassLoader());
             break;
         case SET_UP_EVENT_LIST:
             mSetupEventListSettings = new SetupEventListSettings();
diff --git a/src/java/com/android/internal/telephony/cat/CatService.java b/src/java/com/android/internal/telephony/cat/CatService.java
index 50ceaac..e24a408 100644
--- a/src/java/com/android/internal/telephony/cat/CatService.java
+++ b/src/java/com/android/internal/telephony/cat/CatService.java
@@ -541,7 +541,7 @@
 
     private void broadcastCatCmdIntent(CatCmdMessage cmdMsg) {
         Intent intent = new Intent(AppInterface.CAT_CMD_ACTION);
-        intent.putExtra("STK CMD", cmdMsg);
+        intent.putExtra( "STK CMD", cmdMsg);
         intent.putExtra("SLOT_ID", mSlotId);
         intent.setComponent(AppInterface.getDefaultSTKApplication());
         CatLog.d(this, "Sending CmdMsg: " + cmdMsg+ " on slotid:" + mSlotId);
diff --git a/src/java/com/android/internal/telephony/cat/CommandDetails.java b/src/java/com/android/internal/telephony/cat/CommandDetails.java
index d7c511a..dd1bbcf 100644
--- a/src/java/com/android/internal/telephony/cat/CommandDetails.java
+++ b/src/java/com/android/internal/telephony/cat/CommandDetails.java
@@ -28,7 +28,7 @@
  * Class for Command Details object of proactive commands from SIM.
  * {@hide}
  */
-class CommandDetails extends ValueObject implements Parcelable {
+public class CommandDetails extends ValueObject implements Parcelable {
     @UnsupportedAppUsage
     public boolean compRequired;
     @UnsupportedAppUsage
diff --git a/src/java/com/android/internal/telephony/cat/Input.java b/src/java/com/android/internal/telephony/cat/Input.java
index aaaff43..e9103b8 100644
--- a/src/java/com/android/internal/telephony/cat/Input.java
+++ b/src/java/com/android/internal/telephony/cat/Input.java
@@ -58,7 +58,7 @@
     private Input(Parcel in) {
         text = in.readString();
         defaultText = in.readString();
-        icon = in.readParcelable(null);
+        icon = in.readParcelable(Bitmap.class.getClassLoader());
         minLen = in.readInt();
         maxLen = in.readInt();
         ucs2 = in.readInt() == 1 ? true : false;
diff --git a/src/java/com/android/internal/telephony/cat/Item.java b/src/java/com/android/internal/telephony/cat/Item.java
index 456a46f..702ed4b 100644
--- a/src/java/com/android/internal/telephony/cat/Item.java
+++ b/src/java/com/android/internal/telephony/cat/Item.java
@@ -46,7 +46,7 @@
     public Item(Parcel in) {
         id = in.readInt();
         text = in.readString();
-        icon = in.readParcelable(null);
+        icon = in.readParcelable(Bitmap.class.getClassLoader());
     }
 
     @Override
diff --git a/src/java/com/android/internal/telephony/cat/Menu.java b/src/java/com/android/internal/telephony/cat/Menu.java
index a93fd1f..f1d19b5 100644
--- a/src/java/com/android/internal/telephony/cat/Menu.java
+++ b/src/java/com/android/internal/telephony/cat/Menu.java
@@ -58,12 +58,12 @@
 
     private Menu(Parcel in) {
         title = in.readString();
-        titleIcon = in.readParcelable(null);
+        titleIcon = in.readParcelable(Bitmap.class.getClassLoader());
         // rebuild items list.
         items = new ArrayList<Item>();
         int size = in.readInt();
         for (int i=0; i<size; i++) {
-            Item item = in.readParcelable(null);
+            Item item = in.readParcelable(Item.class.getClassLoader());
             items.add(item);
         }
         defaultItem = in.readInt();
diff --git a/src/java/com/android/internal/telephony/cat/TextMessage.java b/src/java/com/android/internal/telephony/cat/TextMessage.java
index eddca4c..e7c2da6 100644
--- a/src/java/com/android/internal/telephony/cat/TextMessage.java
+++ b/src/java/com/android/internal/telephony/cat/TextMessage.java
@@ -40,7 +40,7 @@
     private TextMessage(Parcel in) {
         title = in.readString();
         text = in.readString();
-        icon = in.readParcelable(null);
+        icon = in.readParcelable(Bitmap.class.getClassLoader());
         iconSelfExplanatory = in.readInt() == 1 ? true : false;
         isHighPriority = in.readInt() == 1 ? true : false;
         responseNeeded = in.readInt() == 1 ? true : false;
diff --git a/src/java/com/android/internal/telephony/cat/ToneSettings.java b/src/java/com/android/internal/telephony/cat/ToneSettings.java
index 61c1573..4e94ead 100644
--- a/src/java/com/android/internal/telephony/cat/ToneSettings.java
+++ b/src/java/com/android/internal/telephony/cat/ToneSettings.java
@@ -35,8 +35,8 @@
     }
 
     private ToneSettings(Parcel in) {
-        duration = in.readParcelable(null);
-        tone = in.readParcelable(null);
+        duration = in.readParcelable(Duration.class.getClassLoader());
+        tone = in.readParcelable(Tone.class.getClassLoader());
         vibrate = in.readInt() == 1;
     }
 
diff --git a/src/java/com/android/internal/telephony/util/TelephonyUtils.java b/src/java/com/android/internal/telephony/util/TelephonyUtils.java
deleted file mode 100644
index 0105577..0000000
--- a/src/java/com/android/internal/telephony/util/TelephonyUtils.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2019 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.internal.telephony.util;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.pm.ComponentInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.Binder;
-import android.os.RemoteException;
-import android.os.SystemProperties;
-
-import java.io.PrintWriter;
-
-/**
- * This class provides various util functions
- */
-public final class TelephonyUtils {
-    public static boolean IS_USER = "user".equals(android.os.Build.TYPE);
-
-    /**
-     * Verify that caller holds {@link android.Manifest.permission#DUMP}.
-     *
-     * @return true if access should be granted.
-     */
-    public static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
-        if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump " + tag + " from from pid="
-                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
-                    + " due to missing android.permission.DUMP permission");
-            return false;
-        } else {
-            return true;
-        }
-    }
-
-    /** {@hide} */
-    public static String emptyIfNull(@Nullable String str) {
-        return str == null ? "" : str;
-    }
-
-    /** {@hide} */
-    public static RuntimeException rethrowAsRuntimeException(RemoteException remoteException) {
-        throw new RuntimeException(remoteException);
-    }
-
-    public static ComponentInfo getComponentInfo(@NonNull ResolveInfo resolveInfo) {
-        if (resolveInfo.activityInfo != null) return resolveInfo.activityInfo;
-        if (resolveInfo.serviceInfo != null) return resolveInfo.serviceInfo;
-        if (resolveInfo.providerInfo != null) return resolveInfo.providerInfo;
-        throw new IllegalStateException("Missing ComponentInfo!");
-    }
-
-    public static boolean IS_DEBUGGABLE =
-            SystemProperties.getInt("ro.debuggable", 0) == 1;
-}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
index 609b028..899ffc8 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
@@ -60,6 +60,7 @@
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
+import java.util.UUID;
 
 public class SubscriptionControllerTest extends TelephonyTest {
     private static final int SINGLE_SIM = 1;
@@ -729,6 +730,57 @@
 
     @Test
     @SmallTest
+    public void testAddSubscriptionIntoGroupWithCarrierPrivilegePermission() throws Exception {
+        testInsertSim();
+        // Adding a second profile and mark as embedded.
+        // TODO b/123300875 slot index 1 is not expected to be valid
+        mSubscriptionControllerUT.addSubInfoRecord("test2", 1);
+        ContentValues values = new ContentValues();
+        values.put(SubscriptionManager.IS_EMBEDDED, 1);
+        mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values,
+                SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 2, null);
+        mSubscriptionControllerUT.refreshCachedActiveSubscriptionInfoList();
+
+        mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);
+        mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE);
+
+        // Create group for sub 1.
+        int[] subIdList = new int[] {1};
+        doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(1);
+        ParcelUuid groupId = mSubscriptionControllerUT.createSubscriptionGroup(
+                subIdList, "packageName1");
+
+        // Try to add sub 2 into group of sub 1.
+        // Should fail as it doesn't have carrier privilege on sub 2.
+        try {
+            mSubscriptionControllerUT.addSubscriptionsIntoGroup(
+                    new int[] {2}, groupId, "packageName1");
+            fail("addSubscriptionsIntoGroup should fail with no permission on sub 2.");
+        } catch (SecurityException e) {
+            // Expected result.
+        }
+
+        doReturn(false).when(mTelephonyManager).hasCarrierPrivileges(1);
+        doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(2);
+        // Try to add sub 2 into group of sub 1.
+        // Should fail as it doesn't have carrier privilege on sub 1.
+        try {
+            mSubscriptionControllerUT.addSubscriptionsIntoGroup(
+                    new int[] {2}, groupId, "packageName2");
+            fail("addSubscriptionsIntoGroup should fail with no permission on the group (sub 1).");
+        } catch (SecurityException e) {
+            // Expected result.
+        }
+
+        doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(1);
+        mSubscriptionControllerUT.addSubscriptionsIntoGroup(new int[] {2}, groupId, "packageName2");
+        List<SubscriptionInfo> infoList = mSubscriptionControllerUT
+                .getSubscriptionsInGroup(groupId, "packageName2");
+        assertEquals(2, infoList.size());
+    }
+
+    @Test
+    @SmallTest
     public void testUpdateSubscriptionGroupWithCarrierPrivilegePermission() throws Exception {
         testInsertSim();
         // Adding a second profile and mark as embedded.
@@ -893,6 +945,15 @@
                 .getSubscriptionsInGroup(groupUuid, mContext.getOpPackageName());
         assertEquals(1, infoList.size());
         assertEquals(2, infoList.get(0).getSubscriptionId());
+
+        // Adding sub 1 into a non-existing UUID, which should be granted.
+        groupUuid = new ParcelUuid(UUID.randomUUID());
+        mSubscriptionControllerUT.addSubscriptionsIntoGroup(
+                subIdList, groupUuid, mContext.getOpPackageName());
+        infoList = mSubscriptionControllerUT
+                .getSubscriptionsInGroup(groupUuid, mContext.getOpPackageName());
+        assertEquals(1, infoList.size());
+        assertEquals(1, infoList.get(0).getSubscriptionId());
     }
 
     private void registerMockTelephonyRegistry() {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
index 3b23510..2dce712 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.nullable;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
@@ -806,8 +807,9 @@
         SmsBroadcastUndelivered.initialize(mContext, mGsmInboundSmsHandler, mCdmaInboundSmsHandler);
 
         // verify that a broadcast receiver is registered for current user (user == null) based on
-        // implementation in ContextFixture
-        verify(mContext, times(1)).registerReceiverAsUser(any(BroadcastReceiver.class),
+        // implementation in ContextFixture. registerReceiver may be called more than once (for
+        // example by GsmInboundSmsHandler if TEST_MODE is true)
+        verify(mContext, atLeastOnce()).registerReceiverAsUser(any(BroadcastReceiver.class),
                 eq((UserHandle)null), any(IntentFilter.class), eq((String)null), eq((Handler)null));
 
         // wait for ScanRawTableThread