Added area info support in cell broadcast service

Added a broadcast for area info changed event, and
also a get method in cell broadcast service to
retrieve the area info.

Test: Cell broadcast sanity tests
Bug: 141318859
Change-Id: I682e579d797c35f1de032b93e0e0eb05e15928e0
diff --git a/src/com/android/cellbroadcastservice/GsmCellBroadcastHandler.java b/src/com/android/cellbroadcastservice/GsmCellBroadcastHandler.java
index 6aee320..b702607 100644
--- a/src/com/android/cellbroadcastservice/GsmCellBroadcastHandler.java
+++ b/src/com/android/cellbroadcastservice/GsmCellBroadcastHandler.java
@@ -19,17 +19,21 @@
 import static com.android.cellbroadcastservice.CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_ERROR__TYPE__GSM_INVALID_PDU;
 import static com.android.cellbroadcastservice.CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_ERROR__TYPE__UNEXPECTED_GSM_MESSAGE_TYPE_FROM_FWK;
 
+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;
@@ -39,6 +43,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;
@@ -49,6 +54,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.
@@ -59,6 +65,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);
@@ -82,6 +90,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
@@ -205,6 +225,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
@@ -232,6 +293,12 @@
                     if (isDuplicate(cbMessage)) {
                         return false;
                     }
+
+                    if (handleAreaInfoMessage(slotIndex, cbMessage)) {
+                        log("Channel " + cbMessage.getServiceCategory() + " message processed");
+                        return false;
+                    }
+
                     handleBroadcastSms(cbMessage);
                     return true;
                 }