Snap for 6664195 from 5e66fb77205bbf1d7426e94254577c307f334400 to rvc-d1-release

Change-Id: If0241e23a49228327bc52826816260169e07fa3c
diff --git a/src/com/android/cellbroadcastservice/GsmCellBroadcastHandler.java b/src/com/android/cellbroadcastservice/GsmCellBroadcastHandler.java
index 8449166..dec379d 100644
--- a/src/com/android/cellbroadcastservice/GsmCellBroadcastHandler.java
+++ b/src/com/android/cellbroadcastservice/GsmCellBroadcastHandler.java
@@ -20,6 +20,7 @@
 import static com.android.cellbroadcastservice.CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_ERROR__TYPE__UNEXPECTED_GSM_MESSAGE_TYPE_FROM_FWK;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.Context;
@@ -32,11 +33,18 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Telephony.CellBroadcasts;
+import android.telephony.AccessNetworkConstants;
 import android.telephony.CbGeoUtils.Geometry;
 import android.telephony.CellBroadcastIntents;
 import android.telephony.CellIdentity;
 import android.telephony.CellIdentityGsm;
+import android.telephony.CellIdentityLte;
+import android.telephony.CellIdentityNr;
+import android.telephony.CellIdentityTdscdma;
+import android.telephony.CellIdentityWcdma;
 import android.telephony.CellInfo;
+import android.telephony.NetworkRegistrationInfo;
+import android.telephony.ServiceState;
 import android.telephony.SmsCbLocation;
 import android.telephony.SmsCbMessage;
 import android.telephony.SubscriptionManager;
@@ -55,6 +63,8 @@
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
 /**
@@ -328,23 +338,93 @@
         }
     }
 
-    // return the GSM cell location from the first GSM cell info
-    private Pair<Integer, Integer> getGsmLacAndCid() {
-        TelephonyManager tm =
-                (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
-        List<CellInfo> infos = tm.getAllCellInfo();
-        for (CellInfo info : infos) {
-            CellIdentity ci = info.getCellIdentity();
-            if (ci instanceof CellIdentityGsm) {
-                CellIdentityGsm ciGsm = (CellIdentityGsm) ci;
-                int lac = ciGsm.getLac() != CellInfo.UNAVAILABLE ? ciGsm.getLac() : -1;
-                int cid = ciGsm.getCid() != CellInfo.UNAVAILABLE ? ciGsm.getCid() : -1;
-                return Pair.create(lac, cid);
-            }
+    /**
+     * Get LAC (location area code for GSM/UMTS) / TAC (tracking area code for LTE/NR) and CID
+     * (Cell id) from the cell identity
+     *
+     * @param ci Cell identity
+     * @return Pair of LAC and CID. {@code null} if not available.
+     */
+    private @Nullable Pair<Integer, Integer> getLacAndCid(CellIdentity ci) {
+        if (ci == null) return null;
+        int lac = CellInfo.UNAVAILABLE;
+        int cid = CellInfo.UNAVAILABLE;
+        if (ci instanceof CellIdentityGsm) {
+            lac = ((CellIdentityGsm) ci).getLac();
+            cid = ((CellIdentityGsm) ci).getCid();
+        } else if (ci instanceof CellIdentityWcdma) {
+            lac = ((CellIdentityWcdma) ci).getLac();
+            cid = ((CellIdentityWcdma) ci).getCid();
+        } else if ((ci instanceof CellIdentityTdscdma)) {
+            lac = ((CellIdentityTdscdma) ci).getLac();
+            cid = ((CellIdentityTdscdma) ci).getCid();
+        } else if (ci instanceof CellIdentityLte) {
+            lac = ((CellIdentityLte) ci).getTac();
+            cid = ((CellIdentityLte) ci).getCi();
+        } else if (ci instanceof CellIdentityNr) {
+            lac = ((CellIdentityNr) ci).getTac();
+            cid = ((CellIdentityNr) ci).getPci();
         }
+
+        if (lac != CellInfo.UNAVAILABLE || cid != CellInfo.UNAVAILABLE) {
+            return Pair.create(lac, cid);
+        }
+
+        // When both LAC and CID are not available.
         return null;
     }
 
+    /**
+     * Get LAC (location area code for GSM/UMTS) / TAC (tracking area code for LTE/NR) and CID
+     * (Cell id) of the registered network.
+     *
+     * @param slotIndex SIM slot index
+     *
+     * @return lac and cid. {@code null} if cell identity is not available from the registered
+     * network.
+     */
+    private @Nullable Pair<Integer, Integer> getLacAndCid(int slotIndex) {
+        TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+        tm.createForSubscriptionId(getSubIdForPhone(mContext, slotIndex));
+
+        ServiceState serviceState = tm.getServiceState();
+
+        if (serviceState == null) return null;
+
+        // The list of cell identity to extract LAC and CID. The higher priority one will be added
+        // into the top of list.
+        List<CellIdentity> cellIdentityList = new ArrayList<>();
+
+        // CS network
+        NetworkRegistrationInfo nri = serviceState.getNetworkRegistrationInfo(
+                NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+        if (nri != null) {
+            cellIdentityList.add(nri.getCellIdentity());
+        }
+
+        // PS network
+        nri = serviceState.getNetworkRegistrationInfo(
+                NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+        if (nri != null) {
+            cellIdentityList.add(nri.getCellIdentity());
+        }
+
+        // When SIM is not inserted, we use the cell identity from the nearby cell. This is
+        // best effort.
+        List<CellInfo> infos = tm.getAllCellInfo();
+        if (infos != null) {
+            cellIdentityList.addAll(
+                    infos.stream().map(CellInfo::getCellIdentity).collect(Collectors.toList()));
+        }
+
+        // Return the first valid LAC and CID from the list.
+        return cellIdentityList.stream()
+                .map(this::getLacAndCid)
+                .filter(Objects::nonNull)
+                .findFirst()
+                .orElse(null);
+    }
+
 
     /**
      * Handle 3GPP format SMS-CB message.
@@ -373,35 +453,17 @@
             TelephonyManager tm =
                     (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
             tm.createForSubscriptionId(getSubIdForPhone(mContext, slotIndex));
-            // TODO make a systemAPI for getNetworkOperatorForSlotIndex
-            String plmn = tm.getSimOperator();
+            String plmn = tm.getNetworkOperator();
             int lac = -1;
             int cid = -1;
-            Pair<Integer, Integer> lacAndCid = getGsmLacAndCid();
-            // Check if GSM lac and cid are available. This is required to support
-            // dual-mode devices such as CDMA/LTE devices that require support for
-            // both 3GPP and 3GPP2 format messages
+            // Get LAC and CID of the current camped cell.
+            Pair<Integer, Integer> lacAndCid = getLacAndCid(slotIndex);
             if (lacAndCid != null) {
                 lac = lacAndCid.first;
                 cid = lacAndCid.second;
             }
 
-            SmsCbLocation location;
-            switch (header.getGeographicalScope()) {
-                case SmsCbMessage.GEOGRAPHICAL_SCOPE_LOCATION_AREA_WIDE:
-                    location = new SmsCbLocation(plmn, lac, -1);
-                    break;
-
-                case SmsCbMessage.GEOGRAPHICAL_SCOPE_CELL_WIDE:
-                case SmsCbMessage.GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE:
-                    location = new SmsCbLocation(plmn, lac, cid);
-                    break;
-
-                case SmsCbMessage.GEOGRAPHICAL_SCOPE_PLMN_WIDE:
-                default:
-                    location = new SmsCbLocation(plmn, -1, -1);
-                    break;
-            }
+            SmsCbLocation location = new SmsCbLocation(plmn, lac, cid);
 
             byte[][] pdus;
             int pageCount = header.getNumberOfPages();
@@ -456,7 +518,8 @@
             return GsmSmsCbMessage.createSmsCbMessage(mContext, header, location, pdus, slotIndex);
 
         } catch (RuntimeException e) {
-            final String errorMessage = "Error in decoding SMS CB pdu" + e.toString();
+            final String errorMessage = "Error in decoding SMS CB pdu: " + e.toString();
+            e.printStackTrace();
             loge(errorMessage);
             CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_ERROR,
                     CELL_BROADCAST_MESSAGE_ERROR__TYPE__GSM_INVALID_PDU, errorMessage);
diff --git a/tests/src/com/android/cellbroadcastservice/tests/CellBroadcastServiceTestBase.java b/tests/src/com/android/cellbroadcastservice/tests/CellBroadcastServiceTestBase.java
index f1c7430..dfdb2e2 100644
--- a/tests/src/com/android/cellbroadcastservice/tests/CellBroadcastServiceTestBase.java
+++ b/tests/src/com/android/cellbroadcastservice/tests/CellBroadcastServiceTestBase.java
@@ -126,6 +126,8 @@
         doReturn(powerManager).when(mMockedContext).getSystemService(Context.POWER_SERVICE);
         doReturn(mMockedTelephonyManager).when(mMockedContext)
                 .getSystemService(Context.TELEPHONY_SERVICE);
+        doReturn(Context.TELEPHONY_SERVICE).when(mMockedContext)
+                .getSystemServiceName(TelephonyManager.class);
         doReturn(mMockedSubscriptionManager).when(mMockedContext)
                 .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
         doReturn(mMockedLocationManager).when(mMockedContext)
diff --git a/tests/src/com/android/cellbroadcastservice/tests/GsmCellBroadcastHandlerTest.java b/tests/src/com/android/cellbroadcastservice/tests/GsmCellBroadcastHandlerTest.java
index a124faa..e94aabb 100644
--- a/tests/src/com/android/cellbroadcastservice/tests/GsmCellBroadcastHandlerTest.java
+++ b/tests/src/com/android/cellbroadcastservice/tests/GsmCellBroadcastHandlerTest.java
@@ -34,8 +34,14 @@
 import android.os.Bundle;
 import android.provider.Settings;
 import android.provider.Telephony;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.CellIdentityLte;
+import android.telephony.NetworkRegistrationInfo;
+import android.telephony.ServiceState;
 import android.telephony.SmsCbCmasInfo;
+import android.telephony.SmsCbLocation;
 import android.telephony.SmsCbMessage;
+import android.telephony.TelephonyManager;
 import android.test.mock.MockContentProvider;
 import android.test.mock.MockContentResolver;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -244,4 +250,43 @@
         verify(mMockedContext, never()).sendOrderedBroadcast(any(), anyString(), anyString(),
                 any(), any(), anyInt(), any(), any());
     }
+
+    @Test
+    @SmallTest
+    public void testSmsCbLocation() {
+        final byte[] pdu = hexStringToBytes("01111B40110101C366701A09368545692408000000000000000"
+                + "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+                + "000000000000000000000000000000000000000000000000B");
+
+        final String fakePlmn = "310999";
+        final int fakeTac = 1234;
+        final int fakeCid = 5678;
+
+        doReturn(fakePlmn).when(mMockedTelephonyManager).getNetworkOperator();
+        ServiceState ss = Mockito.mock(ServiceState.class);
+        doReturn(ss).when(mMockedTelephonyManager).getServiceState();
+        NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+                .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
+                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
+                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
+                .setCellIdentity(new CellIdentityLte(0, 0, fakeCid, 0, fakeTac))
+                .build();
+        doReturn(nri).when(ss).getNetworkRegistrationInfo(anyInt(), anyInt());
+
+        mGsmCellBroadcastHandler.onGsmCellBroadcastSms(0, pdu);
+        mTestableLooper.processAllMessages();
+
+        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        verify(mMockedContext).sendOrderedBroadcast(intentCaptor.capture(), any(),
+                (Bundle) any(), any(), any(), anyInt(), any(), any());
+        Intent intent = intentCaptor.getValue();
+        assertEquals(Telephony.Sms.Intents.ACTION_SMS_EMERGENCY_CB_RECEIVED, intent.getAction());
+        SmsCbMessage msg = intent.getParcelableExtra("message");
+
+        SmsCbLocation location = msg.getLocation();
+        assertEquals(fakePlmn, location.getPlmn());
+        assertEquals(fakeTac, location.getLac());
+        assertEquals(fakeCid, location.getCid());
+    }
 }