blob: edd43060587b703c5ae8fba2629072136ec95ab8 [file] [log] [blame]
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.stk;
18
Preeti Ahuja95919342013-10-01 18:18:55 -070019import android.app.ActivityManager;
20import android.app.ActivityManager.RunningTaskInfo;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050021import android.app.AlertDialog;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080022import android.app.Notification;
23import android.app.NotificationManager;
24import android.app.PendingIntent;
25import android.app.Service;
Wink Savillee68857d2014-10-17 15:23:05 -070026import android.app.Activity;
27import android.app.ActivityManager;
28import android.app.ActivityManager.RecentTaskInfo;
29import android.app.ActivityManager.RunningAppProcessInfo;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070030import android.content.ComponentName;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080031import android.content.Context;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050032import android.content.DialogInterface;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080033import android.content.Intent;
Preeti Ahuja95919342013-10-01 18:18:55 -070034import android.content.res.Configuration;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053035import android.content.res.Resources;
36import android.content.res.Resources.NotFoundException;
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +010037import android.graphics.Bitmap;
38import android.graphics.BitmapFactory;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080039import android.net.Uri;
40import android.os.Bundle;
41import android.os.Handler;
42import android.os.IBinder;
43import android.os.Looper;
44import android.os.Message;
Sooraj Sasindrana4160472016-10-12 16:28:25 -070045import android.os.PersistableBundle;
Preeti Ahuja560be362014-11-25 19:38:24 -080046import android.os.PowerManager;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070047import android.os.SystemProperties;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053048import android.os.Vibrator;
Preeti Ahuja95919342013-10-01 18:18:55 -070049import android.provider.Settings;
Sooraj Sasindrana4160472016-10-12 16:28:25 -070050import android.telephony.CarrierConfigManager;
Wink Saville56469d52009-04-02 01:37:03 -070051import android.telephony.TelephonyManager;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070052import android.text.TextUtils;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080053import android.view.Gravity;
54import android.view.LayoutInflater;
55import android.view.View;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050056import android.view.Window;
57import android.view.WindowManager;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080058import android.widget.ImageView;
59import android.widget.RemoteViews;
60import android.widget.TextView;
61import android.widget.Toast;
Wink Savillee68857d2014-10-17 15:23:05 -070062import android.content.BroadcastReceiver;
63import android.content.IntentFilter;
64import android.content.pm.ApplicationInfo;
65import android.content.pm.PackageManager.NameNotFoundException;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080066
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070067import com.android.internal.telephony.cat.AppInterface;
Preeti Ahuja95919342013-10-01 18:18:55 -070068import com.android.internal.telephony.cat.LaunchBrowserMode;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070069import com.android.internal.telephony.cat.Menu;
70import com.android.internal.telephony.cat.Item;
Pierre Fröjd97503262010-11-08 13:59:36 +010071import com.android.internal.telephony.cat.Input;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070072import com.android.internal.telephony.cat.ResultCode;
73import com.android.internal.telephony.cat.CatCmdMessage;
74import com.android.internal.telephony.cat.CatCmdMessage.BrowserSettings;
Preeti Ahuja95919342013-10-01 18:18:55 -070075import com.android.internal.telephony.cat.CatCmdMessage.SetupEventListSettings;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070076import com.android.internal.telephony.cat.CatLog;
77import com.android.internal.telephony.cat.CatResponseMessage;
78import com.android.internal.telephony.cat.TextMessage;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053079import com.android.internal.telephony.cat.ToneSettings;
Wink Saville94e982b2014-07-11 07:38:14 -070080import com.android.internal.telephony.uicc.IccRefreshResponse;
81import com.android.internal.telephony.uicc.IccCardStatus.CardState;
Wink Savillee68857d2014-10-17 15:23:05 -070082import com.android.internal.telephony.PhoneConstants;
83import com.android.internal.telephony.TelephonyIntents;
84import com.android.internal.telephony.IccCardConstants;
85import com.android.internal.telephony.uicc.UiccController;
Preeti Ahuja95919342013-10-01 18:18:55 -070086import com.android.internal.telephony.GsmAlphabet;
Legler Wuaeefef52014-10-27 00:57:18 +080087import com.android.internal.telephony.cat.CatService;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080088
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070089import java.util.Iterator;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080090import java.util.LinkedList;
Wink Savillee68857d2014-10-17 15:23:05 -070091import java.lang.System;
92import java.util.List;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080093
Preeti Ahuja95919342013-10-01 18:18:55 -070094import static com.android.internal.telephony.cat.CatCmdMessage.
Preeti Ahuja560be362014-11-25 19:38:24 -080095 SetupEventListConstants.IDLE_SCREEN_AVAILABLE_EVENT;
96import static com.android.internal.telephony.cat.CatCmdMessage.
Preeti Ahuja95919342013-10-01 18:18:55 -070097 SetupEventListConstants.LANGUAGE_SELECTION_EVENT;
98
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080099/**
100 * SIM toolkit application level service. Interacts with Telephopny messages,
101 * application's launch and user input from STK UI elements.
Wink Saville79085fc2009-06-09 10:27:23 -0700102 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800103 */
104public class StkAppService extends Service implements Runnable {
105
106 // members
Wink Savillee68857d2014-10-17 15:23:05 -0700107 protected class StkContext {
108 protected CatCmdMessage mMainCmd = null;
109 protected CatCmdMessage mCurrentCmd = null;
110 protected CatCmdMessage mCurrentMenuCmd = null;
111 protected Menu mCurrentMenu = null;
112 protected String lastSelectedItem = null;
113 protected boolean mMenuIsVisible = false;
114 protected boolean mIsInputPending = false;
115 protected boolean mIsMenuPending = false;
116 protected boolean mIsDialogPending = false;
117 protected boolean responseNeeded = true;
118 protected boolean launchBrowser = false;
119 protected BrowserSettings mBrowserSettings = null;
120 protected LinkedList<DelayedCmd> mCmdsQ = null;
121 protected boolean mCmdInProgress = false;
122 protected int mStkServiceState = STATE_UNKNOWN;
123 protected int mSetupMenuState = STATE_UNKNOWN;
124 protected int mMenuState = StkMenuActivity.STATE_INIT;
125 protected int mOpCode = -1;
126 private Activity mActivityInstance = null;
127 private Activity mDialogInstance = null;
128 private Activity mMainActivityInstance = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700129 private int mSlotId = 0;
Preeti Ahuja95919342013-10-01 18:18:55 -0700130 private SetupEventListSettings mSetupEventListSettings = null;
131 private boolean mClearSelectItem = false;
132 private boolean mDisplayTextDlgIsVisibile = false;
133 private CatCmdMessage mCurrentSetupEventCmd = null;
Preeti Ahuja560be362014-11-25 19:38:24 -0800134 private CatCmdMessage mIdleModeTextCmd = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700135 final synchronized void setPendingActivityInstance(Activity act) {
136 CatLog.d(this, "setPendingActivityInstance act : " + mSlotId + ", " + act);
137 callSetActivityInstMsg(OP_SET_ACT_INST, mSlotId, act);
138 }
139 final synchronized Activity getPendingActivityInstance() {
140 CatLog.d(this, "getPendingActivityInstance act : " + mSlotId + ", " +
141 mActivityInstance);
142 return mActivityInstance;
143 }
144 final synchronized void setPendingDialogInstance(Activity act) {
145 CatLog.d(this, "setPendingDialogInstance act : " + mSlotId + ", " + act);
146 callSetActivityInstMsg(OP_SET_DAL_INST, mSlotId, act);
147 }
148 final synchronized Activity getPendingDialogInstance() {
149 CatLog.d(this, "getPendingDialogInstance act : " + mSlotId + ", " +
150 mDialogInstance);
151 return mDialogInstance;
152 }
153 final synchronized void setMainActivityInstance(Activity act) {
154 CatLog.d(this, "setMainActivityInstance act : " + mSlotId + ", " + act);
155 callSetActivityInstMsg(OP_SET_MAINACT_INST, mSlotId, act);
156 }
157 final synchronized Activity getMainActivityInstance() {
158 CatLog.d(this, "getMainActivityInstance act : " + mSlotId + ", " +
159 mMainActivityInstance);
160 return mMainActivityInstance;
161 }
162 }
163
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800164 private volatile Looper mServiceLooper;
165 private volatile ServiceHandler mServiceHandler;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800166 private Context mContext = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800167 private NotificationManager mNotificationManager = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800168 static StkAppService sInstance = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700169 private AppInterface[] mStkService = null;
170 private StkContext[] mStkContext = null;
171 private int mSimCount = 0;
Preeti Ahuja560be362014-11-25 19:38:24 -0800172 private PowerManager mPowerManager = null;
173 private StkCmdReceiver mStkCmdReceiver = null;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530174 private TonePlayer mTonePlayer = null;
175 private Vibrator mVibrator = null;
Preeti Ahuja95919342013-10-01 18:18:55 -0700176
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800177 // Used for setting FLAG_ACTIVITY_NO_USER_ACTION when
178 // creating an intent.
179 private enum InitiatedByUserAction {
180 yes, // The action was started via a user initiated action
181 unknown, // Not known for sure if user initated the action
182 }
183
184 // constants
185 static final String OPCODE = "op";
186 static final String CMD_MSG = "cmd message";
187 static final String RES_ID = "response id";
188 static final String MENU_SELECTION = "menu selection";
189 static final String INPUT = "input";
190 static final String HELP = "help";
191 static final String CONFIRMATION = "confirm";
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500192 static final String CHOICE = "choice";
Wink Savillee68857d2014-10-17 15:23:05 -0700193 static final String SLOT_ID = "SLOT_ID";
194 static final String STK_CMD = "STK CMD";
195 static final String STK_DIALOG_URI = "stk://com.android.stk/dialog/";
196 static final String STK_MENU_URI = "stk://com.android.stk/menu/";
197 static final String STK_INPUT_URI = "stk://com.android.stk/input/";
198 static final String STK_TONE_URI = "stk://com.android.stk/tone/";
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530199 static final String FINISH_TONE_ACTIVITY_ACTION =
200 "android.intent.action.stk.finish_activity";
Preeti Ahuja95919342013-10-01 18:18:55 -0700201
202 // These below constants are used for SETUP_EVENT_LIST
203 static final String SETUP_EVENT_TYPE = "event";
204 static final String SETUP_EVENT_CAUSE = "cause";
205
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800206 // operations ids for different service functionality.
207 static final int OP_CMD = 1;
208 static final int OP_RESPONSE = 2;
209 static final int OP_LAUNCH_APP = 3;
210 static final int OP_END_SESSION = 4;
211 static final int OP_BOOT_COMPLETED = 5;
212 private static final int OP_DELAYED_MSG = 6;
Wink Saville94e982b2014-07-11 07:38:14 -0700213 static final int OP_CARD_STATUS_CHANGED = 7;
Wink Savillee68857d2014-10-17 15:23:05 -0700214 static final int OP_SET_ACT_INST = 8;
215 static final int OP_SET_DAL_INST = 9;
216 static final int OP_SET_MAINACT_INST = 10;
Preeti Ahujab3d0e612014-11-20 13:29:25 -0800217 static final int OP_LOCALE_CHANGED = 11;
218 static final int OP_ALPHA_NOTIFY = 12;
Preeti Ahuja560be362014-11-25 19:38:24 -0800219 static final int OP_IDLE_SCREEN = 13;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800220
Preeti Ahuja95919342013-10-01 18:18:55 -0700221 //Invalid SetupEvent
222 static final int INVALID_SETUP_EVENT = 0xFF;
223
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530224 // Message id to signal stop tone due to play tone timeout.
225 private static final int OP_STOP_TONE = 16;
226
227 // Message id to signal stop tone on user keyback.
228 static final int OP_STOP_TONE_USER = 17;
229
230 // Message id to remove stop tone message from queue.
231 private static final int STOP_TONE_WHAT = 100;
232
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800233 // Response ids
234 static final int RES_ID_MENU_SELECTION = 11;
235 static final int RES_ID_INPUT = 12;
236 static final int RES_ID_CONFIRM = 13;
237 static final int RES_ID_DONE = 14;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500238 static final int RES_ID_CHOICE = 15;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800239
240 static final int RES_ID_TIMEOUT = 20;
241 static final int RES_ID_BACKWARD = 21;
242 static final int RES_ID_END_SESSION = 22;
243 static final int RES_ID_EXIT = 23;
244
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500245 static final int YES = 1;
246 static final int NO = 0;
247
Wink Savillee68857d2014-10-17 15:23:05 -0700248 static final int STATE_UNKNOWN = -1;
249 static final int STATE_NOT_EXIST = 0;
250 static final int STATE_EXIST = 1;
Wink Saville79085fc2009-06-09 10:27:23 -0700251
Wink Savillee68857d2014-10-17 15:23:05 -0700252 private static final String PACKAGE_NAME = "com.android.stk";
253 private static final String STK_MENU_ACTIVITY_NAME = PACKAGE_NAME + ".StkMenuActivity";
254 private static final String STK_INPUT_ACTIVITY_NAME = PACKAGE_NAME + ".StkInputActivity";
255 private static final String STK_DIALOG_ACTIVITY_NAME = PACKAGE_NAME + ".StkDialogActivity";
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800256 // Notification id used to display Idle Mode text in NotificationManager.
257 private static final int STK_NOTIFICATION_ID = 333;
Wink Savillee68857d2014-10-17 15:23:05 -0700258 private static final String LOG_TAG = new Object(){}.getClass().getEnclosingClass().getName();
Wink Saville79085fc2009-06-09 10:27:23 -0700259
260 // Inner class used for queuing telephony messages (proactive commands,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800261 // session end) while the service is busy processing a previous message.
262 private class DelayedCmd {
263 // members
264 int id;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700265 CatCmdMessage msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700266 int slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800267
Wink Savillee68857d2014-10-17 15:23:05 -0700268 DelayedCmd(int id, CatCmdMessage msg, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800269 this.id = id;
270 this.msg = msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700271 this.slotId = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800272 }
273 }
274
Preeti Ahujaa7cdca22013-10-01 18:20:56 -0700275 // system property to set the STK specific default url for launch browser proactive cmds
276 private static final String STK_BROWSER_DEFAULT_URL_SYSPROP = "persist.radio.stk.default_url";
277
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800278 @Override
279 public void onCreate() {
Wink Savillee68857d2014-10-17 15:23:05 -0700280 CatLog.d(LOG_TAG, "onCreate()+");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800281 // Initialize members
Wink Savillee68857d2014-10-17 15:23:05 -0700282 int i = 0;
283 mContext = getBaseContext();
284 mSimCount = TelephonyManager.from(mContext).getSimCount();
285 CatLog.d(LOG_TAG, "simCount: " + mSimCount);
286 mStkService = new AppInterface[mSimCount];
287 mStkContext = new StkContext[mSimCount];
Preeti Ahuja560be362014-11-25 19:38:24 -0800288 mPowerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
289 mStkCmdReceiver = new StkCmdReceiver();
290 registerReceiver(mStkCmdReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
Wink Savillee68857d2014-10-17 15:23:05 -0700291 for (i = 0; i < mSimCount; i++) {
292 CatLog.d(LOG_TAG, "slotId: " + i);
Legler Wuaeefef52014-10-27 00:57:18 +0800293 mStkService[i] = CatService.getInstance(i);
Wink Savillee68857d2014-10-17 15:23:05 -0700294 mStkContext[i] = new StkContext();
295 mStkContext[i].mSlotId = i;
296 mStkContext[i].mCmdsQ = new LinkedList<DelayedCmd>();
297 }
298
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800299 Thread serviceThread = new Thread(null, this, "Stk App Service");
300 serviceThread.start();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800301 mNotificationManager = (NotificationManager) mContext
302 .getSystemService(Context.NOTIFICATION_SERVICE);
303 sInstance = this;
304 }
305
306 @Override
307 public void onStart(Intent intent, int startId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700308 if (intent == null) {
309 CatLog.d(LOG_TAG, "StkAppService onStart intent is null so return");
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530310 return;
311 }
312
Wink Savillee68857d2014-10-17 15:23:05 -0700313 Bundle args = intent.getExtras();
314 if (args == null) {
315 CatLog.d(LOG_TAG, "StkAppService onStart args is null so return");
316 return;
317 }
318
319 int op = args.getInt(OPCODE);
320 int slotId = 0;
321 int i = 0;
322 if (op != OP_BOOT_COMPLETED) {
323 slotId = args.getInt(SLOT_ID);
324 }
Cuihtlauac ALVARADObde7f032015-05-29 16:25:12 +0200325 CatLog.d(LOG_TAG, "onStart sim id: " + slotId + ", op: " + op + ", *****");
Wink Savillee68857d2014-10-17 15:23:05 -0700326 if ((slotId >= 0 && slotId < mSimCount) && mStkService[slotId] == null) {
Legler Wuaeefef52014-10-27 00:57:18 +0800327 mStkService[slotId] = CatService.getInstance(slotId);
Wink Savillee68857d2014-10-17 15:23:05 -0700328 if (mStkService[slotId] == null) {
329 CatLog.d(LOG_TAG, "mStkService is: " + mStkContext[slotId].mStkServiceState);
330 mStkContext[slotId].mStkServiceState = STATE_NOT_EXIST;
331 //Check other StkService state.
332 //If all StkServices are not available, stop itself and uninstall apk.
333 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
334 if (i != slotId
Tsukasa Goto029332b2016-10-05 17:12:06 +0900335 && (mStkService[i] != null)
Wink Savillee68857d2014-10-17 15:23:05 -0700336 && (mStkContext[i].mStkServiceState == STATE_UNKNOWN
337 || mStkContext[i].mStkServiceState == STATE_EXIST)) {
338 break;
339 }
340 }
341 } else {
342 mStkContext[slotId].mStkServiceState = STATE_EXIST;
343 }
344 if (i == mSimCount) {
345 stopSelf();
346 StkAppInstaller.unInstall(mContext);
347 return;
348 }
349 }
350
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530351 waitForLooper();
John Wang62acae42009-10-08 11:20:23 -0700352
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800353 Message msg = mServiceHandler.obtainMessage();
Wink Savillee68857d2014-10-17 15:23:05 -0700354 msg.arg1 = op;
355 msg.arg2 = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800356 switch(msg.arg1) {
357 case OP_CMD:
358 msg.obj = args.getParcelable(CMD_MSG);
359 break;
360 case OP_RESPONSE:
Wink Saville94e982b2014-07-11 07:38:14 -0700361 case OP_CARD_STATUS_CHANGED:
Preeti Ahuja95919342013-10-01 18:18:55 -0700362 case OP_LOCALE_CHANGED:
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530363 case OP_ALPHA_NOTIFY:
Preeti Ahuja560be362014-11-25 19:38:24 -0800364 case OP_IDLE_SCREEN:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800365 msg.obj = args;
366 /* falls through */
367 case OP_LAUNCH_APP:
368 case OP_END_SESSION:
369 case OP_BOOT_COMPLETED:
370 break;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530371 case OP_STOP_TONE_USER:
372 msg.obj = args;
373 msg.what = STOP_TONE_WHAT;
374 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800375 default:
376 return;
377 }
378 mServiceHandler.sendMessage(msg);
379 }
380
381 @Override
382 public void onDestroy() {
Wink Savillee68857d2014-10-17 15:23:05 -0700383 CatLog.d(LOG_TAG, "onDestroy()");
Preeti Ahuja560be362014-11-25 19:38:24 -0800384 if (mStkCmdReceiver != null) {
385 unregisterReceiver(mStkCmdReceiver);
386 mStkCmdReceiver = null;
387 }
388 mPowerManager = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800389 waitForLooper();
390 mServiceLooper.quit();
391 }
392
393 @Override
394 public IBinder onBind(Intent intent) {
395 return null;
396 }
397
398 public void run() {
399 Looper.prepare();
400
401 mServiceLooper = Looper.myLooper();
402 mServiceHandler = new ServiceHandler();
403
404 Looper.loop();
405 }
406
407 /*
408 * Package api used by StkMenuActivity to indicate if its on the foreground.
409 */
Wink Savillee68857d2014-10-17 15:23:05 -0700410 void indicateMenuVisibility(boolean visibility, int slotId) {
411 if (slotId >= 0 && slotId < mSimCount) {
412 mStkContext[slotId].mMenuIsVisible = visibility;
413 }
414 }
415
Preeti Ahuja95919342013-10-01 18:18:55 -0700416 /*
417 * Package api used by StkDialogActivity to indicate if its on the foreground.
418 */
419 void setDisplayTextDlgVisibility(boolean visibility, int slotId) {
420 if (slotId >= 0 && slotId < mSimCount) {
421 mStkContext[slotId].mDisplayTextDlgIsVisibile = visibility;
422 }
423 }
424
Wink Savillee68857d2014-10-17 15:23:05 -0700425 boolean isInputPending(int slotId) {
426 if (slotId >= 0 && slotId < mSimCount) {
427 CatLog.d(LOG_TAG, "isInputFinishBySrv: " + mStkContext[slotId].mIsInputPending);
428 return mStkContext[slotId].mIsInputPending;
429 }
430 return false;
431 }
432
433 boolean isMenuPending(int slotId) {
434 if (slotId >= 0 && slotId < mSimCount) {
435 CatLog.d(LOG_TAG, "isMenuPending: " + mStkContext[slotId].mIsMenuPending);
436 return mStkContext[slotId].mIsMenuPending;
437 }
438 return false;
439 }
440
441 boolean isDialogPending(int slotId) {
442 if (slotId >= 0 && slotId < mSimCount) {
443 CatLog.d(LOG_TAG, "isDialogPending: " + mStkContext[slotId].mIsDialogPending);
444 return mStkContext[slotId].mIsDialogPending;
445 }
446 return false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800447 }
448
449 /*
450 * Package api used by StkMenuActivity to get its Menu parameter.
451 */
Wink Savillee68857d2014-10-17 15:23:05 -0700452 Menu getMenu(int slotId) {
453 CatLog.d(LOG_TAG, "StkAppService, getMenu, sim id: " + slotId);
454 if (slotId >=0 && slotId < mSimCount) {
455 return mStkContext[slotId].mCurrentMenu;
456 } else {
457 return null;
458 }
459 }
460
461 /*
462 * Package api used by StkMenuActivity to get its Main Menu parameter.
463 */
464 Menu getMainMenu(int slotId) {
465 CatLog.d(LOG_TAG, "StkAppService, getMainMenu, sim id: " + slotId);
w30234a08cffe2015-02-04 15:13:25 -0800466 if (slotId >=0 && slotId < mSimCount && (mStkContext[slotId].mMainCmd != null)) {
Wink Savillee68857d2014-10-17 15:23:05 -0700467 return mStkContext[slotId].mMainCmd.getMenu();
468 } else {
469 return null;
470 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800471 }
472
473 /*
474 * Package api used by UI Activities and Dialogs to communicate directly
475 * with the service to deliver state information and parameters.
476 */
477 static StkAppService getInstance() {
478 return sInstance;
479 }
480
481 private void waitForLooper() {
482 while (mServiceHandler == null) {
483 synchronized (this) {
484 try {
485 wait(100);
486 } catch (InterruptedException e) {
487 }
488 }
489 }
490 }
491
492 private final class ServiceHandler extends Handler {
493 @Override
494 public void handleMessage(Message msg) {
Wink Savillee68857d2014-10-17 15:23:05 -0700495 if(null == msg) {
496 CatLog.d(LOG_TAG, "ServiceHandler handleMessage msg is null");
497 return;
498 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800499 int opcode = msg.arg1;
Wink Savillee68857d2014-10-17 15:23:05 -0700500 int slotId = msg.arg2;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800501
Wink Savillee68857d2014-10-17 15:23:05 -0700502 CatLog.d(LOG_TAG, "handleMessage opcode[" + opcode + "], sim id[" + slotId + "]");
503 if (opcode == OP_CMD && msg.obj != null &&
504 ((CatCmdMessage)msg.obj).getCmdType()!= null) {
505 CatLog.d(LOG_TAG, "cmdName[" + ((CatCmdMessage)msg.obj).getCmdType().name() + "]");
506 }
507 mStkContext[slotId].mOpCode = opcode;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800508 switch (opcode) {
509 case OP_LAUNCH_APP:
Wink Savillee68857d2014-10-17 15:23:05 -0700510 if (mStkContext[slotId].mMainCmd == null) {
511 CatLog.d(LOG_TAG, "mMainCmd is null");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800512 // nothing todo when no SET UP MENU command didn't arrive.
513 return;
514 }
Wink Savillee68857d2014-10-17 15:23:05 -0700515 CatLog.d(LOG_TAG, "handleMessage OP_LAUNCH_APP - mCmdInProgress[" +
516 mStkContext[slotId].mCmdInProgress + "]");
517
518 //If there is a pending activity for the slot id,
519 //just finish it and create a new one to handle the pending command.
520 cleanUpInstanceStackBySlot(slotId);
521
Wink Savillee68857d2014-10-17 15:23:05 -0700522 CatLog.d(LOG_TAG, "Current cmd type: " +
523 mStkContext[slotId].mCurrentCmd.getCmdType());
524 //Restore the last command from stack by slot id.
525 restoreInstanceFromStackBySlot(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800526 break;
527 case OP_CMD:
Wink Savillee68857d2014-10-17 15:23:05 -0700528 CatLog.d(LOG_TAG, "[OP_CMD]");
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700529 CatCmdMessage cmdMsg = (CatCmdMessage) msg.obj;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800530 // There are two types of commands:
531 // 1. Interactive - user's response is required.
532 // 2. Informative - display a message, no interaction with the user.
533 //
Wink Saville79085fc2009-06-09 10:27:23 -0700534 // Informative commands can be handled immediately without any delay.
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800535 // Interactive commands can't override each other. So if a command
536 // is already in progress, we need to queue the next command until
537 // the user has responded or a timeout expired.
538 if (!isCmdInteractive(cmdMsg)) {
Wink Savillee68857d2014-10-17 15:23:05 -0700539 handleCmd(cmdMsg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800540 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700541 if (!mStkContext[slotId].mCmdInProgress) {
542 mStkContext[slotId].mCmdInProgress = true;
543 handleCmd((CatCmdMessage) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800544 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700545 CatLog.d(LOG_TAG, "[Interactive][in progress]");
546 mStkContext[slotId].mCmdsQ.addLast(new DelayedCmd(OP_CMD,
547 (CatCmdMessage) msg.obj, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800548 }
549 }
550 break;
551 case OP_RESPONSE:
Preeti Ahuja414bc412013-06-25 19:31:49 -0700552 handleCmdResponse((Bundle) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800553 // call delayed commands if needed.
Wink Savillee68857d2014-10-17 15:23:05 -0700554 if (mStkContext[slotId].mCmdsQ.size() != 0) {
555 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800556 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700557 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800558 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800559 break;
560 case OP_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -0700561 if (!mStkContext[slotId].mCmdInProgress) {
562 mStkContext[slotId].mCmdInProgress = true;
563 handleSessionEnd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800564 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700565 mStkContext[slotId].mCmdsQ.addLast(
566 new DelayedCmd(OP_END_SESSION, null, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800567 }
568 break;
569 case OP_BOOT_COMPLETED:
Wink Savillee68857d2014-10-17 15:23:05 -0700570 CatLog.d(LOG_TAG, " OP_BOOT_COMPLETED");
571 int i = 0;
572 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
573 if (mStkContext[i].mMainCmd != null) {
574 break;
575 }
576 }
577 if (i == mSimCount) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800578 StkAppInstaller.unInstall(mContext);
579 }
580 break;
581 case OP_DELAYED_MSG:
Wink Savillee68857d2014-10-17 15:23:05 -0700582 handleDelayedCmd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800583 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700584 case OP_CARD_STATUS_CHANGED:
Wink Savillee68857d2014-10-17 15:23:05 -0700585 CatLog.d(LOG_TAG, "Card/Icc Status change received");
586 handleCardStatusChangeAndIccRefresh((Bundle) msg.obj, slotId);
587 break;
588 case OP_SET_ACT_INST:
589 Activity act = new Activity();
590 act = (Activity) msg.obj;
591 CatLog.d(LOG_TAG, "Set activity instance. " + act);
592 mStkContext[slotId].mActivityInstance = act;
593 break;
594 case OP_SET_DAL_INST:
595 Activity dal = new Activity();
596 CatLog.d(LOG_TAG, "Set dialog instance. " + dal);
597 dal = (Activity) msg.obj;
598 mStkContext[slotId].mDialogInstance = dal;
599 break;
600 case OP_SET_MAINACT_INST:
601 Activity mainAct = new Activity();
602 mainAct = (Activity) msg.obj;
603 CatLog.d(LOG_TAG, "Set activity instance. " + mainAct);
604 mStkContext[slotId].mMainActivityInstance = mainAct;
Wink Saville94e982b2014-07-11 07:38:14 -0700605 break;
Preeti Ahuja95919342013-10-01 18:18:55 -0700606 case OP_LOCALE_CHANGED:
607 CatLog.d(this, "Locale Changed");
Yuta Ui1481b172016-02-03 15:34:31 +0900608 for (int slot = PhoneConstants.SIM_ID_1; slot < mSimCount; slot++) {
609 checkForSetupEvent(LANGUAGE_SELECTION_EVENT, (Bundle) msg.obj, slot);
610 }
Preeti Ahuja95919342013-10-01 18:18:55 -0700611 break;
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530612 case OP_ALPHA_NOTIFY:
613 handleAlphaNotify((Bundle) msg.obj);
614 break;
Preeti Ahuja560be362014-11-25 19:38:24 -0800615 case OP_IDLE_SCREEN:
616 for (int slot = 0; slot < mSimCount; slot++) {
617 if (mStkContext[slot] != null) {
618 handleIdleScreen(slot);
619 }
620 }
621 break;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530622 case OP_STOP_TONE_USER:
623 case OP_STOP_TONE:
624 CatLog.d(this, "Stop tone");
625 handleStopTone(msg, slotId);
626 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700627 }
628 }
629
Wink Savillee68857d2014-10-17 15:23:05 -0700630 private void handleCardStatusChangeAndIccRefresh(Bundle args, int slotId) {
Wink Saville94e982b2014-07-11 07:38:14 -0700631 boolean cardStatus = args.getBoolean(AppInterface.CARD_STATUS);
632
Wink Savillee68857d2014-10-17 15:23:05 -0700633 CatLog.d(LOG_TAG, "CardStatus: " + cardStatus);
Wink Saville94e982b2014-07-11 07:38:14 -0700634 if (cardStatus == false) {
Wink Savillee68857d2014-10-17 15:23:05 -0700635 CatLog.d(LOG_TAG, "CARD is ABSENT");
Wink Saville94e982b2014-07-11 07:38:14 -0700636 // Uninstall STKAPP, Clear Idle text, Stop StkAppService
Wink Savillee68857d2014-10-17 15:23:05 -0700637 mNotificationManager.cancel(getNotificationId(slotId));
638 if (isAllOtherCardsAbsent(slotId)) {
639 CatLog.d(LOG_TAG, "All CARDs are ABSENT");
640 StkAppInstaller.unInstall(mContext);
641 stopSelf();
642 }
Wink Saville94e982b2014-07-11 07:38:14 -0700643 } else {
644 IccRefreshResponse state = new IccRefreshResponse();
645 state.refreshResult = args.getInt(AppInterface.REFRESH_RESULT);
646
Wink Savillee68857d2014-10-17 15:23:05 -0700647 CatLog.d(LOG_TAG, "Icc Refresh Result: "+ state.refreshResult);
Wink Saville94e982b2014-07-11 07:38:14 -0700648 if ((state.refreshResult == IccRefreshResponse.REFRESH_RESULT_INIT) ||
649 (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET)) {
650 // Clear Idle Text
Wink Savillee68857d2014-10-17 15:23:05 -0700651 mNotificationManager.cancel(getNotificationId(slotId));
Wink Saville94e982b2014-07-11 07:38:14 -0700652 }
653
654 if (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET) {
655 // Uninstall STkmenu
Wink Savillee68857d2014-10-17 15:23:05 -0700656 if (isAllOtherCardsAbsent(slotId)) {
657 StkAppInstaller.unInstall(mContext);
658 }
659 mStkContext[slotId].mCurrentMenu = null;
660 mStkContext[slotId].mMainCmd = null;
Wink Saville94e982b2014-07-11 07:38:14 -0700661 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800662 }
663 }
664 }
Wink Savillee68857d2014-10-17 15:23:05 -0700665 /*
666 * Check if all SIMs are absent except the id of slot equals "slotId".
667 */
668 private boolean isAllOtherCardsAbsent(int slotId) {
669 TelephonyManager mTm = (TelephonyManager) mContext.getSystemService(
670 Context.TELEPHONY_SERVICE);
671 int i = 0;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800672
Wink Savillee68857d2014-10-17 15:23:05 -0700673 for (i = 0; i < mSimCount; i++) {
674 if (i != slotId && mTm.hasIccCard(i)) {
675 break;
676 }
677 }
678 if (i == mSimCount) {
679 return true;
680 } else {
681 return false;
682 }
683 }
Preeti Ahuja95919342013-10-01 18:18:55 -0700684
Preeti Ahuja560be362014-11-25 19:38:24 -0800685 /*
686 * If the device is not in an interactive state, we can assume
687 * that the screen is idle.
688 */
689 private boolean isScreenIdle() {
690 return (!mPowerManager.isInteractive());
691 }
692
693 private void handleIdleScreen(int slotId) {
694
695 // If the idle screen event is present in the list need to send the
696 // response to SIM.
697 CatLog.d(this, "Need to send IDLE SCREEN Available event to SIM");
698 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId);
699
700 if (mStkContext[slotId].mIdleModeTextCmd != null) {
701 launchIdleText(slotId);
702 }
703 }
704
705 private void sendScreenBusyResponse(int slotId) {
706 if (mStkContext[slotId].mCurrentCmd == null) {
707 return;
708 }
709 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
710 CatLog.d(this, "SCREEN_BUSY");
711 resMsg.setResultCode(ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS);
712 mStkService[slotId].onCmdResponse(resMsg);
713 if (mStkContext[slotId].mCmdsQ.size() != 0) {
714 callDelayedMsg(slotId);
715 } else {
716 mStkContext[slotId].mCmdInProgress = false;
717 }
718 }
719
Preeti Ahuja95919342013-10-01 18:18:55 -0700720 private void sendResponse(int resId, int slotId, boolean confirm) {
721 Message msg = mServiceHandler.obtainMessage();
722 msg.arg1 = OP_RESPONSE;
Takanori Nakano49b12722016-02-16 14:34:14 +0900723 msg.arg2 = slotId;
Preeti Ahuja95919342013-10-01 18:18:55 -0700724 Bundle args = new Bundle();
725 args.putInt(StkAppService.RES_ID, resId);
Preeti Ahuja95919342013-10-01 18:18:55 -0700726 args.putBoolean(StkAppService.CONFIRMATION, confirm);
727 msg.obj = args;
728 mServiceHandler.sendMessage(msg);
729 }
730
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700731 private boolean isCmdInteractive(CatCmdMessage cmd) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800732 switch (cmd.getCmdType()) {
733 case SEND_DTMF:
734 case SEND_SMS:
735 case SEND_SS:
736 case SEND_USSD:
737 case SET_UP_IDLE_MODE_TEXT:
738 case SET_UP_MENU:
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500739 case CLOSE_CHANNEL:
740 case RECEIVE_DATA:
741 case SEND_DATA:
Preeti Ahuja95919342013-10-01 18:18:55 -0700742 case SET_UP_EVENT_LIST:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800743 return false;
744 }
745
746 return true;
747 }
748
Wink Savillee68857d2014-10-17 15:23:05 -0700749 private void handleDelayedCmd(int slotId) {
750 CatLog.d(LOG_TAG, "handleDelayedCmd, slotId: " + slotId);
751 if (mStkContext[slotId].mCmdsQ.size() != 0) {
752 DelayedCmd cmd = mStkContext[slotId].mCmdsQ.poll();
753 if (cmd != null) {
754 CatLog.d(LOG_TAG, "handleDelayedCmd - queue size: " +
755 mStkContext[slotId].mCmdsQ.size() +
756 " id: " + cmd.id + "sim id: " + cmd.slotId);
757 switch (cmd.id) {
758 case OP_CMD:
759 handleCmd(cmd.msg, cmd.slotId);
760 break;
761 case OP_END_SESSION:
762 handleSessionEnd(cmd.slotId);
763 break;
764 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800765 }
766 }
767 }
768
Wink Savillee68857d2014-10-17 15:23:05 -0700769 private void callDelayedMsg(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800770 Message msg = mServiceHandler.obtainMessage();
771 msg.arg1 = OP_DELAYED_MSG;
Wink Savillee68857d2014-10-17 15:23:05 -0700772 msg.arg2 = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800773 mServiceHandler.sendMessage(msg);
774 }
775
Wink Savillee68857d2014-10-17 15:23:05 -0700776 private void callSetActivityInstMsg(int inst_type, int slotId, Object obj) {
777 Message msg = mServiceHandler.obtainMessage();
778 msg.obj = obj;
779 msg.arg1 = inst_type;
780 msg.arg2 = slotId;
781 mServiceHandler.sendMessage(msg);
782 }
783
784 private void handleSessionEnd(int slotId) {
Legler Wuaeefef52014-10-27 00:57:18 +0800785 // We should finish all pending activity if receiving END SESSION command.
786 cleanUpInstanceStackBySlot(slotId);
787
Wink Savillee68857d2014-10-17 15:23:05 -0700788 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
789 CatLog.d(LOG_TAG, "[handleSessionEnd] - mCurrentCmd changed to mMainCmd!.");
790 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mMainCmd;
791 CatLog.d(LOG_TAG, "slotId: " + slotId + ", mMenuState: " +
792 mStkContext[slotId].mMenuState);
793
794 mStkContext[slotId].mIsInputPending = false;
795 mStkContext[slotId].mIsMenuPending = false;
796 mStkContext[slotId].mIsDialogPending = false;
797
Wink Savillee68857d2014-10-17 15:23:05 -0700798 if (mStkContext[slotId].mMainCmd == null) {
799 CatLog.d(LOG_TAG, "[handleSessionEnd][mMainCmd is null!]");
800 }
801 mStkContext[slotId].lastSelectedItem = null;
Wink Saville79085fc2009-06-09 10:27:23 -0700802 // In case of SET UP MENU command which removed the app, don't
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800803 // update the current menu member.
Wink Savillee68857d2014-10-17 15:23:05 -0700804 if (mStkContext[slotId].mCurrentMenu != null && mStkContext[slotId].mMainCmd != null) {
805 mStkContext[slotId].mCurrentMenu = mStkContext[slotId].mMainCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800806 }
Wink Savillee68857d2014-10-17 15:23:05 -0700807 CatLog.d(LOG_TAG, "[handleSessionEnd][mMenuState]" + mStkContext[slotId].mMenuIsVisible);
808 // In mutiple instance architecture, the main menu for slotId will be finished when user
809 // goes to the Stk menu of the other SIM. So, we should launch a new instance for the
810 // main menu if the main menu instance has been finished.
811 // If the current menu is secondary menu, we should launch main menu.
812 if (StkMenuActivity.STATE_SECONDARY == mStkContext[slotId].mMenuState) {
813 launchMenuActivity(null, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800814 }
Wink Savillee68857d2014-10-17 15:23:05 -0700815 if (mStkContext[slotId].mCmdsQ.size() != 0) {
816 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800817 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700818 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800819 }
820 // In case a launch browser command was just confirmed, launch that url.
Wink Savillee68857d2014-10-17 15:23:05 -0700821 if (mStkContext[slotId].launchBrowser) {
822 mStkContext[slotId].launchBrowser = false;
823 launchBrowser(mStkContext[slotId].mBrowserSettings);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800824 }
825 }
826
Preeti Ahuja560be362014-11-25 19:38:24 -0800827 // returns true if any Stk related activity already has focus on the screen
828 private boolean isTopOfStack() {
pkanwareab12f32017-02-06 08:35:03 -0800829 ActivityManager mActivityManager = (ActivityManager) mContext
Preeti Ahuja560be362014-11-25 19:38:24 -0800830 .getSystemService(ACTIVITY_SERVICE);
pkanwareab12f32017-02-06 08:35:03 -0800831 String currentPackageName = null;
832 List<RunningTaskInfo> tasks = mActivityManager.getRunningTasks(1);
833 if (tasks == null || tasks.get(0).topActivity == null) {
834 return false;
835 }
836 currentPackageName = tasks.get(0).topActivity.getPackageName();
Preeti Ahuja560be362014-11-25 19:38:24 -0800837 if (null != currentPackageName) {
838 return currentPackageName.equals(PACKAGE_NAME);
839 }
Preeti Ahuja560be362014-11-25 19:38:24 -0800840 return false;
841 }
842
Sooraj Sasindrana4160472016-10-12 16:28:25 -0700843 /**
844 * Get the boolean config from carrier config manager.
845 *
846 * @param context the context to get carrier service
847 * @param key config key defined in CarrierConfigManager
848 * @return boolean value of corresponding key.
849 */
850 private static boolean getBooleanCarrierConfig(Context context, String key) {
851 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(
852 Context.CARRIER_CONFIG_SERVICE);
853 PersistableBundle b = null;
854 if (configManager != null) {
855 b = configManager.getConfig();
856 }
857 if (b != null) {
858 return b.getBoolean(key);
859 } else {
860 // Return static default defined in CarrierConfigManager.
861 return CarrierConfigManager.getDefaultConfig().getBoolean(key);
862 }
863 }
864
Wink Savillee68857d2014-10-17 15:23:05 -0700865 private void handleCmd(CatCmdMessage cmdMsg, int slotId) {
Preeti Ahuja95919342013-10-01 18:18:55 -0700866
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800867 if (cmdMsg == null) {
868 return;
869 }
870 // save local reference for state tracking.
Wink Savillee68857d2014-10-17 15:23:05 -0700871 mStkContext[slotId].mCurrentCmd = cmdMsg;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800872 boolean waitForUsersResponse = true;
873
Wink Savillee68857d2014-10-17 15:23:05 -0700874 mStkContext[slotId].mIsInputPending = false;
875 mStkContext[slotId].mIsMenuPending = false;
876 mStkContext[slotId].mIsDialogPending = false;
877
878 CatLog.d(LOG_TAG,"[handleCmd]" + cmdMsg.getCmdType().name());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800879 switch (cmdMsg.getCmdType()) {
880 case DISPLAY_TEXT:
881 TextMessage msg = cmdMsg.geTextMessage();
Jeevaka Badrappan854a25c2012-12-01 16:32:03 +0200882 waitForUsersResponse = msg.responseNeeded;
Wink Savillee68857d2014-10-17 15:23:05 -0700883 if (mStkContext[slotId].lastSelectedItem != null) {
884 msg.title = mStkContext[slotId].lastSelectedItem;
885 } else if (mStkContext[slotId].mMainCmd != null){
886 msg.title = mStkContext[slotId].mMainCmd.getMenu().title;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800887 } else {
888 // TODO: get the carrier name from the SIM
889 msg.title = "";
890 }
Preeti Ahuja560be362014-11-25 19:38:24 -0800891 //If we receive a low priority Display Text and the device is
892 // not displaying any STK related activity and the screen is not idle
893 // ( that is, device is in an interactive state), then send a screen busy
894 // terminal response. Otherwise display the message. The existing
895 // displayed message shall be updated with the new display text
896 // proactive command (Refer to ETSI TS 102 384 section 27.22.4.1.4.4.2).
897 if (!(msg.isHighPriority || mStkContext[slotId].mMenuIsVisible
898 || mStkContext[slotId].mDisplayTextDlgIsVisibile || isTopOfStack())) {
899 if(!isScreenIdle()) {
900 CatLog.d(LOG_TAG, "Screen is not idle");
901 sendScreenBusyResponse(slotId);
902 } else {
903 launchTextDialog(slotId);
904 }
905 } else {
906 launchTextDialog(slotId);
907 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800908 break;
909 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -0700910 CatLog.d(LOG_TAG, "SELECT_ITEM +");
911 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
912 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
913 launchMenuActivity(cmdMsg.getMenu(), slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800914 break;
915 case SET_UP_MENU:
Wink Savillee68857d2014-10-17 15:23:05 -0700916 mStkContext[slotId].mCmdInProgress = false;
917 mStkContext[slotId].mMainCmd = mStkContext[slotId].mCurrentCmd;
918 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
919 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
920 CatLog.d(LOG_TAG, "SET_UP_MENU [" + removeMenu(slotId) + "]");
921
922 if (removeMenu(slotId)) {
923 int i = 0;
924 CatLog.d(LOG_TAG, "removeMenu() - Uninstall App");
925 mStkContext[slotId].mCurrentMenu = null;
Preeti Ahuja95919342013-10-01 18:18:55 -0700926 mStkContext[slotId].mMainCmd = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700927 //Check other setup menu state. If all setup menu are removed, uninstall apk.
928 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
929 if (i != slotId
930 && (mStkContext[slotId].mSetupMenuState == STATE_UNKNOWN
931 || mStkContext[slotId].mSetupMenuState == STATE_EXIST)) {
932 CatLog.d(LOG_TAG, "Not Uninstall App:" + i + ","
933 + mStkContext[slotId].mSetupMenuState);
934 break;
935 }
936 }
937 if (i == mSimCount) {
938 StkAppInstaller.unInstall(mContext);
939 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800940 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700941 CatLog.d(LOG_TAG, "install App");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800942 StkAppInstaller.install(mContext);
943 }
Wink Savillee68857d2014-10-17 15:23:05 -0700944 if (mStkContext[slotId].mMenuIsVisible) {
945 launchMenuActivity(null, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800946 }
947 break;
948 case GET_INPUT:
949 case GET_INKEY:
Wink Savillee68857d2014-10-17 15:23:05 -0700950 launchInputActivity(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800951 break;
952 case SET_UP_IDLE_MODE_TEXT:
953 waitForUsersResponse = false;
Preeti Ahuja560be362014-11-25 19:38:24 -0800954 mStkContext[slotId].mIdleModeTextCmd = mStkContext[slotId].mCurrentCmd;
955 TextMessage idleModeText = mStkContext[slotId].mCurrentCmd.geTextMessage();
956 if (idleModeText == null) {
957 launchIdleText(slotId);
958 mStkContext[slotId].mIdleModeTextCmd = null;
959 }
960 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
961 if ((mStkContext[slotId].mIdleModeTextCmd != null) && isScreenIdle()) {
962 CatLog.d(this, "set up idle mode");
963 launchIdleText(slotId);
964 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800965 break;
966 case SEND_DTMF:
967 case SEND_SMS:
968 case SEND_SS:
969 case SEND_USSD:
Preeti Ahuja95919342013-10-01 18:18:55 -0700970 case GET_CHANNEL_STATUS:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800971 waitForUsersResponse = false;
Wink Savillee68857d2014-10-17 15:23:05 -0700972 launchEventMessage(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800973 break;
974 case LAUNCH_BROWSER:
Ryuto Sawada0bdc7192016-04-18 12:10:56 +0900975 // The device setup process should not be interrupted by launching browser.
976 if (Settings.Global.getInt(mContext.getContentResolver(),
977 Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
978 CatLog.d(this, "The command is not performed if the setup has not been completed.");
979 sendScreenBusyResponse(slotId);
980 break;
981 }
Sooraj Sasindrana4160472016-10-12 16:28:25 -0700982
983 /* Check if Carrier would not want to launch browser */
984 if (getBooleanCarrierConfig(mContext,
985 CarrierConfigManager.KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL)) {
986 CatLog.d(this, "Browser is not launched as per carrier.");
987 sendResponse(RES_ID_DONE, slotId, true);
988 break;
989 }
990
Preeti Ahujaa7cdca22013-10-01 18:20:56 -0700991 TextMessage alphaId = mStkContext[slotId].mCurrentCmd.geTextMessage();
992 if ((mStkContext[slotId].mCurrentCmd.getBrowserSettings().mode
993 == LaunchBrowserMode.LAUNCH_IF_NOT_ALREADY_LAUNCHED) &&
994 ((alphaId == null) || TextUtils.isEmpty(alphaId.text))) {
995 // don't need user confirmation in this case
996 // just launch the browser or spawn a new tab
997 CatLog.d(this, "Browser mode is: launch if not already launched " +
998 "and user confirmation is not currently needed.\n" +
999 "supressing confirmation dialogue and confirming silently...");
1000 mStkContext[slotId].launchBrowser = true;
1001 mStkContext[slotId].mBrowserSettings =
1002 mStkContext[slotId].mCurrentCmd.getBrowserSettings();
1003 sendResponse(RES_ID_CONFIRM, slotId, true);
1004 } else {
1005 launchConfirmationDialog(alphaId, slotId);
1006 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001007 break;
1008 case SET_UP_CALL:
Preeti Ahujadd240102013-08-30 17:25:06 -07001009 TextMessage mesg = mStkContext[slotId].mCurrentCmd.getCallSettings().confirmMsg;
1010 if((mesg != null) && (mesg.text == null || mesg.text.length() == 0)) {
1011 mesg.text = getResources().getString(R.string.default_setup_call_msg);
1012 }
1013 CatLog.d(this, "SET_UP_CALL mesg.text " + mesg.text);
1014 launchConfirmationDialog(mesg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001015 break;
1016 case PLAY_TONE:
Srikanth Chintala89aa6602014-03-14 16:26:57 +05301017 handlePlayTone(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001018 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001019 case OPEN_CHANNEL:
Wink Savillee68857d2014-10-17 15:23:05 -07001020 launchOpenChannelDialog(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001021 break;
1022 case CLOSE_CHANNEL:
1023 case RECEIVE_DATA:
1024 case SEND_DATA:
Wink Savillee68857d2014-10-17 15:23:05 -07001025 TextMessage m = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001026
1027 if ((m != null) && (m.text == null)) {
1028 switch(cmdMsg.getCmdType()) {
1029 case CLOSE_CHANNEL:
1030 m.text = getResources().getString(R.string.default_close_channel_msg);
1031 break;
1032 case RECEIVE_DATA:
1033 m.text = getResources().getString(R.string.default_receive_data_msg);
1034 break;
1035 case SEND_DATA:
1036 m.text = getResources().getString(R.string.default_send_data_msg);
1037 break;
1038 }
1039 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001040 /*
1041 * Display indication in the form of a toast to the user if required.
1042 */
Wink Savillee68857d2014-10-17 15:23:05 -07001043 launchEventMessage(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001044 break;
Preeti Ahuja95919342013-10-01 18:18:55 -07001045 case SET_UP_EVENT_LIST:
1046 mStkContext[slotId].mSetupEventListSettings =
1047 mStkContext[slotId].mCurrentCmd.getSetEventList();
1048 mStkContext[slotId].mCurrentSetupEventCmd = mStkContext[slotId].mCurrentCmd;
1049 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
Preeti Ahuja560be362014-11-25 19:38:24 -08001050 if (isScreenIdle()) {
1051 CatLog.d(this," Check if IDLE_SCREEN_AVAILABLE_EVENT is present in List");
1052 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId);
1053 }
Preeti Ahuja95919342013-10-01 18:18:55 -07001054 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001055 }
1056
1057 if (!waitForUsersResponse) {
Wink Savillee68857d2014-10-17 15:23:05 -07001058 if (mStkContext[slotId].mCmdsQ.size() != 0) {
1059 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001060 } else {
Wink Savillee68857d2014-10-17 15:23:05 -07001061 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001062 }
1063 }
1064 }
1065
Wink Savillee68857d2014-10-17 15:23:05 -07001066 private void handleCmdResponse(Bundle args, int slotId) {
1067 CatLog.d(LOG_TAG, "handleCmdResponse, sim id: " + slotId);
1068 if (mStkContext[slotId].mCurrentCmd == null) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001069 return;
1070 }
Wink Savillee68857d2014-10-17 15:23:05 -07001071
1072 if (mStkService[slotId] == null) {
Legler Wuaeefef52014-10-27 00:57:18 +08001073 mStkService[slotId] = CatService.getInstance(slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07001074 if (mStkService[slotId] == null) {
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -07001075 // This should never happen (we should be responding only to a message
1076 // that arrived from StkService). It has to exist by this time
Wink Savillee68857d2014-10-17 15:23:05 -07001077 CatLog.d(LOG_TAG, "Exception! mStkService is null when we need to send response.");
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -07001078 throw new RuntimeException("mStkService is null when we need to send response");
1079 }
1080 }
1081
Wink Savillee68857d2014-10-17 15:23:05 -07001082 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001083
1084 // set result code
1085 boolean helpRequired = args.getBoolean(HELP, false);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001086 boolean confirmed = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001087
1088 switch(args.getInt(RES_ID)) {
1089 case RES_ID_MENU_SELECTION:
Wink Savillee68857d2014-10-17 15:23:05 -07001090 CatLog.d(LOG_TAG, "MENU_SELECTION=" + mStkContext[slotId].
1091 mCurrentMenuCmd.getCmdType());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001092 int menuSelection = args.getInt(MENU_SELECTION);
Wink Savillee68857d2014-10-17 15:23:05 -07001093 switch(mStkContext[slotId].mCurrentMenuCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001094 case SET_UP_MENU:
1095 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -07001096 mStkContext[slotId].lastSelectedItem = getItemName(menuSelection, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001097 if (helpRequired) {
1098 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
1099 } else {
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301100 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1101 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001102 }
1103 resMsg.setMenuSelection(menuSelection);
1104 break;
1105 }
1106 break;
1107 case RES_ID_INPUT:
Wink Savillee68857d2014-10-17 15:23:05 -07001108 CatLog.d(LOG_TAG, "RES_ID_INPUT");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001109 String input = args.getString(INPUT);
Wink Savillee68857d2014-10-17 15:23:05 -07001110 if (input != null && (null != mStkContext[slotId].mCurrentCmd.geInput()) &&
1111 (mStkContext[slotId].mCurrentCmd.geInput().yesNo)) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001112 boolean yesNoSelection = input
1113 .equals(StkInputActivity.YES_STR_RESPONSE);
1114 resMsg.setYesNo(yesNoSelection);
1115 } else {
1116 if (helpRequired) {
1117 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
1118 } else {
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301119 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1120 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001121 resMsg.setInput(input);
1122 }
1123 }
1124 break;
1125 case RES_ID_CONFIRM:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -07001126 CatLog.d(this, "RES_ID_CONFIRM");
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001127 confirmed = args.getBoolean(CONFIRMATION);
Wink Savillee68857d2014-10-17 15:23:05 -07001128 switch (mStkContext[slotId].mCurrentCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001129 case DISPLAY_TEXT:
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301130 if (confirmed) {
1131 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1132 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
1133 } else {
1134 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
1135 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001136 break;
1137 case LAUNCH_BROWSER:
1138 resMsg.setResultCode(confirmed ? ResultCode.OK
1139 : ResultCode.UICC_SESSION_TERM_BY_USER);
1140 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -07001141 mStkContext[slotId].launchBrowser = true;
1142 mStkContext[slotId].mBrowserSettings =
1143 mStkContext[slotId].mCurrentCmd.getBrowserSettings();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001144 }
1145 break;
1146 case SET_UP_CALL:
1147 resMsg.setResultCode(ResultCode.OK);
1148 resMsg.setConfirmation(confirmed);
1149 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -07001150 launchEventMessage(slotId,
1151 mStkContext[slotId].mCurrentCmd.getCallSettings().callMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001152 }
1153 break;
1154 }
1155 break;
1156 case RES_ID_DONE:
1157 resMsg.setResultCode(ResultCode.OK);
1158 break;
1159 case RES_ID_BACKWARD:
Wink Savillee68857d2014-10-17 15:23:05 -07001160 CatLog.d(LOG_TAG, "RES_ID_BACKWARD");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001161 resMsg.setResultCode(ResultCode.BACKWARD_MOVE_BY_USER);
1162 break;
1163 case RES_ID_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -07001164 CatLog.d(LOG_TAG, "RES_ID_END_SESSION");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001165 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
1166 break;
1167 case RES_ID_TIMEOUT:
Wink Savillee68857d2014-10-17 15:23:05 -07001168 CatLog.d(LOG_TAG, "RES_ID_TIMEOUT");
Naveen Kallad5176892009-11-30 12:45:29 -08001169 // GCF test-case 27.22.4.1.1 Expected Sequence 1.5 (DISPLAY TEXT,
1170 // Clear message after delay, successful) expects result code OK.
1171 // If the command qualifier specifies no user response is required
1172 // then send OK instead of NO_RESPONSE_FROM_USER
Wink Savillee68857d2014-10-17 15:23:05 -07001173 if ((mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1174 AppInterface.CommandType.DISPLAY_TEXT.value())
1175 && (mStkContext[slotId].mCurrentCmd.geTextMessage().userClear == false)) {
Naveen Kallad5176892009-11-30 12:45:29 -08001176 resMsg.setResultCode(ResultCode.OK);
1177 } else {
1178 resMsg.setResultCode(ResultCode.NO_RESPONSE_FROM_USER);
1179 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001180 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001181 case RES_ID_CHOICE:
1182 int choice = args.getInt(CHOICE);
1183 CatLog.d(this, "User Choice=" + choice);
1184 switch (choice) {
1185 case YES:
1186 resMsg.setResultCode(ResultCode.OK);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001187 confirmed = true;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001188 break;
1189 case NO:
1190 resMsg.setResultCode(ResultCode.USER_NOT_ACCEPT);
1191 break;
1192 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001193
Wink Savillee68857d2014-10-17 15:23:05 -07001194 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1195 AppInterface.CommandType.OPEN_CHANNEL.value()) {
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001196 resMsg.setConfirmation(confirmed);
1197 }
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001198 break;
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001199
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001200 default:
Wink Savillee68857d2014-10-17 15:23:05 -07001201 CatLog.d(LOG_TAG, "Unknown result id");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001202 return;
1203 }
Wink Savillee68857d2014-10-17 15:23:05 -07001204
1205 if (null != mStkContext[slotId].mCurrentCmd &&
1206 null != mStkContext[slotId].mCurrentCmd.getCmdType()) {
1207 CatLog.d(LOG_TAG, "handleCmdResponse- cmdName[" +
1208 mStkContext[slotId].mCurrentCmd.getCmdType().name() + "]");
1209 }
1210 mStkService[slotId].onCmdResponse(resMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001211 }
1212
1213 /**
1214 * Returns 0 or FLAG_ACTIVITY_NO_USER_ACTION, 0 means the user initiated the action.
1215 *
1216 * @param userAction If the userAction is yes then we always return 0 otherwise
1217 * mMenuIsVisible is used to determine what to return. If mMenuIsVisible is true
1218 * then we are the foreground app and we'll return 0 as from our perspective a
1219 * user action did cause. If it's false than we aren't the foreground app and
1220 * FLAG_ACTIVITY_NO_USER_ACTION is returned.
Wink Saville79085fc2009-06-09 10:27:23 -07001221 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001222 * @return 0 or FLAG_ACTIVITY_NO_USER_ACTION
1223 */
Wink Savillee68857d2014-10-17 15:23:05 -07001224 private int getFlagActivityNoUserAction(InitiatedByUserAction userAction, int slotId) {
1225 return ((userAction == InitiatedByUserAction.yes) | mStkContext[slotId].mMenuIsVisible)
1226 ? 0 : Intent.FLAG_ACTIVITY_NO_USER_ACTION;
1227 }
1228 /**
1229 * This method is used for cleaning up pending instances in stack.
1230 */
1231 private void cleanUpInstanceStackBySlot(int slotId) {
1232 Activity activity = mStkContext[slotId].getPendingActivityInstance();
1233 Activity dialog = mStkContext[slotId].getPendingDialogInstance();
1234 CatLog.d(LOG_TAG, "cleanUpInstanceStackBySlot slotId: " + slotId);
Legler Wuaeefef52014-10-27 00:57:18 +08001235 if (mStkContext[slotId].mCurrentCmd == null) {
1236 CatLog.d(LOG_TAG, "current cmd is null.");
1237 return;
1238 }
Wink Savillee68857d2014-10-17 15:23:05 -07001239 if (activity != null) {
1240 CatLog.d(LOG_TAG, "current cmd type: " +
1241 mStkContext[slotId].mCurrentCmd.getCmdType());
1242 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1243 AppInterface.CommandType.GET_INPUT.value() ||
1244 mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1245 AppInterface.CommandType.GET_INKEY.value()) {
1246 mStkContext[slotId].mIsInputPending = true;
1247 } else if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1248 AppInterface.CommandType.SET_UP_MENU.value() ||
1249 mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1250 AppInterface.CommandType.SELECT_ITEM.value()) {
1251 mStkContext[slotId].mIsMenuPending = true;
1252 } else {
1253 }
1254 CatLog.d(LOG_TAG, "finish pending activity.");
1255 activity.finish();
1256 mStkContext[slotId].mActivityInstance = null;
1257 }
1258 if (dialog != null) {
1259 CatLog.d(LOG_TAG, "finish pending dialog.");
1260 mStkContext[slotId].mIsDialogPending = true;
1261 dialog.finish();
1262 mStkContext[slotId].mDialogInstance = null;
1263 }
1264 }
1265 /**
1266 * This method is used for restoring pending instances from stack.
1267 */
1268 private void restoreInstanceFromStackBySlot(int slotId) {
1269 AppInterface.CommandType cmdType = mStkContext[slotId].mCurrentCmd.getCmdType();
1270
1271 CatLog.d(LOG_TAG, "restoreInstanceFromStackBySlot cmdType : " + cmdType);
1272 switch(cmdType) {
1273 case GET_INPUT:
1274 case GET_INKEY:
1275 launchInputActivity(slotId);
1276 //Set mMenuIsVisible to true for showing main menu for
1277 //following session end command.
1278 mStkContext[slotId].mMenuIsVisible = true;
1279 break;
1280 case DISPLAY_TEXT:
1281 launchTextDialog(slotId);
1282 break;
1283 case LAUNCH_BROWSER:
1284 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.geTextMessage(),
1285 slotId);
1286 break;
1287 case OPEN_CHANNEL:
1288 launchOpenChannelDialog(slotId);
1289 break;
1290 case SET_UP_CALL:
1291 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.getCallSettings().
1292 confirmMsg, slotId);
1293 break;
1294 case SET_UP_MENU:
1295 case SELECT_ITEM:
1296 launchMenuActivity(null, slotId);
1297 break;
1298 default:
1299 break;
1300 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001301 }
1302
Wink Savillee68857d2014-10-17 15:23:05 -07001303 private void launchMenuActivity(Menu menu, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001304 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001305 String targetActivity = STK_MENU_ACTIVITY_NAME;
1306 String uriString = STK_MENU_URI + System.currentTimeMillis();
1307 //Set unique URI to create a new instance of activity for different slotId.
1308 Uri uriData = Uri.parse(uriString);
1309
1310 CatLog.d(LOG_TAG, "launchMenuActivity, slotId: " + slotId + " , " +
1311 uriData.toString() + " , " + mStkContext[slotId].mOpCode + ", "
1312 + mStkContext[slotId].mMenuState);
1313 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1314 int intentFlags = Intent.FLAG_ACTIVITY_NEW_TASK;
1315
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001316 if (menu == null) {
1317 // We assume this was initiated by the user pressing the tool kit icon
Wink Savillee68857d2014-10-17 15:23:05 -07001318 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.yes, slotId);
1319 if (mStkContext[slotId].mOpCode == OP_END_SESSION) {
1320 CatLog.d(LOG_TAG, "launchMenuActivity, return OP_END_SESSION");
1321 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
1322 if (mStkContext[slotId].mMainActivityInstance != null) {
1323 CatLog.d(LOG_TAG, "launchMenuActivity, mMainActivityInstance is not null");
1324 return;
1325 }
Wink Savillee68857d2014-10-17 15:23:05 -07001326 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001327
Wink Savillee68857d2014-10-17 15:23:05 -07001328 //If the last pending menu is secondary menu, "STATE" should be "STATE_SECONDARY".
1329 //Otherwise, it should be "STATE_MAIN".
1330 if (mStkContext[slotId].mOpCode == OP_LAUNCH_APP &&
1331 mStkContext[slotId].mMenuState == StkMenuActivity.STATE_SECONDARY) {
1332 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
1333 } else {
1334 newIntent.putExtra("STATE", StkMenuActivity.STATE_MAIN);
1335 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
1336 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001337 } else {
1338 // We don't know and we'll let getFlagActivityNoUserAction decide.
Wink Savillee68857d2014-10-17 15:23:05 -07001339 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001340 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
Wink Savillee68857d2014-10-17 15:23:05 -07001341 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_SECONDARY;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001342 }
Wink Savillee68857d2014-10-17 15:23:05 -07001343 newIntent.putExtra(SLOT_ID, slotId);
1344 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001345 newIntent.setFlags(intentFlags);
1346 mContext.startActivity(newIntent);
1347 }
1348
Wink Savillee68857d2014-10-17 15:23:05 -07001349 private void launchInputActivity(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001350 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001351 String targetActivity = STK_INPUT_ACTIVITY_NAME;
1352 String uriString = STK_INPUT_URI + System.currentTimeMillis();
1353 //Set unique URI to create a new instance of activity for different slotId.
1354 Uri uriData = Uri.parse(uriString);
1355
1356 CatLog.d(LOG_TAG, "launchInputActivity, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001357 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
Wink Savillee68857d2014-10-17 15:23:05 -07001358 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1359 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1360 newIntent.putExtra("INPUT", mStkContext[slotId].mCurrentCmd.geInput());
1361 newIntent.putExtra(SLOT_ID, slotId);
1362 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001363 mContext.startActivity(newIntent);
1364 }
1365
Wink Savillee68857d2014-10-17 15:23:05 -07001366 private void launchTextDialog(int slotId) {
1367 CatLog.d(LOG_TAG, "launchTextDialog, slotId: " + slotId);
1368 Intent newIntent = new Intent();
1369 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1370 int action = getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
1371 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1372 //Set unique URI to create a new instance of activity for different slotId.
1373 Uri uriData = Uri.parse(uriString);
1374 if (newIntent != null) {
1375 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1376 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1377 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1378 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1379 newIntent.setData(uriData);
1380 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1381 newIntent.putExtra(SLOT_ID, slotId);
1382 startActivity(newIntent);
Preeti Ahuja414bc412013-06-25 19:31:49 -07001383 // For display texts with immediate response, send the terminal response
1384 // immediately. responseNeeded will be false, if display text command has
1385 // the immediate response tlv.
1386 if (!mStkContext[slotId].mCurrentCmd.geTextMessage().responseNeeded) {
1387 sendResponse(RES_ID_CONFIRM, slotId, true);
1388 }
Wink Savillee68857d2014-10-17 15:23:05 -07001389 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001390 }
1391
Wink Savillee68857d2014-10-17 15:23:05 -07001392 public boolean isStkDialogActivated(Context context) {
1393 String stkDialogActivity = "com.android.stk.StkDialogActivity";
1394 boolean activated = false;
1395 final ActivityManager am = (ActivityManager) context.getSystemService(
1396 Context.ACTIVITY_SERVICE);
1397 String topActivity = am.getRunningTasks(1).get(0).topActivity.getClassName();
1398
1399 CatLog.d(LOG_TAG, "isStkDialogActivated: " + topActivity);
1400 if (topActivity.equals(stkDialogActivity)) {
1401 activated = true;
1402 }
1403 CatLog.d(LOG_TAG, "activated : " + activated);
1404 return activated;
Johan Hellman3aec01c2011-02-10 10:15:28 +01001405 }
1406
Preeti Ahuja95919342013-10-01 18:18:55 -07001407 private void sendSetUpEventResponse(int event, byte[] addedInfo, int slotId) {
Preeti Ahuja414bc412013-06-25 19:31:49 -07001408 CatLog.d(this, "sendSetUpEventResponse: event : " + event + "slotId = " + slotId);
Preeti Ahuja95919342013-10-01 18:18:55 -07001409
1410 if (mStkContext[slotId].mCurrentSetupEventCmd == null){
1411 CatLog.e(this, "mCurrentSetupEventCmd is null");
1412 return;
1413 }
1414
1415 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentSetupEventCmd);
1416
1417 resMsg.setResultCode(ResultCode.OK);
1418 resMsg.setEventDownload(event, addedInfo);
1419
1420 mStkService[slotId].onCmdResponse(resMsg);
1421 }
1422
1423 private void checkForSetupEvent(int event, Bundle args, int slotId) {
1424 boolean eventPresent = false;
1425 byte[] addedInfo = null;
1426 CatLog.d(this, "Event :" + event);
1427
1428 if (mStkContext[slotId].mSetupEventListSettings != null) {
1429 /* Checks if the event is present in the EventList updated by last
1430 * SetupEventList Proactive Command */
1431 for (int i : mStkContext[slotId].mSetupEventListSettings.eventList) {
1432 if (event == i) {
1433 eventPresent = true;
1434 break;
1435 }
1436 }
1437
1438 /* If Event is present send the response to ICC */
1439 if (eventPresent == true) {
1440 CatLog.d(this, " Event " + event + "exists in the EventList");
1441
1442 switch (event) {
Preeti Ahuja560be362014-11-25 19:38:24 -08001443 case IDLE_SCREEN_AVAILABLE_EVENT:
1444 sendSetUpEventResponse(event, addedInfo, slotId);
1445 removeSetUpEvent(event, slotId);
1446 break;
Preeti Ahuja95919342013-10-01 18:18:55 -07001447 case LANGUAGE_SELECTION_EVENT:
1448 String language = mContext
1449 .getResources().getConfiguration().locale.getLanguage();
1450 CatLog.d(this, "language: " + language);
1451 // Each language code is a pair of alpha-numeric characters.
1452 // Each alpha-numeric character shall be coded on one byte
1453 // using the SMS default 7-bit coded alphabet
1454 addedInfo = GsmAlphabet.stringToGsm8BitPacked(language);
1455 sendSetUpEventResponse(event, addedInfo, slotId);
1456 break;
1457 default:
1458 break;
1459 }
1460 } else {
1461 CatLog.e(this, " Event does not exist in the EventList");
1462 }
1463 } else {
1464 CatLog.e(this, "SetupEventList is not received. Ignoring the event: " + event);
1465 }
1466 }
1467
1468 private void removeSetUpEvent(int event, int slotId) {
1469 CatLog.d(this, "Remove Event :" + event);
1470
1471 if (mStkContext[slotId].mSetupEventListSettings != null) {
1472 /*
1473 * Make new Eventlist without the event
1474 */
1475 for (int i = 0; i < mStkContext[slotId].mSetupEventListSettings.eventList.length; i++) {
1476 if (event == mStkContext[slotId].mSetupEventListSettings.eventList[i]) {
1477 mStkContext[slotId].mSetupEventListSettings.eventList[i] = INVALID_SETUP_EVENT;
1478 break;
1479 }
1480 }
1481 }
1482 }
1483
1484 private void launchEventMessage(int slotId) {
1485 launchEventMessage(slotId, mStkContext[slotId].mCurrentCmd.geTextMessage());
1486 }
1487
Wink Savillee68857d2014-10-17 15:23:05 -07001488 private void launchEventMessage(int slotId, TextMessage msg) {
1489 if (msg == null || (msg.text != null && msg.text.length() == 0)) {
1490 CatLog.d(LOG_TAG, "launchEventMessage return");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001491 return;
1492 }
Wink Savillee68857d2014-10-17 15:23:05 -07001493
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001494 Toast toast = new Toast(mContext.getApplicationContext());
1495 LayoutInflater inflate = (LayoutInflater) mContext
1496 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
1497 View v = inflate.inflate(R.layout.stk_event_msg, null);
1498 TextView tv = (TextView) v
1499 .findViewById(com.android.internal.R.id.message);
1500 ImageView iv = (ImageView) v
1501 .findViewById(com.android.internal.R.id.icon);
1502 if (msg.icon != null) {
1503 iv.setImageBitmap(msg.icon);
1504 } else {
1505 iv.setVisibility(View.GONE);
1506 }
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301507 /* In case of 'self explanatory' stkapp should display the specified
1508 * icon in proactive command (but not the alpha string).
1509 * If icon is non-self explanatory and if the icon could not be displayed
1510 * then alpha string or text data should be displayed
1511 * Ref: ETSI 102.223,section 6.5.4
1512 */
1513 if (mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ||
1514 msg.icon == null || !msg.iconSelfExplanatory) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001515 tv.setText(msg.text);
1516 }
1517
1518 toast.setView(v);
1519 toast.setDuration(Toast.LENGTH_LONG);
1520 toast.setGravity(Gravity.BOTTOM, 0, 0);
1521 toast.show();
1522 }
1523
Wink Savillee68857d2014-10-17 15:23:05 -07001524 private void launchConfirmationDialog(TextMessage msg, int slotId) {
1525 msg.title = mStkContext[slotId].lastSelectedItem;
1526 Intent newIntent = new Intent();
1527 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1528 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1529 //Set unique URI to create a new instance of activity for different slotId.
1530 Uri uriData = Uri.parse(uriString);
1531
1532 if (newIntent != null) {
1533 newIntent.setClassName(this, targetActivity);
1534 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1535 | Intent.FLAG_ACTIVITY_NO_HISTORY
1536 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1537 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1538 newIntent.putExtra("TEXT", msg);
1539 newIntent.putExtra(SLOT_ID, slotId);
1540 newIntent.setData(uriData);
1541 startActivity(newIntent);
1542 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001543 }
1544
1545 private void launchBrowser(BrowserSettings settings) {
1546 if (settings == null) {
1547 return;
1548 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001549
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001550 Uri data = null;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001551 String url;
1552 if (settings.url == null) {
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001553 // if the command did not contain a URL,
1554 // launch the browser to the default homepage.
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001555 CatLog.d(this, "no url data provided by proactive command." +
1556 " launching browser with stk default URL ... ");
1557 url = SystemProperties.get(STK_BROWSER_DEFAULT_URL_SYSPROP,
1558 "http://www.google.com");
1559 } else {
1560 CatLog.d(this, "launch browser command has attached url = " + settings.url);
1561 url = settings.url;
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001562 }
David Brown7c03cfe2011-10-20 15:36:12 -07001563
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001564 if (url.startsWith("http://") || url.startsWith("https://")) {
1565 data = Uri.parse(url);
1566 CatLog.d(this, "launching browser with url = " + url);
1567 } else {
1568 String modifiedUrl = "http://" + url;
1569 data = Uri.parse(modifiedUrl);
1570 CatLog.d(this, "launching browser with modified url = " + modifiedUrl);
1571 }
1572
1573 Intent intent = new Intent(Intent.ACTION_VIEW);
1574 intent.setData(data);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001575 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1576 switch (settings.mode) {
1577 case USE_EXISTING_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001578 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1579 break;
1580 case LAUNCH_NEW_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001581 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
1582 break;
1583 case LAUNCH_IF_NOT_ALREADY_LAUNCHED:
1584 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1585 break;
1586 }
1587 // start browser activity
1588 startActivity(intent);
1589 // a small delay, let the browser start, before processing the next command.
Wink Saville79085fc2009-06-09 10:27:23 -07001590 // this is good for scenarios where a related DISPLAY TEXT command is
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001591 // followed immediately.
1592 try {
Ryuto Sawada350aaa62016-06-13 14:47:22 +09001593 Thread.sleep(3000);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001594 } catch (InterruptedException e) {}
1595 }
1596
Wink Savillee68857d2014-10-17 15:23:05 -07001597 private void launchIdleText(int slotId) {
Preeti Ahuja560be362014-11-25 19:38:24 -08001598 TextMessage msg = mStkContext[slotId].mIdleModeTextCmd.geTextMessage();
dujin.cha2a0eb2a2011-11-11 15:03:57 +09001599
Preeti Ahuja95919342013-10-01 18:18:55 -07001600 if (msg == null || msg.text ==null) {
1601 CatLog.d(LOG_TAG, msg == null ? "mCurrent.getTextMessage is NULL"
1602 : "mCurrent.getTextMessage.text is NULL");
Wink Savillee68857d2014-10-17 15:23:05 -07001603 mNotificationManager.cancel(getNotificationId(slotId));
Wink Saville046db4b2011-11-01 20:42:54 -07001604 return;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001605 } else {
Preeti Ahuja95919342013-10-01 18:18:55 -07001606 CatLog.d(LOG_TAG, "launchIdleText - text[" + msg.text
1607 + "] iconSelfExplanatory[" + msg.iconSelfExplanatory
1608 + "] icon[" + msg.icon + "], sim id: " + slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07001609 CatLog.d(LOG_TAG, "Add IdleMode text");
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001610 PendingIntent pendingIntent = PendingIntent.getService(mContext, 0,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001611 new Intent(mContext, StkAppService.class), 0);
1612
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001613 final Notification.Builder notificationBuilder = new Notification.Builder(
1614 StkAppService.this);
Wink Savillee68857d2014-10-17 15:23:05 -07001615 if (mStkContext[slotId].mMainCmd != null &&
1616 mStkContext[slotId].mMainCmd.getMenu() != null) {
1617 notificationBuilder.setContentTitle(mStkContext[slotId].mMainCmd.getMenu().title);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02001618 } else {
1619 notificationBuilder.setContentTitle("");
1620 }
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001621 notificationBuilder
1622 .setSmallIcon(com.android.internal.R.drawable.stat_notify_sim_toolkit);
1623 notificationBuilder.setContentIntent(pendingIntent);
1624 notificationBuilder.setOngoing(true);
1625 // Set text and icon for the status bar and notification body.
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301626 if (mStkContext[slotId].mIdleModeTextCmd.hasIconLoadFailed() ||
1627 !msg.iconSelfExplanatory) {
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001628 notificationBuilder.setContentText(msg.text);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02001629 notificationBuilder.setTicker(msg.text);
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001630 }
1631 if (msg.icon != null) {
1632 notificationBuilder.setLargeIcon(msg.icon);
1633 } else {
1634 Bitmap bitmapIcon = BitmapFactory.decodeResource(StkAppService.this
1635 .getResources().getSystem(),
1636 com.android.internal.R.drawable.stat_notify_sim_toolkit);
1637 notificationBuilder.setLargeIcon(bitmapIcon);
1638 }
Selim Cinek62eb3fe2014-08-27 17:52:23 +02001639 notificationBuilder.setColor(mContext.getResources().getColor(
1640 com.android.internal.R.color.system_notification_accent_color));
Wink Savillee68857d2014-10-17 15:23:05 -07001641 mNotificationManager.notify(getNotificationId(slotId), notificationBuilder.build());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001642 }
1643 }
1644
Srikanth Chintala89aa6602014-03-14 16:26:57 +05301645 private void handlePlayTone(int slotId) {
1646 TextMessage toneMsg = mStkContext[slotId].mCurrentCmd.geTextMessage();
1647
1648 boolean showUser = true;
1649 boolean displayDialog = true;
1650 Resources resource = Resources.getSystem();
1651 try {
1652 displayDialog = !resource.getBoolean(
1653 com.android.internal.R.bool.config_stkNoAlphaUsrCnf);
1654 } catch (NotFoundException e) {
1655 displayDialog = true;
1656 }
1657
1658 // As per the spec 3GPP TS 11.14, 6.4.5. Play Tone.
1659 // If there is no alpha identifier tlv present, UE may show the
1660 // user information. 'config_stkNoAlphaUsrCnf' value will decide
1661 // whether to show it or not.
1662 // If alpha identifier tlv is present and its data is null, play only tone
1663 // without showing user any information.
1664 // Alpha Id is Present, but the text data is null.
1665 if ((toneMsg.text != null ) && (toneMsg.text.equals(""))) {
1666 CatLog.d(this, "Alpha identifier data is null, play only tone");
1667 showUser = false;
1668 }
1669 // Alpha Id is not present AND we need to show info to the user.
1670 if (toneMsg.text == null && displayDialog) {
1671 CatLog.d(this, "toneMsg.text " + toneMsg.text
1672 + " Starting ToneDialog activity with default message.");
1673 toneMsg.text = getResources().getString(R.string.default_tone_dialog_msg);
1674 showUser = true;
1675 }
1676 // Dont show user info, if config setting is true.
1677 if (toneMsg.text == null && !displayDialog) {
1678 CatLog.d(this, "config value stkNoAlphaUsrCnf is true");
1679 showUser = false;
1680 }
1681
1682 CatLog.d(this, "toneMsg.text: " + toneMsg.text + "showUser: " +showUser +
1683 "displayDialog: " +displayDialog);
1684 playTone(showUser, slotId);
1685 }
1686
1687 private void playTone(boolean showUserInfo, int slotId) {
1688 // Start playing tone and vibration
1689 ToneSettings settings = mStkContext[slotId].mCurrentCmd.getToneSettings();
1690 if (null == settings) {
1691 CatLog.d(this, "null settings, not playing tone.");
1692 return;
1693 }
1694
1695 mVibrator = (Vibrator)getSystemService(VIBRATOR_SERVICE);
1696 mTonePlayer = new TonePlayer();
1697 mTonePlayer.play(settings.tone);
1698 int timeout = StkApp.calculateDurationInMilis(settings.duration);
1699 if (timeout == 0) {
1700 timeout = StkApp.TONE_DEFAULT_TIMEOUT;
1701 }
1702
1703 Message msg = mServiceHandler.obtainMessage();
1704 msg.arg1 = OP_STOP_TONE;
1705 msg.arg2 = slotId;
1706 msg.obj = (Integer)(showUserInfo ? 1 : 0);
1707 msg.what = STOP_TONE_WHAT;
1708 mServiceHandler.sendMessageDelayed(msg, timeout);
1709 if (settings.vibrate) {
1710 mVibrator.vibrate(timeout);
1711 }
1712
1713 // Start Tone dialog Activity to show user the information.
1714 if (showUserInfo) {
1715 Intent newIntent = new Intent(sInstance, ToneDialog.class);
1716 String uriString = STK_TONE_URI + slotId;
1717 Uri uriData = Uri.parse(uriString);
1718 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1719 | Intent.FLAG_ACTIVITY_NO_HISTORY
1720 | Intent.FLAG_ACTIVITY_SINGLE_TOP
1721 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1722 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1723 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1724 newIntent.putExtra(SLOT_ID, slotId);
1725 newIntent.setData(uriData);
1726 startActivity(newIntent);
1727 }
1728 }
1729
1730 private void finishToneDialogActivity() {
1731 Intent finishIntent = new Intent(FINISH_TONE_ACTIVITY_ACTION);
1732 sendBroadcast(finishIntent);
1733 }
1734
1735 private void handleStopTone(Message msg, int slotId) {
1736 int resId = 0;
1737
1738 // Stop the play tone in following cases:
1739 // 1.OP_STOP_TONE: play tone timer expires.
1740 // 2.STOP_TONE_USER: user pressed the back key.
1741 if (msg.arg1 == OP_STOP_TONE) {
1742 resId = RES_ID_DONE;
1743 // Dismiss Tone dialog, after finishing off playing the tone.
1744 int finishActivity = (Integer) msg.obj;
1745 if (finishActivity == 1) finishToneDialogActivity();
1746 } else if (msg.arg1 == OP_STOP_TONE_USER) {
1747 resId = RES_ID_END_SESSION;
1748 }
1749
1750 sendResponse(resId, slotId, true);
1751 mServiceHandler.removeMessages(STOP_TONE_WHAT);
1752 if (mTonePlayer != null) {
1753 mTonePlayer.stop();
1754 mTonePlayer.release();
1755 mTonePlayer = null;
1756 }
1757 if (mVibrator != null) {
1758 mVibrator.cancel();
1759 mVibrator = null;
1760 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001761 }
1762
Takanori Nakano49b12722016-02-16 14:34:14 +09001763 private void launchOpenChannelDialog(final int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -07001764 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001765 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001766 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001767 return;
1768 }
1769
1770 msg.title = getResources().getString(R.string.stk_dialog_title);
1771 if (msg.text == null) {
1772 msg.text = getResources().getString(R.string.default_open_channel_msg);
1773 }
1774
1775 final AlertDialog dialog = new AlertDialog.Builder(mContext)
1776 .setIconAttribute(android.R.attr.alertDialogIcon)
1777 .setTitle(msg.title)
1778 .setMessage(msg.text)
1779 .setCancelable(false)
1780 .setPositiveButton(getResources().getString(R.string.stk_dialog_accept),
1781 new DialogInterface.OnClickListener() {
1782 public void onClick(DialogInterface dialog, int which) {
1783 Bundle args = new Bundle();
1784 args.putInt(RES_ID, RES_ID_CHOICE);
1785 args.putInt(CHOICE, YES);
1786 Message message = mServiceHandler.obtainMessage();
1787 message.arg1 = OP_RESPONSE;
Takanori Nakano49b12722016-02-16 14:34:14 +09001788 message.arg2 = slotId;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001789 message.obj = args;
1790 mServiceHandler.sendMessage(message);
1791 }
1792 })
1793 .setNegativeButton(getResources().getString(R.string.stk_dialog_reject),
1794 new DialogInterface.OnClickListener() {
1795 public void onClick(DialogInterface dialog, int which) {
1796 Bundle args = new Bundle();
1797 args.putInt(RES_ID, RES_ID_CHOICE);
1798 args.putInt(CHOICE, NO);
1799 Message message = mServiceHandler.obtainMessage();
1800 message.arg1 = OP_RESPONSE;
Takanori Nakano49b12722016-02-16 14:34:14 +09001801 message.arg2 = slotId;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001802 message.obj = args;
1803 mServiceHandler.sendMessage(message);
1804 }
1805 })
1806 .create();
1807
1808 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1809 if (!mContext.getResources().getBoolean(
1810 com.android.internal.R.bool.config_sf_slowBlur)) {
1811 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
1812 }
1813
1814 dialog.show();
1815 }
1816
Wink Savillee68857d2014-10-17 15:23:05 -07001817 private void launchTransientEventMessage(int slotId) {
1818 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001819 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001820 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001821 return;
1822 }
1823
1824 msg.title = getResources().getString(R.string.stk_dialog_title);
1825
1826 final AlertDialog dialog = new AlertDialog.Builder(mContext)
1827 .setIconAttribute(android.R.attr.alertDialogIcon)
1828 .setTitle(msg.title)
1829 .setMessage(msg.text)
1830 .setCancelable(false)
1831 .setPositiveButton(getResources().getString(android.R.string.ok),
1832 new DialogInterface.OnClickListener() {
1833 public void onClick(DialogInterface dialog, int which) {
1834 }
1835 })
1836 .create();
1837
1838 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1839 if (!mContext.getResources().getBoolean(
1840 com.android.internal.R.bool.config_sf_slowBlur)) {
1841 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
1842 }
1843
1844 dialog.show();
1845 }
1846
Wink Savillee68857d2014-10-17 15:23:05 -07001847 private int getNotificationId(int slotId) {
1848 int notifyId = STK_NOTIFICATION_ID;
1849 if (slotId >= 0 && slotId < mSimCount) {
1850 notifyId += slotId;
1851 } else {
1852 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
1853 }
1854 CatLog.d(LOG_TAG, "getNotificationId, slotId: " + slotId + ", notifyId: " + notifyId);
1855 return notifyId;
1856 }
1857
1858 private String getItemName(int itemId, int slotId) {
1859 Menu menu = mStkContext[slotId].mCurrentCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001860 if (menu == null) {
1861 return null;
1862 }
1863 for (Item item : menu.items) {
1864 if (item.id == itemId) {
1865 return item.text;
1866 }
1867 }
1868 return null;
1869 }
1870
Wink Savillee68857d2014-10-17 15:23:05 -07001871 private boolean removeMenu(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001872 try {
Wink Savillee68857d2014-10-17 15:23:05 -07001873 if (mStkContext[slotId].mCurrentMenu.items.size() == 1 &&
1874 mStkContext[slotId].mCurrentMenu.items.get(0) == null) {
1875 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001876 return true;
1877 }
1878 } catch (NullPointerException e) {
Wink Savillee68857d2014-10-17 15:23:05 -07001879 CatLog.d(LOG_TAG, "Unable to get Menu's items size");
1880 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001881 return true;
1882 }
Wink Savillee68857d2014-10-17 15:23:05 -07001883 mStkContext[slotId].mSetupMenuState = STATE_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001884 return false;
1885 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05301886
Wink Savillee68857d2014-10-17 15:23:05 -07001887 StkContext getStkContext(int slotId) {
1888 if (slotId >= 0 && slotId < mSimCount) {
1889 return mStkContext[slotId];
1890 } else {
1891 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
1892 return null;
1893 }
1894 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05301895
1896 private void handleAlphaNotify(Bundle args) {
1897 String alphaString = args.getString(AppInterface.ALPHA_STRING);
1898
1899 CatLog.d(this, "Alpha string received from card: " + alphaString);
1900 Toast toast = Toast.makeText(sInstance, alphaString, Toast.LENGTH_LONG);
1901 toast.setGravity(Gravity.TOP, 0, 0);
1902 toast.show();
1903 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001904}