diff options
author | Preeti Ahuja <preetia@codeaurora.org> | 2014-02-26 14:09:35 +0530 |
---|---|---|
committer | Linux Build Service Account <lnxbuild@localhost> | 2016-08-24 08:12:24 -0600 |
commit | 4f656cd99673cee1f9a8f280dff9da414baec6ae (patch) | |
tree | 0126568e098d059803bdf1736ad444706d786f5e | |
parent | 74fa06f65f4680fb5ca26cd3f0a9936d19ec4ee4 (diff) | |
download | android_frameworks_opt_telephony-4f656cd99673cee1f9a8f280dff9da414baec6ae.tar.gz android_frameworks_opt_telephony-4f656cd99673cee1f9a8f280dff9da414baec6ae.tar.bz2 android_frameworks_opt_telephony-4f656cd99673cee1f9a8f280dff9da414baec6ae.zip |
Cat: Add support for Activate cmd and HCI connectivity event
Add FLAG_RECEIVER_FOREGROUND to CatService broadcast intents
Stk app is unable to receive broadcasts from CatService until
BOOT_COMPLETED intent is received from framework.
FLAG_RECEIVER_FOREGROUND flag is added to the intents sent
by CatService so that Stk app can receive these broadcasts
before BOOT_COMPLETED is received.
Change-Id: Ica8e72e354891438dcd6b7e899a2ba78d980d396
Cat: Add support for Activate cmd and HCI connectivity event
Add support for Activate proactive command defined in ETSI TS
102 223 [6.4.40] and HCI connectivity event defined in ETSI TS
102 223 [7.5.18].
CRs-Fixed: 618962
Change-Id: I3755cb275a09a346d7b0b799242c818d969f8dff
9 files changed, 312 insertions, 4 deletions
diff --git a/src/java/com/android/internal/telephony/cat/AppInterface.java b/src/java/com/android/internal/telephony/cat/AppInterface.java index d48a82b7c..681f069f8 100644 --- a/src/java/com/android/internal/telephony/cat/AppInterface.java +++ b/src/java/com/android/internal/telephony/cat/AppInterface.java @@ -49,6 +49,18 @@ public interface AppInterface { public static final String STK_PERMISSION = "android.permission.RECEIVE_STK_COMMANDS"; /* + * Intent action broadcasted by StkAppService when the ACTIVATE proactive command + * arrives. + */ + public static final String CAT_ACTIVATE_NOTIFY_ACTION = + "org.codeaurora.intent.action.stk.activate_notify"; + /* + * Intent action broadcasted by NfcService when the HCI Connectivity event occurs. + */ + public static final String CAT_HCI_CONNECTIVITY_ACTION = + "org.codeaurora.intent.action.stk.hci_connectivity"; + + /* * Callback function from app to telephony to pass a result code and user's * input back to the ICC. */ @@ -81,7 +93,8 @@ public interface AppInterface { CLOSE_CHANNEL(0x41), RECEIVE_DATA(0x42), SEND_DATA(0x43), - GET_CHANNEL_STATUS(0x44); + GET_CHANNEL_STATUS(0x44), + ACTIVATE(0x70); private int mValue; diff --git a/src/java/com/android/internal/telephony/cat/CatCmdMessage.java b/src/java/com/android/internal/telephony/cat/CatCmdMessage.java index ac9bb7236..e99473c21 100644 --- a/src/java/com/android/internal/telephony/cat/CatCmdMessage.java +++ b/src/java/com/android/internal/telephony/cat/CatCmdMessage.java @@ -68,6 +68,7 @@ public class CatCmdMessage implements Parcelable { public static final int LANGUAGE_SELECTION_EVENT = 0x07; public static final int BROWSER_TERMINATION_EVENT = 0x08; public static final int BROWSING_STATUS_EVENT = 0x0F; + public static final int HCI_CONNECTIVITY_EVENT = 0x13; } public final class BrowserTerminationCauses { @@ -126,6 +127,7 @@ public class CatCmdMessage implements Parcelable { mSetupEventListSettings = new SetupEventListSettings(); mSetupEventListSettings.eventList = ((SetEventListParams) cmdParams).mEventInfo; break; + case ACTIVATE: case PROVIDE_LOCAL_INFORMATION: default: break; diff --git a/src/java/com/android/internal/telephony/cat/CatService.java b/src/java/com/android/internal/telephony/cat/CatService.java index 696bfce5e..c3728a78d 100644 --- a/src/java/com/android/internal/telephony/cat/CatService.java +++ b/src/java/com/android/internal/telephony/cat/CatService.java @@ -49,6 +49,8 @@ import static com.android.internal.telephony.cat.CatCmdMessage. SetupEventListConstants.IDLE_SCREEN_AVAILABLE_EVENT; import static com.android.internal.telephony.cat.CatCmdMessage. SetupEventListConstants.LANGUAGE_SELECTION_EVENT; +import static com.android.internal.telephony.cat.CatCmdMessage. + SetupEventListConstants.HCI_CONNECTIVITY_EVENT; class RilMessage { int mId; @@ -341,9 +343,13 @@ public class CatService extends Handler implements AppInterface { CatLog.d(this,"Event: " + eventVal); switch (eventVal) { /* Currently android is supporting only the below events in SetupEventList - * Language Selection. */ + * Idle Screen Available, + * Language Selection and + * HCI Connectivity. + */ case IDLE_SCREEN_AVAILABLE_EVENT: case LANGUAGE_SELECTION_EVENT: + case HCI_CONNECTIVITY_EVENT: break; default: flag = false; @@ -499,6 +505,13 @@ public class CatService extends Handler implements AppInterface { sendTerminalResponse(cmdParams.mCmdDet, ResultCode.OK, false, 0, null); } break; + case ACTIVATE: + // TO DO: Retrieve the target of the ACTIVATE cmd from the cmd. + // Target : '01' = UICC-CFL interface according to TS 102 613 [39]; + // '00' and '02' to 'FF' = RFU (Reserved for Future Use). + resultCode = ResultCode.OK; + sendTerminalResponse(cmdParams.mCmdDet, resultCode, false, 0 ,null); + break; default: CatLog.d(this, "Unsupported command"); return; @@ -527,6 +540,7 @@ public class CatService extends Handler implements AppInterface { mCurrntCmd = mMenuCmd; Intent intent = new Intent(AppInterface.CAT_SESSION_END_ACTION); intent.putExtra("SLOT_ID", mSlotId); + intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); mContext.sendBroadcast(intent, AppInterface.STK_PERMISSION); } @@ -726,7 +740,9 @@ public class CatService extends Handler implements AppInterface { /* * Currently the below events are supported: - * Language Selection Event. + * Idle Screen Available, + * Language Selection Event and + * HCI Connectivity. * Other event download commands should be encoded similar way */ /* TODO: eventDownload should be extended for other Envelope Commands */ @@ -741,6 +757,9 @@ public class CatService extends Handler implements AppInterface { // Language length should be 2 byte buf.write(0x02); break; + case HCI_CONNECTIVITY_EVENT: + CatLog.d(this, " Sending HCI Connectivity event download to ICC"); + break; default: break; } @@ -867,6 +886,7 @@ public class CatService extends Handler implements AppInterface { private void broadcastCardStateAndIccRefreshResp(CardState cardState, IccRefreshResponse iccRefreshState) { Intent intent = new Intent(AppInterface.CAT_ICC_STATUS_CHANGE); + intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); boolean cardPresent = (cardState == CardState.CARDSTATE_PRESENT); if (iccRefreshState != null) { diff --git a/src/java/com/android/internal/telephony/cat/CommandDetails.java b/src/java/com/android/internal/telephony/cat/CommandDetails.java index aaa9d6839..64ba7f51f 100644 --- a/src/java/com/android/internal/telephony/cat/CommandDetails.java +++ b/src/java/com/android/internal/telephony/cat/CommandDetails.java @@ -121,3 +121,12 @@ class ItemsIconId extends ValueObject { return ComprehensionTlvTag.ITEM_ICON_ID_LIST; } } + +class ActivateDescriptor extends ValueObject { + public int target; + + @Override + ComprehensionTlvTag getTag() { + return ComprehensionTlvTag.ACTIVATE_DESCRIPTOR; + } +} diff --git a/src/java/com/android/internal/telephony/cat/CommandParams.java b/src/java/com/android/internal/telephony/cat/CommandParams.java index 7dfedab8f..edb377211 100644 --- a/src/java/com/android/internal/telephony/cat/CommandParams.java +++ b/src/java/com/android/internal/telephony/cat/CommandParams.java @@ -224,3 +224,13 @@ class BIPClientParams extends CommandParams { return false; } } +class ActivateParams extends CommandParams { + int mActivateTarget; + + + ActivateParams(CommandDetails cmdDet, int target) { + super(cmdDet); + mActivateTarget = target; + } +} + diff --git a/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java b/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java index f220dd823..d2ba2d6e6 100755 --- a/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java +++ b/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java @@ -35,6 +35,8 @@ import static com.android.internal.telephony.cat.CatCmdMessage. SetupEventListConstants.BROWSER_TERMINATION_EVENT; import static com.android.internal.telephony.cat.CatCmdMessage. SetupEventListConstants.BROWSING_STATUS_EVENT; +import static com.android.internal.telephony.cat.CatCmdMessage. + SetupEventListConstants.HCI_CONNECTIVITY_EVENT; /** * Factory class, used for decoding raw byte arrays, received from baseband, * into a CommandParams object. @@ -202,6 +204,9 @@ class CommandParamsFactory extends Handler { case SEND_DATA: cmdPending = processBIPClient(cmdDet, ctlvs); break; + case ACTIVATE: + cmdPending = processActivate(cmdDet, ctlvs); + break; default: // unsupported proactive commands mCmdParams = new CommandParams(cmdDet); @@ -730,6 +735,7 @@ class CommandParamsFactory extends Handler { case LANGUAGE_SELECTION_EVENT: case BROWSER_TERMINATION_EVENT: case BROWSING_STATUS_EVENT: + case HCI_CONNECTIVITY_EVENT: eventList[i] = eventValue; i++; break; @@ -1010,6 +1016,27 @@ class CommandParamsFactory extends Handler { return false; } + private boolean processActivate(CommandDetails cmdDet, + List<ComprehensionTlv> ctlvs) throws ResultException { + AppInterface.CommandType commandType = + AppInterface.CommandType.fromInt(cmdDet.typeOfCommand); + CatLog.d(this, "process " + commandType.name()); + + ComprehensionTlv ctlv = null; + int target; + + //parse activate descriptor + ctlv = searchForTag(ComprehensionTlvTag.ACTIVATE_DESCRIPTOR, ctlvs); + if (ctlv != null) { + target = ValueParser.retrieveTarget(ctlv); + mCmdParams = new CommandParams(cmdDet); + CatLog.d(this, "Activate cmd target = " + target); + } else { + CatLog.d(this, "ctlv is null"); + } + return false; + } + public void dispose() { mIconLoader.dispose(); mIconLoader = null; diff --git a/src/java/com/android/internal/telephony/cat/ComprehensionTlvTag.java b/src/java/com/android/internal/telephony/cat/ComprehensionTlvTag.java index 973dbc813..9e31c27c7 100644 --- a/src/java/com/android/internal/telephony/cat/ComprehensionTlvTag.java +++ b/src/java/com/android/internal/telephony/cat/ComprehensionTlvTag.java @@ -46,7 +46,8 @@ public enum ComprehensionTlvTag { LANGUAGE(0x2d), URL(0x31), BROWSER_TERMINATION_CAUSE(0x34), - TEXT_ATTRIBUTE(0x50); + TEXT_ATTRIBUTE(0x50), + ACTIVATE_DESCRIPTOR(0x7b); private int mValue; diff --git a/src/java/com/android/internal/telephony/cat/ValueParser.java b/src/java/com/android/internal/telephony/cat/ValueParser.java index 91a6fd6fe..c6b16c783 100644 --- a/src/java/com/android/internal/telephony/cat/ValueParser.java +++ b/src/java/com/android/internal/telephony/cat/ValueParser.java @@ -354,4 +354,16 @@ abstract class ValueParser { throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); } } + + static int retrieveTarget(ComprehensionTlv ctlv) throws ResultException { + ActivateDescriptor activateDesc = new ActivateDescriptor(); + byte[] rawValue = ctlv.getRawValue(); + int valueIndex = ctlv.getValueIndex(); + try { + activateDesc.target = rawValue[valueIndex] & 0xff; + return activateDesc.target; + } catch (IndexOutOfBoundsException e) { + throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); + } + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/cat/CatServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/cat/CatServiceTest.java new file mode 100644 index 000000000..b378e6e3c --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/cat/CatServiceTest.java @@ -0,0 +1,214 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +package com.android.internal.telephony; + +import android.content.Context; +import android.content.Intent; +import android.os.HandlerThread; +import android.telephony.TelephonyManager; +import android.test.suitebuilder.annotation.SmallTest; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import com.android.internal.telephony.cat.*; +import com.android.internal.telephony.TelephonyTestUtils; +import com.android.internal.telephony.uicc.IccFileHandler; +import com.android.internal.telephony.uicc.UiccCard; + +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import static org.junit.Assert.*; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +import java.lang.reflect.Method; +import junit.framework.Assert; + +public class CatServiceTest extends TelephonyTest { + + private static final int SINGLE_SIM = 1; + + private TelephonyManager mTelephonyManager; + private CatService mCatService; + + @Mock + private UiccCard mMockUiccCard; + + @Mock + private IccFileHandler mIccFileHandler; + + + /* CatService extends handler and to instantiate the object within this test, + * we will need a looper to be ready. The HandlerThread here is used for this. The .start() + * is invoked in the setUp() call and the CatService is initialized in the + * onLooperPrepared() callback. + * + * This will not be required if the class under test is not extending Handler + */ + private class CatServiceTestHandler extends HandlerThread { + + private CatServiceTestHandler(String name) { + super(name); + } + + @Override + public void onLooperPrepared() { + mCatService = CatService.getInstance( + mSimulatedCommands, mContext, mMockUiccCard, 0); + setReady(true); + } + } + + @Before + public void setUp() throws Exception { + super.setUp(this.getClass().getSimpleName()); + + mTelephonyManager = (TelephonyManager) mContext.getSystemService( + Context.TELEPHONY_SERVICE); + + /* These are preconditions for the tests, all the APIs that the Class Under Test + * will invoke, has to be setup here using dummy values + */ + doReturn(SINGLE_SIM).when(mTelephonyManager).getSimCount(); + doReturn(SINGLE_SIM).when(mTelephonyManager).getPhoneCount(); + + /* Some of the objects are already provided by the base class and a subset of it + * which is required for the CatService test will be used as dummy responses + * when the Class Under Test will invoke it in its constructor or in the methods + * under test + */ + doReturn(mUiccCardApplication3gpp).when(mMockUiccCard).getApplicationIndex(0); + doReturn(mIccFileHandler).when(mUiccCardApplication3gpp).getIccFileHandler(); + doReturn(mSimRecords).when(mUiccCardApplication3gpp).getIccRecords(); + + /* Kick off the handler thread, which leads to instantiation of the CatService object */ + new CatServiceTestHandler(TAG).start(); + waitUntilReady(); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + mTelephonyManager = null; + mCatService.dispose(); + } + + @Test @SmallTest + public void isSupportedSetupEventCommand() { + assertNotNull(mCatService); + + /* Create a mock object to be sent to method under test */ + CatCmdMessage mockCatMsg = mock(CatCmdMessage.class); + + /* Create a real object that will returned when getSetEventList() is invoked + * on the mock object + */ + CatCmdMessage.SetupEventListSettings eventListSettings = + mockCatMsg.new SetupEventListSettings(); + + /* Define the mock behavior for getSetEventList(), to return the real object created */ + Mockito.when(mockCatMsg.getSetEventList()).thenReturn(eventListSettings); + + eventListSettings.eventList = + new int[]{CatCmdMessage.SetupEventListConstants.LANGUAGE_SELECTION_EVENT}; + assertEquals(true, callIsSupportedSetupEventCommand(mockCatMsg)); + + eventListSettings.eventList = + new int[]{CatCmdMessage.SetupEventListConstants.HCI_CONNECTIVITY_EVENT}; + assertEquals(true, callIsSupportedSetupEventCommand(mockCatMsg)); + } + + /* Wrapper function that uses reflection to invoke private methods */ + private boolean callIsSupportedSetupEventCommand(CatCmdMessage mockCatMsg) { + Class clsParams[] = new Class[1]; + clsParams[0] = CatCmdMessage.class; + + Object params[] = new Object[1]; + params[0] = mockCatMsg; + + return (boolean)invokeNonStaticMethod(CatService.class, mCatService, + "isSupportedSetupEventCommand", clsParams, params); + } + + /* In this test the method under test creates an intent, + * sets a flag and broadcasts it, this test ensures the flag is set + */ + @Test + public void broadcastCatCmdIntent() { + CatCmdMessage mockCatMsg = mock(CatCmdMessage.class); + + Class clsParams[] = new Class[1]; + clsParams[0] = CatCmdMessage.class; + + Object params[] = new Object[1]; + params[0] = mockCatMsg; + + /* broadcastCatCmdIntent method will get tested and 'sendBroadcast' would get invoked */ + invokeNonStaticMethod(CatService.class, mCatService, + "broadcastCatCmdIntent", clsParams, params); + + /* Since mock Context is used, sendBroadcast method is trapped + * and arguments can be examined. In the example below, first argument is an + * intent and is captured and examined for the flag. Parameters of no interest can + * be left as anyInt() or anyString() based on the method signature + */ + ArgumentCaptor<Intent> intentCapture = ArgumentCaptor.forClass(Intent.class); + Mockito.verify(mContext).sendBroadcast(intentCapture.capture(), Mockito.anyString()); + + assertEquals( + ((Intent)intentCapture.getValue()).getFlags() & Intent.FLAG_RECEIVER_FOREGROUND, + Intent.FLAG_RECEIVER_FOREGROUND); + } + + @Test + public void handleSessionEnd() { + invokeNonStaticMethod(CatService.class, mCatService, "handleSessionEnd", null, null); + + ArgumentCaptor<Intent> intentCapture = ArgumentCaptor.forClass(Intent.class); + Mockito.verify(mContext).sendBroadcast(intentCapture.capture(), Mockito.anyString()); + + assertEquals( + ((Intent)intentCapture.getValue()).getFlags() & Intent.FLAG_RECEIVER_FOREGROUND, + Intent.FLAG_RECEIVER_FOREGROUND); + } + + private Object invokeNonStaticMethod(Class clazz, Object caller, String method, + Class[] clsParams, Object[] params) { + try { + Method methodReflection = clazz.getDeclaredMethod(method, clsParams); + methodReflection.setAccessible(true); + return methodReflection.invoke(caller, params); + } catch (Exception e) { + Assert.fail(e.toString()); + return null; + } + } +} |