一、CatService的创建过程
- @UiccCard.java
- public void update(Context c, CommandsInterface ci, IccCardStatus ics) {
- synchronized (mLock) {
- if (mUiccApplications.length > 0 && mUiccApplications[0] != null) {
- //创建CatService
- mCatService = CatService.getInstance(mCi, mContext, this);
- } else {
- if (mCatService != null) {
- mCatService.dispose();
- }
- mCatService = null;
- }
- }
- }
- @CatService.java
- public static CatService getInstance(CommandsInterface ci, Context context, UiccCard ic) {
- UiccCardApplication ca = null;
- IccFileHandler fh = null;
- IccRecords ir = null;
- if (ic != null) {
- //获取UiccCardApplication、IccFileHandler、IccRecords等对象
- ca = ic.getApplicationIndex(0);
- if (ca != null) {
- fh = ca.getIccFileHandler();
- ir = ca.getIccRecords();
- }
- }
- synchronized (sInstanceLock) {
- if (sInstance == null) {
- if (ci == null || ca == null || ir == null || context == null || fh == null || ic == null) {
- return null;
- }
- //创建CatService的消息处理线程
- HandlerThread thread = new HandlerThread("Cat Telephony service");
- thread.start();
- //创建CatService实例对象
- sInstance = new CatService(ci, ca, ir, context, fh, ic);
- } else if ((ir != null) && (mIccRecords != ir)) {
- //CatService已经被创建过,只需要更新其监听器
- if (mIccRecords != null) {
- mIccRecords.unregisterForRecordsLoaded(sInstance);
- }
- if (mUiccApplication != null) {
- mUiccApplication.unregisterForReady(sInstance);
- }
- mIccRecords = ir;
- mUiccApplication = ca;
- mIccRecords.registerForRecordsLoaded(sInstance, MSG_ID_ICC_RECORDS_LOADED, null);
- mUiccApplication.registerForReady(sInstance, MSG_ID_SIM_READY, null);
- } else {
- CatLog.d(sInstance, "Return current sInstance");
- }
- return sInstance;
- }
- }
- private CatService(CommandsInterface ci, UiccCardApplication ca, IccRecords ir, Context context, IccFileHandler fh, UiccCard ic) {
- if (ci == null || ca == null || ir == null || context == null || fh == null || ic == null) {
- throw new NullPointerException( "Service: Input parameters must not be null");
- }
- mCmdIf = ci;
- mContext = context;
- //获取RilMessageDecoder对象
- mMsgDecoder = RilMessageDecoder.getInstance(this, fh);
- //向RIL注册监听器
- mCmdIf.setOnCatSessionEnd(this, MSG_ID_SESSION_END, null);
- mCmdIf.setOnCatProactiveCmd(this, MSG_ID_PROACTIVE_COMMAND, null);
- mCmdIf.setOnCatEvent(this, MSG_ID_EVENT_NOTIFY, null);
- mCmdIf.setOnCatCallSetUp(this, MSG_ID_CALL_SETUP, null);
- mIccRecords = ir;
- mUiccApplication = ca;
- //向UiccCardApplication对象注册SIM Ready的监听器
- //向IccRecords对象注册Icc Record Loaded的监听器
- mUiccApplication.registerForReady(this, MSG_ID_SIM_READY, null);
- mIccRecords.registerForRecordsLoaded(this, MSG_ID_ICC_RECORDS_LOADED, null);
- mStkAppInstalled = isStkAppInstalled();
- }
1、获取RilMessageDecoder对象mMsgDecoder;
2、向RIL注册相关的通知监听;
3、向UiccCardApplication、IccRecords注册SIM卡和Record的监听;
二、CatService的消息机制
1、MSG_ID_SESSION_END
2、MSG_ID_PROACTIVE_COMMAND
3、MSG_ID_RIL_MSG_DECODED
4、MSG_ID_EVENT_NOTIFY
5、MSG_ID_CALL_SETUP
6、MSG_ID_SIM_READY
7、MSG_ID_ICC_RECORDS_LOADED
而这六个消息事件中,有四个是比较重要的,按照接收的先后顺序分别是:
MSG_ID_SIM_READY ----通知CatService,SIM卡已经就绪,需要CatService反馈是否就绪
MSG_ID_PROACTIVE_COMMAND ----CatService拿到SIM卡中的STK信息
MSG_ID_RIL_MSG_DECODED ----RilMessageDecoder解析完STK数据后给CatService发送通知
MSG_ID_SESSION_END ----RIL上传当前消息已经传输完毕
下面我们主要介绍以上四个消息的处理流程。
2.1、MSG_ID_SIM_READY
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_ID_SIM_READY:
- //向RIL发送消息
- mCmdIf.reportStkServiceIsRunning(null);
- break;
- default:
- throw new AssertionError("Unrecognized CAT command: " + msg.what);
- }
- }
此时的RIL将会向Modem发送RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING的消息,从而告诉Modem,CatService已经准备好接受STK的数据了。
2.2、MSG_ID_PROACTIVE_COMMAND
请注意, 如果SIM卡不支持STK业务,将接收不到该消息。
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_ID_SESSION_END:
- case MSG_ID_PROACTIVE_COMMAND:
- case MSG_ID_EVENT_NOTIFY:
- case MSG_ID_REFRESH:
- String data = null;
- if (msg.obj != null) {
- AsyncResult ar = (AsyncResult) msg.obj;
- if (ar != null && ar.result != null) {
- try {
- data = (String) ar.result;
- } catch (ClassCastException e) {
- break;
- }
- }
- }
- //通过RilMessageDecoder去解析数据
- mMsgDecoder.sendStartDecodingMessageParams(new RilMessage(msg.what, data));
- break;
- default:
- throw new AssertionError("Unrecognized CAT command: " + msg.what);
- }
- }
- @RilMessageDecoder.java
- public void sendStartDecodingMessageParams(RilMessage rilMsg) {
- Message msg = obtainMessage(CMD_START);
- msg.obj = rilMsg;
- sendMessage(msg);
- }
- private class StateStart extends State {
- @Override
- public boolean processMessage(Message msg) {
- if (msg.what == CMD_START) {
- if (decodeMessageParams((RilMessage)msg.obj)) {
- transitionTo(mStateCmdParamsReady);
- }
- } else {
- CatLog.d(this, "StateStart unexpected expecting START=" + CMD_START + " got " + msg.what);
- }
- return true;
- }
- }
- private boolean decodeMessageParams(RilMessage rilMsg) {
- boolean decodingStarted;
- mCurrentRilMessage = rilMsg;
- switch(rilMsg.mId) {
- case CatService.MSG_ID_PROACTIVE_COMMAND:
- case CatService.MSG_ID_EVENT_NOTIFY:
- case CatService.MSG_ID_REFRESH:
- byte[] rawData = null;
- try {
- rawData = IccUtils.hexStringToBytes((String) rilMsg.mData);
- } catch (Exception e) {
- }
- try {
- // Start asynch parsing of the command parameters.
- mCmdParamsFactory.make(BerTlv.decode(rawData));
- decodingStarted = true;
- } catch (ResultException e) {
- }
- break;
- default:
- decodingStarted = false;
- break;
- }
- return decodingStarted;
- }
- @CommandParamsFactory.java
- void make(BerTlv berTlv) {
- mCmdParams = null;
- mIconLoadState = LOAD_NO_ICON;
- boolean cmdPending = false;
- List<ComprehensionTlv> ctlvs = berTlv.getComprehensionTlvs();
- CommandDetails cmdDet = processCommandDetails(ctlvs);
- //得到当前的命令类型
- AppInterface.CommandType cmdType = AppInterface.CommandType .fromInt(cmdDet.typeOfCommand);
- try {
- switch (cmdType) {
- case SET_UP_MENU:
- cmdPending = processSelectItem(cmdDet, ctlvs);
- break;
- case SELECT_ITEM:
- cmdPending = processSelectItem(cmdDet, ctlvs);
- break;
- case DISPLAY_TEXT:
- cmdPending = processDisplayText(cmdDet, ctlvs);
- break;
- case SET_UP_IDLE_MODE_TEXT:
- cmdPending = processSetUpIdleModeText(cmdDet, ctlvs);
- break;
- case GET_INKEY:
- cmdPending = processGetInkey(cmdDet, ctlvs);
- break;
- case GET_INPUT:
- cmdPending = processGetInput(cmdDet, ctlvs);
- break;
- case SEND_DTMF:
- case SEND_SMS:
- case SEND_SS:
- case SEND_USSD:
- cmdPending = processEventNotify(cmdDet, ctlvs);
- break;
- case GET_CHANNEL_STATUS:
- case SET_UP_CALL:
- cmdPending = processSetupCall(cmdDet, ctlvs);
- break;
- case REFRESH:
- processRefresh(cmdDet, ctlvs);
- cmdPending = false;
- break;
- case LAUNCH_BROWSER:
- cmdPending = processLaunchBrowser(cmdDet, ctlvs);
- break;
- case PLAY_TONE:
- cmdPending = processPlayTone(cmdDet, ctlvs);
- break;
- 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);
- sendCmdParams(ResultCode.BEYOND_TERMINAL_CAPABILITY);
- return;
- }
- } catch (ResultException e) {
- }
- if (!cmdPending) {
- sendCmdParams(ResultCode.OK);
- }
- }
1、SET_UP_MENU ---开机完成后初始化STK菜单项,而且是根目录菜单,子菜单项是在发生SELECT_ITEM后解析的
2、SELECT_ITEM ---点击STK菜单项后,传递二级目录的数据
3、DISPLAY_TEXT ---弹出文本提示框,比如开机的运营商问候语
4、GET_INPUT ---弹出编辑框,比如编辑群发短信
5、SEND_SMS ---发送短消息给运行商
我们分别来看以上几个事件的处理流程:
2.2.1、SET_UP_MENU
- private boolean processSelectItem(CommandDetails cmdDet, List<ComprehensionTlv> ctlvs) throws ResultException {
- Menu menu = new Menu();
- IconId titleIconId = null;
- ItemsIconId itemsIconId = null;
- Iterator<ComprehensionTlv> iter = ctlvs.iterator();
- //搜索并解析该STK应用的名字,比如“神州行天地”
- ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID, ctlvs);
- if (ctlv != null) {
- menu.title = ValueParser.retrieveAlphaId(ctlv);
- }
- //循环解析该STK应用的所有根目录菜单
- //比如对于神州行的卡,就会有“轻松问候”、“短信群发”、“优惠快讯”、“业务精选”等菜单
- while (true) {
- ctlv = searchForNextTag(ComprehensionTlvTag.ITEM, iter);
- if (ctlv != null) {
- menu.items.add(ValueParser.retrieveItem(ctlv));
- } else {
- break;
- }
- }
- if (menu.items.size() == 0) {
- throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING);
- }
- //搜索ITEM_ID
- ctlv = searchForTag(ComprehensionTlvTag.ITEM_ID, ctlvs);
- if (ctlv != null) {
- menu.defaultItem = ValueParser.retrieveItemId(ctlv) - 1;
- }
- //搜索ICON_ID
- ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs);
- if (ctlv != null) {
- mIconLoadState = LOAD_SINGLE_ICON;
- titleIconId = ValueParser.retrieveIconId(ctlv);
- menu.titleIconSelfExplanatory = titleIconId.selfExplanatory;
- }
- ctlv = searchForTag(ComprehensionTlvTag.ITEM_ICON_ID_LIST, ctlvs);
- if (ctlv != null) {
- mIconLoadState = LOAD_MULTI_ICONS;
- itemsIconId = ValueParser.retrieveItemsIconId(ctlv);
- menu.itemsIconSelfExplanatory = itemsIconId.selfExplanatory;
- }
- boolean presentTypeSpecified = (cmdDet.commandQualifier & 0x01) != 0;
- if (presentTypeSpecified) {
- if ((cmdDet.commandQualifier & 0x02) == 0) {
- menu.presentationType = PresentationType.DATA_VALUES;
- } else {
- menu.presentationType = PresentationType.NAVIGATION_OPTIONS;
- }
- }
- menu.softKeyPreferred = (cmdDet.commandQualifier & 0x04) != 0;
- menu.helpAvailable = (cmdDet.commandQualifier & 0x80) != 0;
- //用解析的菜单项构建mCmdParams对象
- mCmdParams = new SelectItemParams(cmdDet, menu, titleIconId != null);
- //处理图标的载入
- switch(mIconLoadState) {
- case LOAD_NO_ICON:
- return false;
- case LOAD_SINGLE_ICON:
- mIconLoader.loadIcon(titleIconId.recordNumber, this .obtainMessage(MSG_ID_LOAD_ICON_DONE));
- break;
- case LOAD_MULTI_ICONS:
- int[] recordNumbers = itemsIconId.recordNumbers;
- if (titleIconId != null) {
- // Create a new array for all the icons (title and items).
- recordNumbers = new int[itemsIconId.recordNumbers.length + 1];
- recordNumbers[0] = titleIconId.recordNumber;
- System.arraycopy(itemsIconId.recordNumbers, 0, recordNumbers, 1, itemsIconId.recordNumbers.length);
- }
- mIconLoader.loadIcons(recordNumbers, this .obtainMessage(MSG_ID_LOAD_ICON_DONE));
- break;
- }
- return true;
- }
在上面这个过程中,processSelectItem()会对STK的菜单项的文本、ID、图标等进行解析,最终把解析完的数据放入mCmdParams中,并通过CatService把数据发送给StkAppService并显示相应的菜单项。
2.2.2、SELECT_ITEM
SELECT_ITEM的事件也是通过processSelectItem()来处理的,他的主要作用就是当用户点击某个STK菜单时,对下一级菜单进行解析,并在StkAppService中进行显示。
2.2.3、DISPLAY_TEXT
- private boolean processDisplayText(CommandDetails cmdDet, List<ComprehensionTlv> ctlvs) throws ResultException {
- TextMessage textMsg = new TextMessage();
- IconId iconId = null;
- //得到显示的文本,比如开机后的运营商欢迎语
- ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.TEXT_STRING, ctlvs);
- if (ctlv != null) {
- textMsg.text = ValueParser.retrieveTextString(ctlv);
- }
- if (textMsg.text == null) {
- throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
- }
- ctlv = searchForTag(ComprehensionTlvTag.IMMEDIATE_RESPONSE, ctlvs);
- if (ctlv != null) {
- textMsg.responseNeeded = false;
- }
- //图标
- ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs);
- if (ctlv != null) {
- iconId = ValueParser.retrieveIconId(ctlv);
- textMsg.iconSelfExplanatory = iconId.selfExplanatory;
- }
- //显示的持续时间
- ctlv = searchForTag(ComprehensionTlvTag.DURATION, ctlvs);
- if (ctlv != null) {
- textMsg.duration = ValueParser.retrieveDuration(ctlv);
- }
- textMsg.isHighPriority = (cmdDet.commandQualifier & 0x01) != 0;
- textMsg.userClear = (cmdDet.commandQualifier & 0x80) != 0;
- //构建mCmdParams
- mCmdParams = new DisplayTextParams(cmdDet, textMsg);
- if (iconId != null) {
- mIconLoadState = LOAD_SINGLE_ICON;
- mIconLoader.loadIcon(iconId.recordNumber, this .obtainMessage(MSG_ID_LOAD_ICON_DONE));
- return true;
- }
- return false;
- }
我们看到,在processDisplayText()的过程中,主要还是对要显示数据进行解析,得到显示的文本和图标,最终将解析结果放入mCmdParams中并发送给StkAppService。
2.2.4、GET_INPUT
- private boolean processGetInput(CommandDetails cmdDet, List<ComprehensionTlv> ctlvs) throws ResultException {
- Input input = new Input();
- IconId iconId = null;
- //要显示的提示字串,比如“输入内容”
- ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.TEXT_STRING, ctlvs);
- if (ctlv != null) {
- input.text = ValueParser.retrieveTextString(ctlv);
- } else {
- throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING);
- }
- //得到输入框的输入最大长度
- ctlv = searchForTag(ComprehensionTlvTag.RESPONSE_LENGTH, ctlvs);
- if (ctlv != null) {
- try {
- byte[] rawValue = ctlv.getRawValue();
- int valueIndex = ctlv.getValueIndex();
- input.minLen = rawValue[valueIndex] & 0xff;
- input.maxLen = rawValue[valueIndex + 1] & 0xff;
- } catch (IndexOutOfBoundsException e) {
- throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
- }
- } else {
- throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING);
- }
- ctlv = searchForTag(ComprehensionTlvTag.DEFAULT_TEXT, ctlvs);
- if (ctlv != null) {
- input.defaultText = ValueParser.retrieveTextString(ctlv);
- }
- // parse icon identifier
- ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs);
- if (ctlv != null) {
- iconId = ValueParser.retrieveIconId(ctlv);
- }
- input.digitOnly = (cmdDet.commandQualifier & 0x01) == 0;
- input.ucs2 = (cmdDet.commandQualifier & 0x02) != 0;
- input.echo = (cmdDet.commandQualifier & 0x04) == 0;
- input.packed = (cmdDet.commandQualifier & 0x08) != 0;
- input.helpAvailable = (cmdDet.commandQualifier & 0x80) != 0;
- mCmdParams = new GetInputParams(cmdDet, input);
- if (iconId != null) {
- mIconLoadState = LOAD_SINGLE_ICON;
- mIconLoader.loadIcon(iconId.recordNumber, this .obtainMessage(MSG_ID_LOAD_ICON_DONE));
- return true;
- }
- return false;
- }
和上面两个消息类似,最终会把解析得到的编辑框信息发送给StkAppService来显示。
2.2.5、SEND_SMS
- private boolean processEventNotify(CommandDetails cmdDet, List<ComprehensionTlv> ctlvs) throws ResultException {
- TextMessage textMsg = new TextMessage();
- IconId iconId = null;
- //发送短信时的提示语,比如“正在发送消息…”
- ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID, ctlvs);
- textMsg.text = ValueParser.retrieveAlphaId(ctlv);
- ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs);
- if (ctlv != null) {
- iconId = ValueParser.retrieveIconId(ctlv);
- textMsg.iconSelfExplanatory = iconId.selfExplanatory;
- }
- textMsg.responseNeeded = false;
- mCmdParams = new DisplayTextParams(cmdDet, textMsg);
- if (iconId != null) {
- mIconLoadState = LOAD_SINGLE_ICON;
- mIconLoader.loadIcon(iconId.recordNumber, this .obtainMessage(MSG_ID_LOAD_ICON_DONE));
- return true;
- }
- return false;
- }
和上面的消息类似,最终会把解析得到的信息发送给StkAppService来显示。
2.2.6、CommandParamsFactory作用
- void make(BerTlv berTlv) {
- try {
- switch (cmdType) {
- case SET_UP_MENU:
- case SELECT_ITEM:
- case DISPLAY_TEXT:
- case SET_UP_IDLE_MODE_TEXT:
- case GET_INKEY:
- case GET_INPUT:
- case SEND_DTMF:
- case SEND_SMS:
- case SEND_SS:
- case SEND_USSD:
- case GET_CHANNEL_STATUS:
- case SET_UP_CALL:
- case REFRESH:
- case LAUNCH_BROWSER:
- case PLAY_TONE:
- case PROVIDE_LOCAL_INFORMATION:
- case OPEN_CHANNEL:
- case CLOSE_CHANNEL:
- case RECEIVE_DATA:
- case SEND_DATA:
- default:
- }
- } catch (ResultException e) {
- }
- if (!cmdPending) {
- //将解析的mCmdParams发送给RilMessageDecoder
- sendCmdParams(ResultCode.OK);
- }
- }
- private void sendCmdParams(ResultCode resCode) {
- mCaller.sendMsgParamsDecoded(resCode, mCmdParams);
- }
- @RilMessageDecoder.java
- public void sendMsgParamsDecoded(ResultCode resCode, CommandParams cmdParams) {
- Message msg = obtainMessage(RilMessageDecoder.CMD_PARAMS_READY);
- msg.arg1 = resCode.value();
- msg.obj = cmdParams;
- sendMessage(msg);
- }
接下来就 需要RilMessageDecoder将解析的结果发送给CatService。
当RilMessageDecoder通过sendMsgParamsDecoded()将消息发送出去后,经过其父类StateMachine的处理,再次由RilMessageDecoder接收到消息:
- private class StateCmdParamsReady extends State {
- @Override
- public boolean processMessage(Message msg) {
- if (msg.what == CMD_PARAMS_READY) {
- //接收到消息
- mCurrentRilMessage.mResCode = ResultCode.fromInt(msg.arg1);
- mCurrentRilMessage.mData = msg.obj;
- sendCmdForExecution(mCurrentRilMessage);
- transitionTo(mStateStart);
- } else {
- CatLog.d(this, "StateCmdParamsReady expecting CMD_PARAMS_READY=" + CMD_PARAMS_READY + " got " + msg.what);
- deferMessage(msg);
- }
- return true;
- }
- }
- private void sendCmdForExecution(RilMessage rilMsg) {
- Message msg = mCaller.obtainMessage(CatService.MSG_ID_RIL_MSG_DECODED,
- new RilMessage(rilMsg));
- msg.sendToTarget();
- }
然后在CatService中将会收到MSG_ID_RIL_MSG_DECODED的消息。
2.3、MSG_ID_RIL_MSG_DECODED
下面来看该消息的处理流程:
- @CatService.java
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_ID_RIL_MSG_DECODED:
- handleRilMsg((RilMessage) msg.obj);
- break;
- default:
- throw new AssertionError("Unrecognized CAT command: " + msg.what);
- }
- }
- private void handleRilMsg(RilMessage rilMsg) {
- CommandParams cmdParams = null;
- switch (rilMsg.mId) {
- case MSG_ID_PROACTIVE_COMMAND:
- try {
- //拿到解析后的数据
- cmdParams = (CommandParams) rilMsg.mData;
- } catch (ClassCastException e) {
- }
- if (cmdParams != null) {
- if (rilMsg.mResCode == ResultCode.OK) {
- //处理当前的数据
- handleCommand(cmdParams, true);
- } else {
- sendTerminalResponse(cmdParams.mCmdDet, rilMsg.mResCode, false, 0, null);
- }
- }
- break;
- }
- }
- private void handleCommand(CommandParams cmdParams, boolean isProactiveCmd) {
- CharSequence message;
- CatCmdMessage cmdMsg = new CatCmdMessage(cmdParams);
- switch (cmdParams.getCommandType()) {
- case SET_UP_MENU:
- if (removeMenu(cmdMsg.getMenu())) {
- mMenuCmd = null;
- } else {
- mMenuCmd = cmdMsg;
- }
- sendTerminalResponse(cmdParams.mCmdDet, ResultCode.OK, false, 0, null);
- break;
- case DISPLAY_TEXT:
- if (!cmdMsg.geTextMessage().responseNeeded) {
- sendTerminalResponse(cmdParams.mCmdDet, ResultCode.OK, false, 0, null);
- }
- break;
- case SELECT_ITEM:
- case GET_INPUT:
- case GET_INKEY:
- break;
- case SEND_DTMF:
- case SEND_SMS:
- case SEND_SS:
- case SEND_USSD:
- if ((((DisplayTextParams)cmdParams).mTextMsg.text != null) && (((DisplayTextParams)cmdParams).mTextMsg.text.equals(STK_DEFAULT))) {
- message = mContext.getText(com.android.internal.R.string.sending);
- ((DisplayTextParams)cmdParams).mTextMsg.text = message.toString();
- }
- break;
- case PLAY_TONE:
- break;
- case SET_UP_CALL:
- if ((((CallSetupParams) cmdParams).mConfirmMsg.text != null) && (((CallSetupParams) cmdParams).mConfirmMsg.text.equals(STK_DEFAULT))) {
- message = mContext.getText(com.android.internal.R.string.SetupCallDefault);
- ((CallSetupParams) cmdParams).mConfirmMsg.text = message.toString();
- }
- break;
- default:
- CatLog.d(this, "Unsupported command");
- return;
- }
- mCurrntCmd = cmdMsg;
- Intent intent = new Intent(AppInterface.CAT_CMD_ACTION);
- intent.putExtra("STK CMD", cmdMsg);
- mContext.sendBroadcast(intent);
- }
我们看到,在handleCommand()中,对于主要的几种数据类型,比如SET_UP_MENU、DISPLAY_TEXT的最后都有sendTerminalResponse()的操作,而这个操作的作用就是将数据封装后发送给RIL。并且在handleCommand()的最后,通过广播的形式将当前解析的结果发送出来,发送之后就有STK应用的StkAppService.Java负责接收,并构建STK菜单。
2.4、MSG_ID_SESSION_END
和MSG_ID_PROACTIVE_COMMAND的消息流程类似,只是更加的简单:
- @CatService.java
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_ID_SESSION_END:
- case MSG_ID_PROACTIVE_COMMAND:
- case MSG_ID_EVENT_NOTIFY:
- case MSG_ID_REFRESH:
- CatLog.d(this, "ril message arrived");
- String data = null;
- if (msg.obj != null) {
- AsyncResult ar = (AsyncResult) msg.obj;
- if (ar != null && ar.result != null) {
- try {
- data = (String) ar.result;
- } catch (ClassCastException e) {
- break;
- }
- }
- }
- //让RilMessageDecoder去处理
- mMsgDecoder.sendStartDecodingMessageParams(new RilMessage(msg.what, data));
- break;
- }
- }
- private boolean decodeMessageParams(RilMessage rilMsg) {
- boolean decodingStarted;
- mCurrentRilMessage = rilMsg;
- switch(rilMsg.mId) {
- case CatService.MSG_ID_SESSION_END:
- case CatService.MSG_ID_CALL_SETUP:
- mCurrentRilMessage.mResCode = ResultCode.OK;
- sendCmdForExecution(mCurrentRilMessage);
- decodingStarted = false;
- break;
- default:
- decodingStarted = false;
- break;
- }
- return decodingStarted;
- }
接下来的流程和MSG_ID_PROACTIVE_COMMAND相同,就是将结果发送给RIL和StkAppService.java。
三、CatService的主要作用
现在,我们可以来简要分析CatService的作用了。
从以上的分析中得知, CatService的作用主要体现在接收并解析RIL层发来的STK相关原始数据,并把解析后的数据同时传回给RIL和发送给StkAppService。但是我们发现,CatService虽然对数据进行了解析,但是并没有显示菜单、弹出提示框的动作,而真正将数据转化为控件是在StkAppService中完成的,这是一个上层的app,主要作用就是拿到CatService解析的数据并进行显示,以及处理用户在相应菜单上进行的点击操作。
四、StkAppService
在前面的2.3中我们知道,当CatService完成RIL上报的数据解析后,就会收到MSG_ID_RIL_MSG_DECODED消息,然后CatService就会将解析的结果发送给RIL,同时发送Intent出来:
- Intent intent = new Intent(AppInterface.CAT_CMD_ACTION);
- intent.putExtra("STK CMD", cmdMsg);
- mContext.sendBroadcast(intent);
- @StkCmdReceiver.java
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action.equals(AppInterface.CAT_CMD_ACTION)) {
- handleCommandMessage(context, intent);
- } else if (action.equals(AppInterface.CAT_SESSION_END_ACTION)) {
- handleSessionEnd(context, intent);
- }
- }
- private void handleCommandMessage(Context context, Intent intent) {
- Bundle args = new Bundle();
- args.putInt(StkAppService.OPCODE, StkAppService.OP_CMD);
- args.putParcelable(StkAppService.CMD_MSG, intent .getParcelableExtra("STK CMD"));
- context.startService(new Intent(context, StkAppService.class) .putExtras(args));
- }
在StkAppService的onStart()时,将会从Intent中获取OPCODE中的数据,也就是OP_CMD,然后把从CatService传递下来的CatCmdMessage数据放入message中,发送给mServiceHandler:
- @StkAppService.java
- public void onStart(Intent intent, int startId) {
- mStkService = com.android.internal.telephony.cat.CatService .getInstance();
- if (mStkService == null) {
- }
- Bundle args = intent.getExtras();
- if (args == null) {
- return;
- }
- Message msg = mServiceHandler.obtainMessage();
- msg.arg1 = args.getInt(OPCODE);
- switch(msg.arg1) {
- case OP_CMD:
- msg.obj = args.getParcelable(CMD_MSG);
- break;
- case OP_RESPONSE:
- msg.obj = args;
- case OP_LAUNCH_APP:
- case OP_END_SESSION:
- case OP_BOOT_COMPLETED:
- break;
- default:
- return;
- }
- mServiceHandler.sendMessage(msg);
- }
- private final class ServiceHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- int opcode = msg.arg1;
- switch (opcode) {
- case OP_LAUNCH_APP:
- break;
- case OP_CMD:
- CatCmdMessage cmdMsg = (CatCmdMessage) msg.obj;
- if (!isCmdInteractive(cmdMsg)) {
- handleCmd(cmdMsg);
- } else {
- if (!mCmdInProgress) {
- mCmdInProgress = true;
- handleCmd((CatCmdMessage) msg.obj);
- } else {
- mCmdsQ.addLast(new DelayedCmd(OP_CMD, (CatCmdMessage) msg.obj));
- }
- }
- break;
- case OP_RESPONSE:
- break;
- case OP_END_SESSION:
- break;
- case OP_BOOT_COMPLETED:
- break;
- case OP_DELAYED_MSG:
- break;
- }
- }
- }
- private void handleCmd(CatCmdMessage cmdMsg) {
- if (cmdMsg == null) {
- return;
- }
- switch (cmdMsg.getCmdType()) {
- case DISPLAY_TEXT:
- //弹出提示框
- TextMessage msg = cmdMsg.geTextMessage();
- responseNeeded = msg.responseNeeded;
- waitForUsersResponse = msg.responseNeeded;
- if (lastSelectedItem != null) {
- msg.title = lastSelectedItem;
- } else if (mMainCmd != null){
- msg.title = mMainCmd.getMenu().title;
- } else {
- msg.title = "";
- }
- launchTextDialog();
- break;
- case SELECT_ITEM:
- //载入下一级菜单
- mCurrentMenu = cmdMsg.getMenu();
- launchMenuActivity(cmdMsg.getMenu());
- break;
- case SET_UP_MENU:
- //显示列表
- mMainCmd = mCurrentCmd;
- mCurrentMenu = cmdMsg.getMenu();
- if (removeMenu()) {
- CatLog.d(this, "Uninstall App");
- mCurrentMenu = null;
- StkAppInstaller.unInstall(mContext);
- } else {
- CatLog.d(this, "Install App");
- StkAppInstaller.install(mContext);
- }
- if (mMenuIsVisibile) {
- launchMenuActivity(null);
- }
- break;
- case GET_INPUT:
- case GET_INKEY:
- //显示输入框
- launchInputActivity();
- break;
- case SET_UP_IDLE_MODE_TEXT:
- waitForUsersResponse = false;
- launchIdleText();
- break;
- case SEND_DTMF:
- case SEND_SMS:
- case SEND_SS:
- case SEND_USSD:
- //发送信息的提示
- waitForUsersResponse = false;
- launchEventMessage();
- break;
- case LAUNCH_BROWSER:
- //载入浏览器
- launchConfirmationDialog(mCurrentCmd.geTextMessage());
- break;
- case SET_UP_CALL:
- //呼叫
- launchConfirmationDialog(mCurrentCmd.getCallSettings().confirmMsg);
- break;
- case PLAY_TONE:
- //播放铃声
- launchToneDialog();
- break;
- case OPEN_CHANNEL:
- launchOpenChannelDialog();
- break;
- case CLOSE_CHANNEL:
- case RECEIVE_DATA:
- case SEND_DATA:
- TextMessage m = mCurrentCmd.geTextMessage();
- if ((m != null) && (m.text == null)) {
- switch(cmdMsg.getCmdType()) {
- case CLOSE_CHANNEL:
- m.text = getResources().getString(R.string.default_close_channel_msg);
- break;
- case RECEIVE_DATA:
- m.text = getResources().getString(R.string.default_receive_data_msg);
- break;
- case SEND_DATA:
- m.text = getResources().getString(R.string.default_send_data_msg);
- break;
- }
- }
- launchEventMessage();
- break;
- }
- if (!waitForUsersResponse) {
- if (mCmdsQ.size() != 0) {
- callDelayedMsg();
- } else {
- mCmdInProgress = false;
- }
- }
- }
至此,Uicc相关的知识总结完毕。