Merge "Add support of dislaying Alpha tag for BIP commands" into ics-mr1
diff --git a/telephony/java/com/android/internal/telephony/cat/AppInterface.java b/telephony/java/com/android/internal/telephony/cat/AppInterface.java
index 2eb6ccb..299e140 100644
--- a/telephony/java/com/android/internal/telephony/cat/AppInterface.java
+++ b/telephony/java/com/android/internal/telephony/cat/AppInterface.java
@@ -42,6 +42,7 @@
      * Enumeration for representing "Type of Command" of proactive commands.
      * Those are the only commands which are supported by the Telephony. Any app
      * implementation should support those.
+     * Refer to ETSI TS 102.223 section 9.4
      */
     public static enum CommandType {
         DISPLAY_TEXT(0x21),
@@ -59,7 +60,11 @@
         SET_UP_IDLE_MODE_TEXT(0x28),
         SET_UP_MENU(0x25),
         SET_UP_CALL(0x10),
-        PROVIDE_LOCAL_INFORMATION(0x26);
+        PROVIDE_LOCAL_INFORMATION(0x26),
+        OPEN_CHANNEL(0x40),
+        CLOSE_CHANNEL(0x41),
+        RECEIVE_DATA(0x42),
+        SEND_DATA(0x43);
 
         private int mValue;
 
diff --git a/telephony/java/com/android/internal/telephony/cat/CatCmdMessage.java b/telephony/java/com/android/internal/telephony/cat/CatCmdMessage.java
index 5155bb2..48c2e2b 100644
--- a/telephony/java/com/android/internal/telephony/cat/CatCmdMessage.java
+++ b/telephony/java/com/android/internal/telephony/cat/CatCmdMessage.java
@@ -85,6 +85,13 @@
             mCallSettings.confirmMsg = ((CallSetupParams) cmdParams).confirmMsg;
             mCallSettings.callMsg = ((CallSetupParams) cmdParams).callMsg;
             break;
+        case OPEN_CHANNEL:
+        case CLOSE_CHANNEL:
+        case RECEIVE_DATA:
+        case SEND_DATA:
+            BIPClientParams param = (BIPClientParams) cmdParams;
+            mTextMsg = param.textMsg;
+            break;
         }
     }
 
diff --git a/telephony/java/com/android/internal/telephony/cat/CatService.java b/telephony/java/com/android/internal/telephony/cat/CatService.java
index 5a994f3..74af9fa 100644
--- a/telephony/java/com/android/internal/telephony/cat/CatService.java
+++ b/telephony/java/com/android/internal/telephony/cat/CatService.java
@@ -18,6 +18,8 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -32,6 +34,7 @@
 
 
 import java.io.ByteArrayOutputStream;
+import java.util.List;
 import java.util.Locale;
 
 class RilMessage {
@@ -72,6 +75,7 @@
     private CatCmdMessage mMenuCmd = null;
 
     private RilMessageDecoder mMsgDecoder = null;
+    private boolean mStkAppInstalled = false;
 
     // Service constants.
     static final int MSG_ID_SESSION_END              = 1;
@@ -125,7 +129,10 @@
         mCmdIf.registerForNVReady(this, MSG_ID_SIM_READY, null);
         mIccRecords.registerForRecordsLoaded(this, MSG_ID_ICC_RECORDS_LOADED, null);
 
-        CatLog.d(this, "Is running");
+        // Check if STK application is availalbe
+        mStkAppInstalled = isStkAppInstalled();
+
+        CatLog.d(this, "Running CAT service. STK app installed:" + mStkAppInstalled);
     }
 
     public void dispose() {
@@ -154,7 +161,7 @@
             if (rilMsg.mResCode == ResultCode.OK) {
                 cmdParams = (CommandParams) rilMsg.mData;
                 if (cmdParams != null) {
-                    handleProactiveCommand(cmdParams);
+                    handleCommand(cmdParams, false);
                 }
             }
             break;
@@ -170,7 +177,7 @@
             }
             if (cmdParams != null) {
                 if (rilMsg.mResCode == ResultCode.OK) {
-                    handleProactiveCommand(cmdParams);
+                    handleCommand(cmdParams, true);
                 } else {
                     // for proactive commands that couldn't be decoded
                     // successfully respond with the code generated by the
@@ -183,7 +190,7 @@
         case MSG_ID_REFRESH:
             cmdParams = (CommandParams) rilMsg.mData;
             if (cmdParams != null) {
-                handleProactiveCommand(cmdParams);
+                handleCommand(cmdParams, false);
             }
             break;
         case MSG_ID_SESSION_END:
@@ -197,11 +204,13 @@
     }
 
     /**
-     * Handles RIL_UNSOL_STK_PROACTIVE_COMMAND unsolicited command from RIL.
+     * Handles RIL_UNSOL_STK_EVENT_NOTIFY or RIL_UNSOL_STK_PROACTIVE_COMMAND command
+     * from RIL.
      * Sends valid proactive command data to the application using intents.
-     *
+     * RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE will be send back if the command is
+     * from RIL_UNSOL_STK_PROACTIVE_COMMAND.
      */
-    private void handleProactiveCommand(CommandParams cmdParams) {
+    private void handleCommand(CommandParams cmdParams, boolean isProactiveCmd) {
         CatLog.d(this, cmdParams.getCommandType().name());
 
         CharSequence message;
@@ -235,15 +244,16 @@
                     case CommandParamsFactory.DTTZ_SETTING:
                         resp = new DTTZResponseData(null);
                         sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, resp);
-                        return;
+                        break;
                     case CommandParamsFactory.LANGUAGE_SETTING:
                         resp = new LanguageResponseData(Locale.getDefault().getLanguage());
                         sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, resp);
-                        return;
+                        break;
                     default:
                         sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, null);
-                        return;
                 }
+                // No need to start STK app here.
+                return;
             case LAUNCH_BROWSER:
                 if ((((LaunchBrowserParams) cmdParams).confirmMsg.text != null)
                         && (((LaunchBrowserParams) cmdParams).confirmMsg.text.equals(STK_DEFAULT))) {
@@ -274,6 +284,42 @@
                     ((CallSetupParams) cmdParams).confirmMsg.text = message.toString();
                 }
                 break;
+            case OPEN_CHANNEL:
+            case CLOSE_CHANNEL:
+            case RECEIVE_DATA:
+            case SEND_DATA:
+                BIPClientParams cmd = (BIPClientParams) cmdParams;
+                if (cmd.bHasAlphaId && (cmd.textMsg.text == null)) {
+                    CatLog.d(this, "cmd " + cmdParams.getCommandType() + " with null alpha id");
+                    // If alpha length is zero, we just respond with OK.
+                    if (isProactiveCmd) {
+                        sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, null);
+                    }
+                    return;
+                }
+                // Respond with permanent failure to avoid retry if STK app is not present.
+                if (!mStkAppInstalled) {
+                    CatLog.d(this, "No STK application found.");
+                    if (isProactiveCmd) {
+                        sendTerminalResponse(cmdParams.cmdDet,
+                                             ResultCode.BEYOND_TERMINAL_CAPABILITY,
+                                             false, 0, null);
+                        return;
+                    }
+                }
+                /*
+                 * CLOSE_CHANNEL, RECEIVE_DATA and SEND_DATA can be delivered by
+                 * either PROACTIVE_COMMAND or EVENT_NOTIFY.
+                 * If PROACTIVE_COMMAND is used for those commands, send terminal
+                 * response here.
+                 */
+                if (isProactiveCmd &&
+                    ((cmdParams.getCommandType() == CommandType.CLOSE_CHANNEL) ||
+                     (cmdParams.getCommandType() == CommandType.RECEIVE_DATA) ||
+                     (cmdParams.getCommandType() == CommandType.SEND_DATA))) {
+                    sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, null);
+                }
+                break;
             default:
                 CatLog.d(this, "Unsupported command");
                 return;
@@ -684,6 +730,7 @@
         case NO_RESPONSE_FROM_USER:
         case UICC_SESSION_TERM_BY_USER:
         case BACKWARD_MOVE_BY_USER:
+        case USER_NOT_ACCEPT:
             resp = null;
             break;
         default:
@@ -692,4 +739,14 @@
         sendTerminalResponse(cmdDet, resMsg.resCode, false, 0, resp);
         mCurrntCmd = null;
     }
+
+    private boolean isStkAppInstalled() {
+        Intent intent = new Intent(AppInterface.CAT_CMD_ACTION);
+        PackageManager pm = mContext.getPackageManager();
+        List<ResolveInfo> broadcastReceivers =
+                            pm.queryBroadcastReceivers(intent, PackageManager.GET_META_DATA);
+        int numReceiver = broadcastReceivers == null ? 0 : broadcastReceivers.size();
+
+        return (numReceiver > 0);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/cat/CommandParams.java b/telephony/java/com/android/internal/telephony/cat/CommandParams.java
index 22a5c8c..959c9e2 100644
--- a/telephony/java/com/android/internal/telephony/cat/CommandParams.java
+++ b/telephony/java/com/android/internal/telephony/cat/CommandParams.java
@@ -166,4 +166,29 @@
     }
 }
 
+/*
+ * BIP (Bearer Independent Protocol) is the mechanism for SIM card applications
+ * to access data connection through the mobile device.
+ *
+ * SIM utilizes proactive commands (OPEN CHANNEL, CLOSE CHANNEL, SEND DATA and
+ * RECEIVE DATA to control/read/write data for BIP. Refer to ETSI TS 102 223 for
+ * the details of proactive commands procedures and their structures.
+ */
+class BIPClientParams extends CommandParams {
+    TextMessage textMsg;
+    boolean bHasAlphaId;
 
+    BIPClientParams(CommandDetails cmdDet, TextMessage textMsg, boolean has_alpha_id) {
+        super(cmdDet);
+        this.textMsg = textMsg;
+        this.bHasAlphaId = has_alpha_id;
+    }
+
+    boolean setIcon(Bitmap icon) {
+        if (icon != null && textMsg != null) {
+            textMsg.icon = icon;
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java b/telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java
index e7fca5a..89c1329 100644
--- a/telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java
+++ b/telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java
@@ -165,6 +165,12 @@
              case PROVIDE_LOCAL_INFORMATION:
                 cmdPending = processProvideLocalInfo(cmdDet, ctlvs);
                 break;
+             case OPEN_CHANNEL:
+             case CLOSE_CHANNEL:
+             case RECEIVE_DATA:
+             case SEND_DATA:
+                 cmdPending = processBIPClient(cmdDet, ctlvs);
+                 break;
             default:
                 // unsupported proactive commands
                 mCmdParams = new CommandParams(cmdDet);
@@ -893,4 +899,43 @@
         }
         return false;
     }
+
+    private boolean processBIPClient(CommandDetails cmdDet,
+                                     List<ComprehensionTlv> ctlvs) throws ResultException {
+        AppInterface.CommandType commandType =
+                                    AppInterface.CommandType.fromInt(cmdDet.typeOfCommand);
+        if (commandType != null) {
+            CatLog.d(this, "process "+ commandType.name());
+        }
+
+        TextMessage textMsg = new TextMessage();
+        IconId iconId = null;
+        ComprehensionTlv ctlv = null;
+        boolean has_alpha_id = false;
+
+        // parse alpha identifier
+        ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID, ctlvs);
+        if (ctlv != null) {
+            textMsg.text = ValueParser.retrieveAlphaId(ctlv);
+            CatLog.d(this, "alpha TLV text=" + textMsg.text);
+            has_alpha_id = true;
+        }
+
+        // parse icon identifier
+        ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs);
+        if (ctlv != null) {
+            iconId = ValueParser.retrieveIconId(ctlv);
+            textMsg.iconSelfExplanatory = iconId.selfExplanatory;
+        }
+
+        textMsg.responseNeeded = false;
+        mCmdParams = new BIPClientParams(cmdDet, textMsg, has_alpha_id);
+
+        if (iconId != null) {
+            mIconLoadState = LOAD_SINGLE_ICON;
+            mIconLoader.loadIcon(iconId.recordNumber, this.obtainMessage(MSG_ID_LOAD_ICON_DONE));
+            return true;
+        }
+        return false;
+    }
 }