Merge change 7522

* changes:
  EventHub: Add support for excluding devices from being opened by as a keyboard.
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index 80d688e..bcddca1 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -24,7 +24,6 @@
 import android.content.res.TypedArray;
 import android.database.DataSetObserver;
 import android.util.AttributeSet;
-import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -40,6 +39,7 @@
 public class Spinner extends AbsSpinner implements OnClickListener {
     
     private CharSequence mPrompt;
+    private AlertDialog mPopup;
 
     public Spinner(Context context) {
         this(context, null);
@@ -78,6 +78,16 @@
         }
     }
 
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        
+        if (mPopup != null && mPopup.isShowing()) {
+            mPopup.dismiss();
+            mPopup = null;
+        }
+    }
+
     /**
      * <p>A spinner does not support item click events. Calling this method
      * will raise an exception.</p>
@@ -244,7 +254,7 @@
             if (mPrompt != null) {
                 builder.setTitle(mPrompt);
             }
-            builder.setSingleChoiceItems(adapter, getSelectedItemPosition(), this).show();
+            mPopup = builder.setSingleChoiceItems(adapter, getSelectedItemPosition(), this).show();
         }
 
         return handled;
@@ -253,6 +263,7 @@
     public void onClick(DialogInterface dialog, int which) {
         setSelection(which);
         dialog.dismiss();
+        mPopup = null;
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 5ec4020..8a1e928 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -109,4 +109,10 @@
 
     /** The international dialing prefix conversion string */
     static final String PROPERTY_IDP_STRING = "ro.cdma.idpstring";
+
+    /**
+     * Defines the schema for the carrier specified OTASP number
+     */
+    static final String PROPERTY_OTASP_NUM_SCHEMA = "ro.cdma.otaspnumschema";
+
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 1cd6e58..f04d26c 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -60,12 +60,16 @@
 import java.util.List;
 import java.util.Timer;
 import java.util.TimerTask;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 /**
  * {@hide}
  */
 public class CDMAPhone extends PhoneBase {
     static final String LOG_TAG = "CDMA";
-    private static final boolean LOCAL_DEBUG = true;
+    private static final boolean DBG = true;
 
     // Default Emergency Callback Mode exit timer
     private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
@@ -100,6 +104,8 @@
     private Registrant mECMExitRespRegistrant;
     private String mEsn;
     private String mMeid;
+    // string to define how the carrier specifies its own ota sp number
+    private String mCarrierOtaSpNumSchema;
 
     // A runnable which is used to automatically exit from ECM after a period of time.
     private Runnable mExitEcmRunnable = new Runnable() {
@@ -155,6 +161,10 @@
         String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
         mIsPhoneInECMState = inEcm.equals("true");
 
+        // get the string that specifies the carrier OTA Sp number
+        mCarrierOtaSpNumSchema = SystemProperties.get(
+                TelephonyProperties.PROPERTY_OTASP_NUM_SCHEMA,"");
+
         // Notify voicemails.
         notifier.notifyMessageWaitingChanged(this);
     }
@@ -203,7 +213,7 @@
     }
 
     protected void finalize() {
-        if(LOCAL_DEBUG) Log.d(LOG_TAG, "CDMAPhone finalized");
+        if(DBG) Log.d(LOG_TAG, "CDMAPhone finalized");
     }
 
 
@@ -935,7 +945,7 @@
                         break;
                     }
 
-                    if (LOCAL_DEBUG) Log.d(LOG_TAG, "Baseband version: " + ar.result);
+                    if (DBG) Log.d(LOG_TAG, "Baseband version: " + ar.result);
                     setSystemProperty(TelephonyProperties.PROPERTY_BASEBAND_VERSION, (String)ar.result);
                 }
                 break;
@@ -1129,10 +1139,10 @@
         mSMS.setCellBroadcastConfig(configValuesArray, response);
     }
 
-    public static final String IS683A_FEATURE_CODE = "*228" ;
-    public static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4 ;
-    public static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2 ;
-    public static final int IS683A_SYS_SEL_CODE_OFFSET = 4;
+    private static final String IS683A_FEATURE_CODE = "*228";
+    private static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4;
+    private static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2;
+    private static final int IS683A_SYS_SEL_CODE_OFFSET = 4;
 
     private static final int IS683_CONST_800MHZ_A_BAND = 0;
     private static final int IS683_CONST_800MHZ_B_BAND = 1;
@@ -1142,6 +1152,7 @@
     private static final int IS683_CONST_1900MHZ_D_BLOCK = 5;
     private static final int IS683_CONST_1900MHZ_E_BLOCK = 6;
     private static final int IS683_CONST_1900MHZ_F_BLOCK = 7;
+    private static final int INVALID_SYSTEM_SELECTION_CODE = -1;
 
     private boolean isIs683OtaSpDialStr(String dialStr) {
         int sysSelCodeInt;
@@ -1152,39 +1163,147 @@
             if (dialStr.equals(IS683A_FEATURE_CODE)) {
                 isOtaspDialString = true;
             }
-        } else if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE, 0,
-                                          IS683A_FEATURE_CODE_NUM_DIGITS) == true)
-                    && (dialStrLen >=
-                        (IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS))) {
-            StringBuilder sb = new StringBuilder(dialStr);
-            // Separate the System Selection Code into its own string
-            char[] sysSel = new char[2];
-            sb.delete(0, IS683A_SYS_SEL_CODE_OFFSET);
-            sb.getChars(0, IS683A_SYS_SEL_CODE_NUM_DIGITS, sysSel, 0);
-
-            if ((PhoneNumberUtils.isISODigit(sysSel[0]))
-                    && (PhoneNumberUtils.isISODigit(sysSel[1]))) {
-                String sysSelCode = new String(sysSel);
-                sysSelCodeInt = Integer.parseInt((String)sysSelCode);
-                switch (sysSelCodeInt) {
-                    case IS683_CONST_800MHZ_A_BAND:
-                    case IS683_CONST_800MHZ_B_BAND:
-                    case IS683_CONST_1900MHZ_A_BLOCK:
-                    case IS683_CONST_1900MHZ_B_BLOCK:
-                    case IS683_CONST_1900MHZ_C_BLOCK:
-                    case IS683_CONST_1900MHZ_D_BLOCK:
-                    case IS683_CONST_1900MHZ_E_BLOCK:
-                    case IS683_CONST_1900MHZ_F_BLOCK:
-                        isOtaspDialString = true;
-                        break;
-
-                    default:
-                        break;
-                }
+        } else {
+            sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
+            switch (sysSelCodeInt) {
+                case IS683_CONST_800MHZ_A_BAND:
+                case IS683_CONST_800MHZ_B_BAND:
+                case IS683_CONST_1900MHZ_A_BLOCK:
+                case IS683_CONST_1900MHZ_B_BLOCK:
+                case IS683_CONST_1900MHZ_C_BLOCK:
+                case IS683_CONST_1900MHZ_D_BLOCK:
+                case IS683_CONST_1900MHZ_E_BLOCK:
+                case IS683_CONST_1900MHZ_F_BLOCK:
+                    isOtaspDialString = true;
+                    break;
+                default:
+                    break;
             }
         }
         return isOtaspDialString;
     }
+    /**
+     * This function extracts the system selection code from the dial string.
+     */
+    private int extractSelCodeFromOtaSpNum(String dialStr) {
+        int dialStrLen = dialStr.length();
+        int sysSelCodeInt = INVALID_SYSTEM_SELECTION_CODE;
+
+        if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE,
+                                   0, IS683A_FEATURE_CODE_NUM_DIGITS)) &&
+            (dialStrLen >= (IS683A_FEATURE_CODE_NUM_DIGITS +
+                            IS683A_SYS_SEL_CODE_NUM_DIGITS))) {
+                // Since we checked the condition above, the system selection code
+                // extracted from dialStr will not cause any exception
+                sysSelCodeInt = Integer.parseInt (
+                                dialStr.substring (IS683A_FEATURE_CODE_NUM_DIGITS,
+                                IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS));
+        }
+        if (DBG) Log.d(LOG_TAG, "extractSelCodeFromOtaSpNum " + sysSelCodeInt);
+        return sysSelCodeInt;
+    }
+
+    /**
+     * This function checks if the system selection code extracted from
+     * the dial string "sysSelCodeInt' is the system selection code specified
+     * in the carrier ota sp number schema "sch".
+     */
+    private boolean
+    checkOtaSpNumBasedOnSysSelCode (int sysSelCodeInt, String sch[]) {
+        boolean isOtaSpNum = false;
+        try {
+            // Get how many number of system selection code ranges
+            int selRc = Integer.parseInt((String)sch[1]);
+            for (int i = 0; i < selRc; i++) {
+                if (!TextUtils.isEmpty(sch[i+2]) && !TextUtils.isEmpty(sch[i+3])) {
+                    int selMin = Integer.parseInt((String)sch[i+2]);
+                    int selMax = Integer.parseInt((String)sch[i+3]);
+                    // Check if the selection code extracted from the dial string falls
+                    // within any of the range pairs specified in the schema.
+                    if ((sysSelCodeInt >= selMin) && (sysSelCodeInt <= selMax)) {
+                        isOtaSpNum = true;
+                        break;
+                    }
+                }
+            }
+        } catch (NumberFormatException ex) {
+            // If the carrier ota sp number schema is not correct, we still allow dial
+            // and only log the error:
+            Log.e(LOG_TAG, "checkOtaSpNumBasedOnSysSelCode, error", ex);
+        }
+        return isOtaSpNum;
+    }
+
+    // Define the pattern/format for carrier specified OTASP number schema.
+    // It separates by comma and/or whitespace.
+    private static Pattern pOtaSpNumSchema = Pattern.compile("[,\\s]+");
+
+    /**
+     * The following function checks if a dial string is a carrier specified
+     * OTASP number or not by checking against the OTASP number schema stored
+     * in PROPERTY_OTASP_NUM_SCHEMA.
+     *
+     * Currently, there are 2 schemas for carriers to specify the OTASP number:
+     * 1) Use system selection code:
+     *    The schema is:
+     *    SELC,the # of code pairs,min1,max1,min2,max2,...
+     *    e.g "SELC,3,10,20,30,40,60,70" indicates that there are 3 pairs of
+     *    selection codes, and they are {10,20}, {30,40} and {60,70} respectively.
+     *
+     * 2) Use feature code:
+     *    The schema is:
+     *    "FC,length of feature code,feature code".
+     *     e.g "FC,2,*2" indicates that the length of the feature code is 2,
+     *     and the code itself is "*2".
+     */
+    private boolean isCarrierOtaSpNum(String dialStr) {
+        boolean isOtaSpNum = false;
+        int sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
+        if (sysSelCodeInt == INVALID_SYSTEM_SELECTION_CODE) {
+            return isOtaSpNum;
+        }
+        // mCarrierOtaSpNumSchema is retrieved from PROPERTY_OTASP_NUM_SCHEMA:
+        if (!TextUtils.isEmpty(mCarrierOtaSpNumSchema)) {
+            Matcher m = pOtaSpNumSchema.matcher(mCarrierOtaSpNumSchema);
+            if (DBG) {
+                Log.d(LOG_TAG, "isCarrierOtaSpNum,schema" + mCarrierOtaSpNumSchema);
+            }
+
+            if (m.find()) {
+                String sch[] = pOtaSpNumSchema.split(mCarrierOtaSpNumSchema);
+                // If carrier uses system selection code mechanism
+                if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("SELC")) {
+                    if (sysSelCodeInt!=INVALID_SYSTEM_SELECTION_CODE) {
+                        isOtaSpNum=checkOtaSpNumBasedOnSysSelCode(sysSelCodeInt,sch);
+                    } else {
+                        if (DBG) {
+                            Log.d(LOG_TAG, "isCarrierOtaSpNum,sysSelCodeInt is invalid");
+                        }
+                    }
+                } else if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("FC")) {
+                    int fcLen =  Integer.parseInt((String)sch[1]);
+                    String fc = (String)sch[2];
+                    if (dialStr.regionMatches(0,fc,0,fcLen)) {
+                        isOtaSpNum = true;
+                    } else {
+                        if (DBG) Log.d(LOG_TAG, "isCarrierOtaSpNum,not otasp number");
+                    }
+                } else {
+                    if (DBG) {
+                        Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema not supported" + sch[0]);
+                    }
+                }
+            } else {
+                if (DBG) {
+                    Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern not right" +
+                          mCarrierOtaSpNumSchema);
+                }
+            }
+        } else {
+            if (DBG) Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern empty");
+        }
+        return isOtaSpNum;
+    }
 
      /**
       * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier
@@ -1196,12 +1315,13 @@
     @Override
      public  boolean isOtaSpNumber(String dialStr){
          boolean isOtaSpNum = false;
-         if(dialStr != null){
-             isOtaSpNum=isIs683OtaSpDialStr(dialStr);
+         if (dialStr != null) {
+             isOtaSpNum = isIs683OtaSpDialStr(dialStr);
              if(isOtaSpNum == false){
-             //TO DO:Add carrier specific OTASP number detection here.
+                 isOtaSpNum = isCarrierOtaSpNum(dialStr);
              }
          }
+         if (DBG) Log.d(LOG_TAG, "isOtaSpNumber " + isOtaSpNum);
          return isOtaSpNum;
      }