Added area info support in cell broadcast service am: 87db6b74ba am: bd8106d00d

Change-Id: I0fcde329f3b06bf245ae41a3b7bac2e4ce8857b7
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index e075727..7b71d76 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -30,6 +30,8 @@
     <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
 
+    <protected-broadcast android:name="android.telephony.action.AREA_INFO_UPDATED" />
+
     <uses-sdk android:minSdkVersion="29"/>
 
     <application android:label="Module used to handle cell broadcasts."
diff --git a/res/values/config.xml b/res/values/config.xml
index 23c8177..7f02d4a 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -37,4 +37,13 @@
     <!-- Whether to reset alert message duplicate detection and geo-fencing check after
     reboot or toggling airplane mode -->
     <bool name="reset_on_power_cycle_or_airplane_mode">false</bool>
+
+    <!-- Cell broadcast channels for area info update. Note the channel configuration for area info
+         is needed in CellBroadcastReceiver as well.  -->
+    <integer-array name="area_info_channels">
+    </integer-array>
+
+    <!-- Package names of the area info receivers -->
+    <string-array name="config_area_info_receiver_packages" translatable="false">
+    </string-array>
 </resources>
diff --git a/src/com/android/cellbroadcastservice/DefaultCellBroadcastService.java b/src/com/android/cellbroadcastservice/DefaultCellBroadcastService.java
index 70d23ae..6b99801 100644
--- a/src/com/android/cellbroadcastservice/DefaultCellBroadcastService.java
+++ b/src/com/android/cellbroadcastservice/DefaultCellBroadcastService.java
@@ -16,6 +16,7 @@
 
 package com.android.cellbroadcastservice;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.os.Bundle;
 import android.telephony.CellBroadcastService;
@@ -100,6 +101,12 @@
                 originatingAddress, callback);
     }
 
+    @Override
+    public @NonNull String getCellBroadcastAreaInfo(int slotIndex) {
+        Log.d(TAG, "getCellBroadcastAreaInfo on slotId=" + slotIndex);
+        return mGsmCellBroadcastHandler.getCellBroadcastAreaInfo(slotIndex);
+    }
+
     /**
      * Parses a CDMA broadcast SMS
      *
diff --git a/src/com/android/cellbroadcastservice/GsmCellBroadcastHandler.java b/src/com/android/cellbroadcastservice/GsmCellBroadcastHandler.java
index fb04fa0..a61cc6d 100644
--- a/src/com/android/cellbroadcastservice/GsmCellBroadcastHandler.java
+++ b/src/com/android/cellbroadcastservice/GsmCellBroadcastHandler.java
@@ -16,17 +16,21 @@
 
 package com.android.cellbroadcastservice;
 
+import android.annotation.NonNull;
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Looper;
 import android.os.Message;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.provider.Telephony.CellBroadcasts;
 import android.telephony.CbGeoUtils.Geometry;
+import android.telephony.CellBroadcastIntents;
 import android.telephony.CellIdentity;
 import android.telephony.CellIdentityGsm;
 import android.telephony.CellInfo;
@@ -36,6 +40,7 @@
 import android.telephony.TelephonyManager;
 import android.text.format.DateUtils;
 import android.util.Pair;
+import android.util.SparseArray;
 
 import com.android.cellbroadcastservice.GsmSmsCbMessage.GeoFencingTriggerMessage;
 import com.android.cellbroadcastservice.GsmSmsCbMessage.GeoFencingTriggerMessage.CellBroadcastIdentity;
@@ -46,6 +51,7 @@
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.stream.IntStream;
 
 /**
  * Handler for 3GPP format Cell Broadcasts. Parent class can also handle CDMA Cell Broadcasts.
@@ -56,6 +62,8 @@
     /** Indicates that a message is not being broadcasted. */
     private static final String MESSAGE_NOT_BROADCASTED = "0";
 
+    private SparseArray<String> mAreaInfos = new SparseArray<>();
+
     /** This map holds incomplete concatenated messages waiting for assembly. */
     private final HashMap<SmsCbConcatInfo, byte[][]> mSmsCbPageMap =
             new HashMap<>(4);
@@ -79,6 +87,18 @@
     }
 
     /**
+     * Get the area information
+     *
+     * @param slotIndex SIM slot index
+     * @return The area information
+     */
+    @NonNull
+    public String getCellBroadcastAreaInfo(int slotIndex) {
+        String info = mAreaInfos.get(slotIndex);
+        return info == null ? "" : info;
+    }
+
+    /**
      * Create a new CellBroadcastHandler.
      * @param context the context to use for dispatching Intents
      * @return the new handler
@@ -202,6 +222,47 @@
     }
 
     /**
+     * Process area info message.
+     *
+     * @param slotIndex SIM slot index
+     * @param message Cell broadcast message
+     * @return {@code true} if the mssage is an area info message and got processed correctly,
+     * otherwise {@code false}.
+     */
+    private boolean handleAreaInfoMessage(int slotIndex, SmsCbMessage message) {
+        SubscriptionManager subMgr = (SubscriptionManager) mContext.getSystemService(
+                Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+
+        // Check area info message
+        int[] subIds = subMgr.getSubscriptionIds(slotIndex);
+        Resources res;
+        if (subIds != null) {
+            res = getResources(subIds[0]);
+        } else {
+            res = getResources(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
+        }
+        int[] areaInfoChannels = res.getIntArray(R.array.area_info_channels);
+
+        if (IntStream.of(areaInfoChannels).anyMatch(
+                x -> x == message.getServiceCategory())) {
+            mAreaInfos.put(slotIndex, message.getMessageBody());
+
+            String[] pkgs = mContext.getResources().getStringArray(
+                    R.array.config_area_info_receiver_packages);
+            for (String pkg : pkgs) {
+                Intent intent = new Intent(CellBroadcastIntents.ACTION_AREA_INFO_UPDATED);
+                intent.setPackage(pkg);
+                mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+                        android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+            }
+            return true;
+        }
+
+        // This is not an area info message.
+        return false;
+    }
+
+    /**
      * Handle 3GPP-format Cell Broadcast messages sent from radio.
      *
      * @param message the message to process
@@ -229,6 +290,12 @@
                     if (isDuplicate(cbMessage)) {
                         return false;
                     }
+
+                    if (handleAreaInfoMessage(slotIndex, cbMessage)) {
+                        log("Channel " + cbMessage.getServiceCategory() + " message processed");
+                        return false;
+                    }
+
                     handleBroadcastSms(cbMessage);
                     return true;
                 }
diff --git a/tests/src/com/android/cellbroadcastservice/tests/CellBroadcastServiceTestBase.java b/tests/src/com/android/cellbroadcastservice/tests/CellBroadcastServiceTestBase.java
index 009986e..9ec3489 100644
--- a/tests/src/com/android/cellbroadcastservice/tests/CellBroadcastServiceTestBase.java
+++ b/tests/src/com/android/cellbroadcastservice/tests/CellBroadcastServiceTestBase.java
@@ -158,6 +158,8 @@
             doReturn(value).when(mMockedResources).getInteger(eq(id));
         } else if (value instanceof Integer[]) {
             doReturn(value).when(mMockedResources).getIntArray(eq(id));
+        } else if (value instanceof int[]) {
+            doReturn(value).when(mMockedResources).getIntArray(eq(id));
         } else if (value instanceof String) {
             doReturn(value).when(mMockedResources).getString(eq(id));
         }
diff --git a/tests/src/com/android/cellbroadcastservice/tests/GsmCellBroadcastHandlerTest.java b/tests/src/com/android/cellbroadcastservice/tests/GsmCellBroadcastHandlerTest.java
index 837fdcc..4e9e62e 100644
--- a/tests/src/com/android/cellbroadcastservice/tests/GsmCellBroadcastHandlerTest.java
+++ b/tests/src/com/android/cellbroadcastservice/tests/GsmCellBroadcastHandlerTest.java
@@ -157,7 +157,11 @@
         putResources(com.android.cellbroadcastservice.R.integer.message_expiration_time, 86400000);
         putResources(
                 com.android.cellbroadcastservice.R.array.config_defaultCellBroadcastReceiverPkgs,
-                new String[]{"fake.cellbroadcast.pkg"});
+                new String[]{"fake.cellcbroadcast.pkg"});
+        putResources(com.android.cellbroadcastservice.R.array.area_info_channels, new int[]{});
+        putResources(
+                com.android.cellbroadcastservice.R.array.config_area_info_receiver_packages,
+                new String[]{"fake.inforeceiver.pkg"});
     }
 
     @After