Merge tag 'android-6.0.1_r3' into 601r3

Android 6.0.1 release 3

* tag 'android-6.0.1_r3':
  DO NOT MERGE. Fixed emergency alert TTS not playing on bluetooth speaker.
  Fixed that emergency alert reminder does not trigger every 2 minutes.
  Fixed that "Turn on notification" does not work.

Change-Id: Ie67c5bec6b7c0e61ffb2126921f6a060f16afd1c
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 6e022fd..9f4b1d9 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -68,6 +68,7 @@
     <string name="category_brazil_settings_title" msgid="6343130548572319922">"针对巴西的设置"</string>
     <string name="enable_channel_50_alerts_title" msgid="2818924064446974167">"显示 50 频道的广播"</string>
     <string name="enable_channel_50_alerts_summary" msgid="7507770011325273009">"巴西使用频道 50 来广播区域动态信息"</string>
+    <string name="category_india_settings_title">针对印度的设置</string>
     <string name="category_dev_settings_title" msgid="6194393458398329994">"开发者选项"</string>
     <string name="cmas_category_heading" msgid="3923503130776640717">"警报类别:"</string>
     <string name="cmas_category_geo" msgid="4979494217069688527">"地球物理"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index 7e7ae9b..9c9a91a 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -21,4 +21,8 @@
     <bool name="show_cmas_settings">true</bool>
     <!-- Whether to enable channel 50 settings (Brazil) -->
     <bool name="show_brazil_settings">false</bool>
+    <!-- Whether to enable channel 50 and 60 settings (India) -->
+    <bool name="show_india_settings">false</bool>
+    <!-- CellBroadcast channel 60 enabled or not,default value is true -->
+    <bool name="def_channel_60_enabled">true</bool>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 57e2d9a..84e602a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -137,10 +137,16 @@
 
     <!-- Preference category title for Brazil settings. [CHAR LIMIT=50] -->
     <string name="category_brazil_settings_title">Settings for Brazil</string>
+    <!-- Preference category title for India settings. [CHAR LIMIT=50] -->
+    <string name="category_india_settings_title">Settings for India</string>
     <!-- Preference title for enable channel 50 alerts (Brazil only). [CHAR LIMIT=30] -->
     <string name="enable_channel_50_alerts_title">Show channel 50 broadcasts</string>
     <!-- Preference summary for enable channel 50 alerts (Brazil only). [CHAR LIMIT=100] -->
     <string name="enable_channel_50_alerts_summary">Channel 50 is used in Brazil for area update information</string>
+    <!-- Preference title for enable channel 60 alerts. [CHAR LIMIT=30] -->
+    <string name="enable_channel_60_alerts_title">Show channel 60 broadcasts</string>
+    <!-- Preference summary for enable channel 60 alerts. [CHAR LIMIT=100] -->
+    <string name="enable_channel_60_alerts_summary">Channel 60 is used in India for Operator specific information</string>
 
     <!-- Preference category title for developer settings. [CHAR LIMIT=50] -->
     <string name="category_dev_settings_title">Developer options</string>
diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml
index 8d3b1fa..35eb1bb 100644
--- a/res/xml/preferences.xml
+++ b/res/xml/preferences.xml
@@ -94,6 +94,17 @@
 
     </PreferenceCategory>
 
+    <!-- This preference is ignored and hidden
+         unless the boolean "show_india_settings" is set to true in config.xml. -->
+    <PreferenceCategory android:title="@string/category_india_settings_title"
+                        android:key="category_india_settings">
+
+        <CheckBoxPreference android:key="enable_channel_60_alerts"
+                            android:summary="@string/enable_channel_60_alerts_summary"
+                            android:title="@string/enable_channel_60_alerts_title" />
+
+    </PreferenceCategory>
+
     <!-- Only visible when Developer options toggle is enabled in Settings. -->
     <PreferenceCategory android:title="@string/category_dev_settings_title"
                         android:key="category_dev_settings">
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertService.java b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertService.java
index ef4ead8..8ea36b0 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastAlertService.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastAlertService.java
@@ -28,9 +28,13 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.SystemProperties;
+import android.preference.PreferenceManager;
 import android.provider.Telephony;
 import android.telephony.CellBroadcastMessage;
+import android.telephony.TelephonyManager;
 import android.telephony.SmsCbCmasInfo;
+import android.telephony.SmsCbEtwsInfo;
 import android.telephony.SmsCbLocation;
 import android.telephony.SmsCbMessage;
 import android.telephony.SubscriptionManager;
@@ -58,6 +62,17 @@
     /** Sticky broadcast for latest area info broadcast received. */
     static final String CB_AREA_INFO_RECEIVED_ACTION =
             "android.cellbroadcastreceiver.CB_AREA_INFO_RECEIVED";
+    /** system property to enable/disable broadcast duplicate detecion.  */
+    private static final String CB_DUP_DETECTION = "persist.cb.dup_detection";
+
+    /** Check for system property to enable/disable duplicate detection.  */
+    static boolean mUseDupDetection = SystemProperties.getBoolean(CB_DUP_DETECTION, true);
+
+    /** Channel 50 Cell Broadcast. */
+    static final int CB_CHANNEL_50 = 50;
+
+    /** Channel 60 Cell Broadcast. */
+    static final int CB_CHANNEL_60 = 60;
 
     /**
      *  Container for service category, serial number, location, and message body hash code for
@@ -68,6 +83,7 @@
         private final int mSerialNumber;
         private final SmsCbLocation mLocation;
         private final int mBodyHash;
+        private final SmsCbEtwsInfo mEtwsWarningInfo;
 
         MessageServiceCategoryAndScope(int serviceCategory, int serialNumber,
                 SmsCbLocation location, int bodyHash) {
@@ -75,10 +91,23 @@
             mSerialNumber = serialNumber;
             mLocation = location;
             mBodyHash = bodyHash;
+            mEtwsWarningInfo = null;
+        }
+        MessageServiceCategoryAndScope(int serviceCategory, int serialNumber,
+                SmsCbLocation location, int bodyHash, SmsCbEtwsInfo etwsWarningInfo) {
+            mServiceCategory = serviceCategory;
+            mSerialNumber = serialNumber;
+            mLocation = location;
+            mBodyHash = bodyHash;
+            mEtwsWarningInfo = etwsWarningInfo;
         }
 
         @Override
         public int hashCode() {
+            if (mEtwsWarningInfo != null) {
+                return mEtwsWarningInfo.hashCode() + mLocation.hashCode() + 5 * mServiceCategory
+                        + 7 * mSerialNumber + 13 * mBodyHash;
+            }
             return mLocation.hashCode() + 5 * mServiceCategory + 7 * mSerialNumber + 13 * mBodyHash;
         }
 
@@ -89,6 +118,14 @@
             }
             if (o instanceof MessageServiceCategoryAndScope) {
                 MessageServiceCategoryAndScope other = (MessageServiceCategoryAndScope) o;
+                if (mEtwsWarningInfo == null && other.mEtwsWarningInfo != null) {
+                    return false;
+                } else if (mEtwsWarningInfo != null && other.mEtwsWarningInfo == null) {
+                    return false;
+                } else if (mEtwsWarningInfo != null && other.mEtwsWarningInfo != null
+                        && !mEtwsWarningInfo.equals(other.mEtwsWarningInfo)) {
+                    return false;
+                }
                 return (mServiceCategory == other.mServiceCategory &&
                         mSerialNumber == other.mSerialNumber &&
                         mLocation.equals(other.mLocation) &&
@@ -99,8 +136,10 @@
 
         @Override
         public String toString() {
-            return "{mServiceCategory: " + mServiceCategory + " serial number: " + mSerialNumber +
-                    " location: " + mLocation.toString() + " body hash: " + mBodyHash + '}';
+            return "{mServiceCategory: " + mServiceCategory + " serial number: " + mSerialNumber
+                    + " location: " + mLocation.toString() + " mEtwsWarningInfo: "
+                    + (mEtwsWarningInfo == null ? "NULL" : mEtwsWarningInfo.toString())
+                    + " body hash: " + mBodyHash +'}';
         }
     }
 
@@ -175,33 +214,37 @@
         // and category should be used for duplicate detection.
         int hashCode = message.isEtwsMessage() ? message.getMessageBody().hashCode() : 0;
 
-        // Check for duplicate message IDs according to CMAS carrier requirements. Message IDs
-        // are stored in volatile memory. If the maximum of 65535 messages is reached, the
-        // message ID of the oldest message is deleted from the list.
-        MessageServiceCategoryAndScope newCmasId = new MessageServiceCategoryAndScope(
-                message.getServiceCategory(), message.getSerialNumber(), message.getLocation(),
-                hashCode);
+        if (mUseDupDetection) {
+            // Check for duplicate message IDs according to CMAS carrier requirements. Message IDs
+            // are stored in volatile memory. If the maximum of 65535 messages is reached, the
+            // message ID of the oldest message is deleted from the list.
+            MessageServiceCategoryAndScope newCmasId = new MessageServiceCategoryAndScope(
+                    message.getServiceCategory(), message.getSerialNumber(), message.getLocation(),
+                            hashCode, message.getEtwsWarningInfo());
+            Log.v(TAG,"newCmasId:" + newCmasId + " hash: " + newCmasId.hashCode()
+                + "body hash:" + hashCode);
 
-        // Add the new message ID to the list. It's okay if this is a duplicate message ID,
-        // because the list is only used for removing old message IDs from the hash set.
-        if (sCmasIdList.size() < MAX_MESSAGE_ID_SIZE) {
-            sCmasIdList.add(newCmasId);
-        } else {
-            // Get oldest message ID from the list and replace with the new message ID.
-            MessageServiceCategoryAndScope oldestCmasId = sCmasIdList.get(sCmasIdListIndex);
-            sCmasIdList.set(sCmasIdListIndex, newCmasId);
-            Log.d(TAG, "message ID limit reached, removing oldest message ID " + oldestCmasId);
-            // Remove oldest message ID from the set.
-            sCmasIdSet.remove(oldestCmasId);
-            if (++sCmasIdListIndex >= MAX_MESSAGE_ID_SIZE) {
-                sCmasIdListIndex = 0;
+            // Add the new message ID to the list. It's okay if this is a duplicate message ID,
+            // because the list is only used for removing old message IDs from the hash set.
+            if (sCmasIdList.size() < MAX_MESSAGE_ID_SIZE) {
+                sCmasIdList.add(newCmasId);
+            } else {
+                // Get oldest message ID from the list and replace with the new message ID.
+                MessageServiceCategoryAndScope oldestCmasId = sCmasIdList.get(sCmasIdListIndex);
+                sCmasIdList.set(sCmasIdListIndex, newCmasId);
+                Log.d(TAG, "message ID limit reached, removing oldest message ID " + oldestCmasId);
+                // Remove oldest message ID from the set.
+                sCmasIdSet.remove(oldestCmasId);
+                if (++sCmasIdListIndex >= MAX_MESSAGE_ID_SIZE) {
+                    sCmasIdListIndex = 0;
+                }
+             }
+            // Set.add() returns false if message ID has already been added
+            if (!sCmasIdSet.add(newCmasId)) {
+                Log.d(TAG, "ignoring duplicate alert with " + newCmasId);
+                return;
             }
         }
-        // Set.add() returns false if message ID has already been added
-        if (!sCmasIdSet.add(newCmasId)) {
-            Log.d(TAG, "ignoring duplicate alert with " + newCmasId);
-            return;
-        }
 
         final Intent alertIntent = new Intent(SHOW_NEW_ALERT_ACTION);
         alertIntent.setClass(this, CellBroadcastAlertService.class);
@@ -259,7 +302,6 @@
      * @return true if the user has enabled this message type; false otherwise
      */
     private boolean isMessageEnabledByUser(CellBroadcastMessage message) {
-
         // Check if ETWS/CMAS test message is forced to disabled on the device.
         boolean forceDisableEtwsCmasTest =
                 CellBroadcastSettings.isEtwsCmasTestMessageForcedDisabled(this, message.getSubId());
@@ -304,10 +346,23 @@
                     return true;    // presidential-level CMAS alerts are always enabled
             }
         }
-
-        if (message.getServiceCategory() == 50) {
-            // save latest area info broadcast for Settings display and send as broadcast
-            CellBroadcastReceiverApp.setLatestAreaInfo(message);
+        int serviceCategory = message.getServiceCategory();
+        if (serviceCategory == CB_CHANNEL_50 || serviceCategory == CB_CHANNEL_60) {
+            boolean channel60Preference = false;
+            if (serviceCategory == CB_CHANNEL_50) {
+                // save latest area info on channel 50 for Settings display
+                CellBroadcastReceiverApp.setLatestAreaInfo(message);
+            } else { //it is Channel 60 CB
+                boolean enable60Channel =  SubscriptionManager.getResourcesForSubId(
+                        getApplicationContext(), message.getSubId()).getBoolean(
+                        R.bool.show_india_settings);
+                if (enable60Channel) {
+                    channel60Preference = PreferenceManager.getDefaultSharedPreferences(this).
+                            getBoolean(CellBroadcastSettings.KEY_ENABLE_CHANNEL_60_ALERTS,
+                            enable60Channel);
+                }
+            }
+            // send broadcasts for channel 50 and 60
             Intent intent = new Intent(CB_AREA_INFO_RECEIVED_ACTION);
             intent.putExtra("message", message);
             // Send broadcast twice, once for apps that have PRIVILEGED permission and once
@@ -316,9 +371,15 @@
                     android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
             sendBroadcastAsUser(intent, UserHandle.ALL,
                     android.Manifest.permission.READ_PHONE_STATE);
-            return false;   // area info broadcasts are displayed in Settings status screen
-        }
 
+            String country = TelephonyManager.getDefault().getSimCountryIso(message.getSubId());
+            // In Brazil(50)/India(50/60) the area info broadcasts are displayed in Settings,
+            // CBwidget or Mms.
+            // But in other country it should be displayed as a normal CB alert.
+            boolean needIgnore = "in".equals(country)
+                    || ("br".equals(country) && (message.getServiceCategory() == CB_CHANNEL_50));
+            return ((!needIgnore) || channel60Preference);
+        }
         return true;    // other broadcast messages are always enabled
     }
 
@@ -333,7 +394,6 @@
         // Close dialogs and window shade
         Intent closeDialogs = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         sendBroadcast(closeDialogs);
-
         // start audio/vibration/speech service for emergency alerts
         Intent audioIntent = new Intent(this, CellBroadcastAlertAudio.class);
         audioIntent.setAction(CellBroadcastAlertAudio.ACTION_START_ALERT_AUDIO);
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastConfigService.java b/src/com/android/cellbroadcastreceiver/CellBroadcastConfigService.java
index 88e5c74..8133c51 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastConfigService.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastConfigService.java
@@ -168,13 +168,22 @@
                 TelephonyManager tm = (TelephonyManager) getSystemService(
                         Context.TELEPHONY_SERVICE);
 
-                boolean enableChannel50Support = res.getBoolean(R.bool.show_brazil_settings) ||
-                        "br".equals(tm.getSimCountryIso());
+                String country = tm.getSimCountryIso(subId);
+                boolean enableChannel50Support = res.getBoolean(R.bool.show_brazil_settings)
+                        || "br".equals(country) || res.getBoolean(R.bool.show_india_settings)
+                        || "in".equals(country);
+
+                boolean enableChannel60Support = res.getBoolean(R.bool.show_india_settings)
+                        || "in".equals(tm.getSimCountryIso());
 
                 boolean enableChannel50Alerts = enableChannel50Support &&
                         SubscriptionManager.getBooleanSubscriptionProperty(subId,
                                 SubscriptionManager.CB_CHANNEL_50_ALERT, true, this);
 
+                boolean enableChannel60Alerts = enableChannel60Support &&
+                        SubscriptionManager.getBooleanSubscriptionProperty(subId,
+                                SubscriptionManager.CB_CHANNEL_60_ALERT, true, this);
+
                 // Note:  ETWS is for 3GPP only
 
                 // Check if ETWS/CMAS test message is forced disabled on the device.
@@ -346,6 +355,21 @@
                     manager.disableCellBroadcast(50, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM);
                 }
 
+                // Enable Channel 60 for India
+                if (isCdma) {
+                    if (DBG) log("channel 60 is not applicable for cdma");
+                } else { //gsm type
+                    if (enableChannel60Alerts) {
+                        if (DBG) log("enabling cell broadcast channel 60");
+                        manager.enableCellBroadcast(60, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM);
+                        if (DBG) log("enabled cell broadcast channel 60");
+                    } else {
+                        if (DBG) log("disabling cell broadcast channel 60");
+                        manager.disableCellBroadcast(60, SmsManager.CELL_BROADCAST_RAN_TYPE_GSM);
+                        if (DBG) log("disabled cell broadcast channel 60");
+                    }
+                }
+
                 if ("il".equals(tm.getSimCountryIso()) || "il".equals(tm.getNetworkCountryIso())) {
                     if (DBG) log("enabling channels 919-928 for Israel");
                     manager.enableCellBroadcastRange(919, 928,
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastReceiver.java b/src/com/android/cellbroadcastreceiver/CellBroadcastReceiver.java
index f255f63..d776b8a 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastReceiver.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastReceiver.java
@@ -46,8 +46,8 @@
 
 public class CellBroadcastReceiver extends BroadcastReceiver {
     private static final String TAG = "CellBroadcastReceiver";
-    static final boolean DBG = false;    // STOPSHIP: change to false before ship
-    private static int mServiceState = -1;
+    static final boolean DBG = true;    // STOPSHIP: change to false before ship
+    private int[] mServiceState = null;
     private static final String GET_LATEST_CB_AREA_INFO_ACTION =
             "android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO";
 
@@ -63,18 +63,32 @@
 
         if (TelephonyIntents.ACTION_SERVICE_STATE_CHANGED.equals(action)) {
             if (DBG) log("Intent ACTION_SERVICE_STATE_CHANGED");
-            int subId = intent.getExtras().getInt(PhoneConstants.SUBSCRIPTION_KEY);
+            int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+                    SubscriptionManager.INVALID_SUBSCRIPTION_ID);
             Log.d(TAG, "subscriptionId = " + subId);
             if (!SubscriptionManager.isValidSubscriptionId(subId)) {
                 return;
             }
             ServiceState serviceState = ServiceState.newFromBundle(intent.getExtras());
             int newState = serviceState.getState();
-            if (newState != mServiceState) {
+            SubscriptionInfo subInfo = SubscriptionManager.from(context).
+                    getActiveSubscriptionInfo(subId);
+            if (subInfo == null) {
+                loge("subId is not active:" + subId);
+                return;
+            }
+            int slotId = subInfo.getSimSlotIndex();
+            if (mServiceState == null) {
+                int phoneCount = TelephonyManager.getDefault().getPhoneCount();
+                mServiceState = new int[phoneCount];
+                for (int i = 0; i < phoneCount; i++) {
+                    mServiceState[i] =  ServiceState.STATE_OUT_OF_SERVICE;
+                }
+            }
+            if (newState != mServiceState[slotId]) {
                 Log.d(TAG, "Service state changed! " + newState + " Full: " + serviceState +
-                        " Current state=" + mServiceState);
-                mServiceState = newState;
-
+                        " Current state=" + mServiceState[slotId]);
+                mServiceState[slotId] = newState;
                 if (((newState == ServiceState.STATE_IN_SERVICE) ||
                         (newState == ServiceState.STATE_EMERGENCY_ONLY)) &&
                         (UserHandle.myUserId() == UserHandle.USER_OWNER)) {
@@ -121,18 +135,20 @@
             }
         } else if (GET_LATEST_CB_AREA_INFO_ACTION.equals(action)) {
             if (privileged) {
-                CellBroadcastMessage message = CellBroadcastReceiverApp.getLatestAreaInfo();
-                if (message != null) {
-                    Intent areaInfoIntent = new Intent(
-                            CellBroadcastAlertService.CB_AREA_INFO_RECEIVED_ACTION);
-                    areaInfoIntent.putExtra("message", message);
-                    // Send broadcast twice, once for apps that have PRIVILEGED permission and once
-                    // for those that have the runtime one
-                    context.sendBroadcastAsUser(areaInfoIntent, UserHandle.ALL,
-                            android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
-                    context.sendBroadcastAsUser(areaInfoIntent, UserHandle.ALL,
-                            android.Manifest.permission.READ_PHONE_STATE);
-                }
+                int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+                        SubscriptionManager.getDefaultSmsSubId());
+                CellBroadcastMessage message = CellBroadcastReceiverApp.getLatestAreaInfo(subId);
+                Log.d(TAG, "onReceive GET_LATEST_CB_AREA_INFO_ACTION subId :" + subId
+                        + "message :" + message);
+                Intent areaInfoIntent = new Intent(
+                        CellBroadcastAlertService.CB_AREA_INFO_RECEIVED_ACTION);
+                areaInfoIntent.putExtra("message", message);
+                // Send broadcast twice, once for apps that have PRIVILEGED permission and once
+                // for those that have the runtime one
+                context.sendBroadcastAsUser(areaInfoIntent, UserHandle.ALL,
+                        android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+                context.sendBroadcastAsUser(areaInfoIntent, UserHandle.ALL,
+                        android.Manifest.permission.READ_PHONE_STATE);
             } else {
                 Log.e(TAG, "caller missing READ_PHONE_STATE permission, returning");
             }
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastReceiverApp.java b/src/com/android/cellbroadcastreceiver/CellBroadcastReceiverApp.java
index b9e6039..2b62177 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastReceiverApp.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastReceiverApp.java
@@ -21,6 +21,8 @@
 import android.util.Log;
 import android.preference.PreferenceManager;
 
+import java.util.HashMap;
+import java.util.Map;
 import java.util.ArrayList;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -43,7 +45,8 @@
             new ArrayList<CellBroadcastMessage>(4);
 
     /** Latest area info cell broadcast received. */
-    private static CellBroadcastMessage sLatestAreaInfo;
+    private static Map<Integer, CellBroadcastMessage> sLatestAreaInfo =
+            new HashMap<Integer, CellBroadcastMessage>();
 
     /** Adds a new unread non-emergency message and returns the current list. */
     static ArrayList<CellBroadcastMessage> addNewMessageToList(CellBroadcastMessage message) {
@@ -58,11 +61,11 @@
 
     /** Saves the latest area info broadcast received. */
     static void setLatestAreaInfo(CellBroadcastMessage areaInfo) {
-        sLatestAreaInfo = areaInfo;
+        sLatestAreaInfo.put(areaInfo.getSubId(), areaInfo);
     }
 
     /** Returns the latest area info broadcast received. */
-    static CellBroadcastMessage getLatestAreaInfo() {
-        return sLatestAreaInfo;
+    static CellBroadcastMessage getLatestAreaInfo(int subId) {
+        return sLatestAreaInfo.get(subId);
     }
 }
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastSearchIndexableProvider.java b/src/com/android/cellbroadcastreceiver/CellBroadcastSearchIndexableProvider.java
index b8f56eb..e4c3014 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastSearchIndexableProvider.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastSearchIndexableProvider.java
@@ -144,6 +144,16 @@
             cursor.addRow(ref);
         }
 
+        boolean enableChannel60Support = res.getBoolean(R.bool.show_india_settings) ||
+                "in".equals(tm.getSimCountryIso());
+
+        if (!enableChannel60Support) {
+            ref = new Object[1];
+            ref[COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE] =
+                    CellBroadcastSettings.KEY_CATEGORY_INDIA_SETTINGS;
+            cursor.addRow(ref);
+        }
+
         if (!enableDevSettings) {
             ref = new Object[1];
             ref[COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE] =
diff --git a/src/com/android/cellbroadcastreceiver/CellBroadcastSettings.java b/src/com/android/cellbroadcastreceiver/CellBroadcastSettings.java
index 2e83dbc..f8b02b2 100644
--- a/src/com/android/cellbroadcastreceiver/CellBroadcastSettings.java
+++ b/src/com/android/cellbroadcastreceiver/CellBroadcastSettings.java
@@ -90,9 +90,14 @@
     // Preference category for Brazil specific settings.
     public static final String KEY_CATEGORY_BRAZIL_SETTINGS = "category_brazil_settings";
 
+    // Preference category for India specific settings.
+    public static final String KEY_CATEGORY_INDIA_SETTINGS = "category_india_settings";
+
     // Preference key for whether to enable channel 50 notifications
     // Enabled by default for phones sold in Brazil, otherwise this setting may be hidden.
     public static final String KEY_ENABLE_CHANNEL_50_ALERTS = "enable_channel_50_alerts";
+    // Preference key for whether to enable channel 60 notifications
+    public static final String KEY_ENABLE_CHANNEL_60_ALERTS = "enable_channel_60_alerts";
 
     // Preference key for initial opt-in/opt-out dialog.
     public static final String KEY_SHOW_CMAS_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
@@ -121,6 +126,7 @@
     private CheckBoxPreference mSpeechCheckBox;
     private CheckBoxPreference mEtwsTestCheckBox;
     private CheckBoxPreference mChannel50CheckBox;
+    private CheckBoxPreference mChannel60CheckBox;
     private CheckBoxPreference mCmasCheckBox;
     private CheckBoxPreference mOptOutCheckBox;
     private PreferenceCategory mAlertCategory;
@@ -193,6 +199,8 @@
                     findPreference(KEY_ENABLE_ETWS_TEST_ALERTS);
             mChannel50CheckBox = (CheckBoxPreference)
                     findPreference(KEY_ENABLE_CHANNEL_50_ALERTS);
+            mChannel60CheckBox = (CheckBoxPreference)
+                    findPreference(KEY_ENABLE_CHANNEL_60_ALERTS);
             mCmasCheckBox = (CheckBoxPreference)
                     findPreference(KEY_ENABLE_CMAS_TEST_ALERTS);
             mOptOutCheckBox = (CheckBoxPreference)
@@ -211,6 +219,7 @@
                 mSpeechCheckBox.setEnabled(false);
                 mEtwsTestCheckBox.setEnabled(false);
                 mChannel50CheckBox.setEnabled(false);
+                mChannel60CheckBox.setEnabled(false);
                 mCmasCheckBox.setEnabled(false);
                 mOptOutCheckBox.setEnabled(false);
                 return;
@@ -236,6 +245,12 @@
                                                     SubscriptionManager.CB_CHANNEL_50_ALERT,
                                                     newVal + "");
                                     break;
+                                case KEY_ENABLE_CHANNEL_60_ALERTS:
+                                    SubscriptionManager
+                                            .setSubscriptionProperty(mSir.getSubscriptionId(),
+                                                    SubscriptionManager.CB_CHANNEL_60_ALERT,
+                                                    newVal + "");
+                                    break;
                                 case KEY_ENABLE_ETWS_TEST_ALERTS:
                                     SubscriptionManager
                                             .setSubscriptionProperty(mSir.getSubscriptionId(),
@@ -401,11 +416,24 @@
             boolean enableChannel50Support = SubscriptionManager.getResourcesForSubId(
                     getApplicationContext(), mSir.getSubscriptionId()).getBoolean(
                     R.bool.show_brazil_settings)
-                    || "br".equals(mTelephonyManager.getSimCountryIso());
+                    || "br".equals(mTelephonyManager.getSimCountryIso(mSir.getSubscriptionId()))
+                    || SubscriptionManager.getResourcesForSubId(
+                    getApplicationContext(), mSir.getSubscriptionId()).getBoolean(
+                    R.bool.show_india_settings)
+                    || "in".equals(mTelephonyManager.getSimCountryIso(mSir.getSubscriptionId()));
 
             if (!enableChannel50Support) {
                 prefScreen.removePreference(findPreference(KEY_CATEGORY_BRAZIL_SETTINGS));
             }
+
+            boolean enableChannel60Support = SubscriptionManager.getResourcesForSubId(
+                    getApplicationContext(), mSir.getSubscriptionId()).getBoolean(
+                    R.bool.show_india_settings)
+                    || "in".equals(mTelephonyManager.getSimCountryIso(mSir.getSubscriptionId()));
+
+            if (!enableChannel60Support) {
+                prefScreen.removePreference(findPreference(KEY_CATEGORY_INDIA_SETTINGS));
+            }
             if (!enableDevSettings) {
                 prefScreen.removePreference(findPreference(KEY_CATEGORY_DEV_SETTINGS));
             }
@@ -480,6 +508,16 @@
                 mChannel50CheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
             }
 
+            if (mChannel60CheckBox != null) {
+                if (SubscriptionManager.getBooleanSubscriptionProperty(mSir.getSubscriptionId(),
+                        SubscriptionManager.CB_CHANNEL_60_ALERT, true, this)) {
+                    mChannel60CheckBox.setChecked(true);
+                } else {
+                    mChannel60CheckBox.setChecked(false);
+                }
+                mChannel60CheckBox.setOnPreferenceChangeListener(startConfigServiceListener);
+            }
+
             if (mEtwsTestCheckBox != null) {
                 if (!forceDisableEtwsCmasTest &&
                         SubscriptionManager.getBooleanSubscriptionProperty(mSir.getSubscriptionId(),