blob: ea30d8010b0367fea9579082deb2f4186de35604 [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;
fionaxu2c91c752017-04-21 18:11:57 -070023import android.app.NotificationChannel;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080024import android.app.NotificationManager;
25import android.app.PendingIntent;
26import android.app.Service;
Wink Savillee68857d2014-10-17 15:23:05 -070027import android.app.Activity;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080028import android.content.Context;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050029import android.content.DialogInterface;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080030import android.content.Intent;
Preeti Ahuja95919342013-10-01 18:18:55 -070031import android.content.res.Configuration;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053032import android.content.res.Resources;
33import android.content.res.Resources.NotFoundException;
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +010034import android.graphics.Bitmap;
35import android.graphics.BitmapFactory;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080036import android.net.Uri;
37import android.os.Bundle;
38import android.os.Handler;
39import android.os.IBinder;
40import android.os.Looper;
41import android.os.Message;
Takanori Nakanoc8054ba2016-08-15 19:18:16 +090042import android.os.Parcel;
Sooraj Sasindrana4160472016-10-12 16:28:25 -070043import android.os.PersistableBundle;
Preeti Ahuja560be362014-11-25 19:38:24 -080044import android.os.PowerManager;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070045import android.os.SystemProperties;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053046import android.os.Vibrator;
Preeti Ahuja95919342013-10-01 18:18:55 -070047import android.provider.Settings;
Sooraj Sasindrana4160472016-10-12 16:28:25 -070048import android.telephony.CarrierConfigManager;
Wink Saville56469d52009-04-02 01:37:03 -070049import android.telephony.TelephonyManager;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070050import android.text.TextUtils;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080051import android.view.Gravity;
52import android.view.LayoutInflater;
53import android.view.View;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050054import android.view.WindowManager;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080055import android.widget.ImageView;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080056import android.widget.TextView;
57import android.widget.Toast;
Wink Savillee68857d2014-10-17 15:23:05 -070058import android.content.IntentFilter;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080059
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070060import com.android.internal.telephony.cat.AppInterface;
Preeti Ahuja95919342013-10-01 18:18:55 -070061import com.android.internal.telephony.cat.LaunchBrowserMode;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070062import com.android.internal.telephony.cat.Menu;
63import com.android.internal.telephony.cat.Item;
64import com.android.internal.telephony.cat.ResultCode;
65import com.android.internal.telephony.cat.CatCmdMessage;
66import com.android.internal.telephony.cat.CatCmdMessage.BrowserSettings;
Preeti Ahuja95919342013-10-01 18:18:55 -070067import com.android.internal.telephony.cat.CatCmdMessage.SetupEventListSettings;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070068import com.android.internal.telephony.cat.CatLog;
69import com.android.internal.telephony.cat.CatResponseMessage;
70import com.android.internal.telephony.cat.TextMessage;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053071import com.android.internal.telephony.cat.ToneSettings;
Wink Saville94e982b2014-07-11 07:38:14 -070072import com.android.internal.telephony.uicc.IccRefreshResponse;
Wink Savillee68857d2014-10-17 15:23:05 -070073import com.android.internal.telephony.PhoneConstants;
Preeti Ahuja95919342013-10-01 18:18:55 -070074import com.android.internal.telephony.GsmAlphabet;
Legler Wuaeefef52014-10-27 00:57:18 +080075import com.android.internal.telephony.cat.CatService;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080076
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070077import java.util.Iterator;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080078import java.util.LinkedList;
Wink Savillee68857d2014-10-17 15:23:05 -070079import java.lang.System;
80import java.util.List;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080081
Preeti Ahuja95919342013-10-01 18:18:55 -070082import static com.android.internal.telephony.cat.CatCmdMessage.
Preeti Ahuja560be362014-11-25 19:38:24 -080083 SetupEventListConstants.IDLE_SCREEN_AVAILABLE_EVENT;
84import static com.android.internal.telephony.cat.CatCmdMessage.
Preeti Ahuja95919342013-10-01 18:18:55 -070085 SetupEventListConstants.LANGUAGE_SELECTION_EVENT;
86
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080087/**
88 * SIM toolkit application level service. Interacts with Telephopny messages,
89 * application's launch and user input from STK UI elements.
Wink Saville79085fc2009-06-09 10:27:23 -070090 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080091 */
92public class StkAppService extends Service implements Runnable {
93
94 // members
Wink Savillee68857d2014-10-17 15:23:05 -070095 protected class StkContext {
96 protected CatCmdMessage mMainCmd = null;
97 protected CatCmdMessage mCurrentCmd = null;
98 protected CatCmdMessage mCurrentMenuCmd = null;
99 protected Menu mCurrentMenu = null;
100 protected String lastSelectedItem = null;
101 protected boolean mMenuIsVisible = false;
102 protected boolean mIsInputPending = false;
103 protected boolean mIsMenuPending = false;
104 protected boolean mIsDialogPending = false;
105 protected boolean responseNeeded = true;
106 protected boolean launchBrowser = false;
107 protected BrowserSettings mBrowserSettings = null;
108 protected LinkedList<DelayedCmd> mCmdsQ = null;
109 protected boolean mCmdInProgress = false;
110 protected int mStkServiceState = STATE_UNKNOWN;
111 protected int mSetupMenuState = STATE_UNKNOWN;
112 protected int mMenuState = StkMenuActivity.STATE_INIT;
113 protected int mOpCode = -1;
114 private Activity mActivityInstance = null;
115 private Activity mDialogInstance = null;
116 private Activity mMainActivityInstance = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700117 private int mSlotId = 0;
Preeti Ahuja95919342013-10-01 18:18:55 -0700118 private SetupEventListSettings mSetupEventListSettings = null;
119 private boolean mClearSelectItem = false;
120 private boolean mDisplayTextDlgIsVisibile = false;
121 private CatCmdMessage mCurrentSetupEventCmd = null;
Preeti Ahuja560be362014-11-25 19:38:24 -0800122 private CatCmdMessage mIdleModeTextCmd = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700123 final synchronized void setPendingActivityInstance(Activity act) {
124 CatLog.d(this, "setPendingActivityInstance act : " + mSlotId + ", " + act);
125 callSetActivityInstMsg(OP_SET_ACT_INST, mSlotId, act);
126 }
127 final synchronized Activity getPendingActivityInstance() {
128 CatLog.d(this, "getPendingActivityInstance act : " + mSlotId + ", " +
129 mActivityInstance);
130 return mActivityInstance;
131 }
132 final synchronized void setPendingDialogInstance(Activity act) {
133 CatLog.d(this, "setPendingDialogInstance act : " + mSlotId + ", " + act);
134 callSetActivityInstMsg(OP_SET_DAL_INST, mSlotId, act);
135 }
136 final synchronized Activity getPendingDialogInstance() {
137 CatLog.d(this, "getPendingDialogInstance act : " + mSlotId + ", " +
138 mDialogInstance);
139 return mDialogInstance;
140 }
141 final synchronized void setMainActivityInstance(Activity act) {
142 CatLog.d(this, "setMainActivityInstance act : " + mSlotId + ", " + act);
143 callSetActivityInstMsg(OP_SET_MAINACT_INST, mSlotId, act);
144 }
145 final synchronized Activity getMainActivityInstance() {
146 CatLog.d(this, "getMainActivityInstance act : " + mSlotId + ", " +
147 mMainActivityInstance);
148 return mMainActivityInstance;
149 }
150 }
151
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800152 private volatile Looper mServiceLooper;
153 private volatile ServiceHandler mServiceHandler;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800154 private Context mContext = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800155 private NotificationManager mNotificationManager = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800156 static StkAppService sInstance = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700157 private AppInterface[] mStkService = null;
158 private StkContext[] mStkContext = null;
159 private int mSimCount = 0;
Preeti Ahuja560be362014-11-25 19:38:24 -0800160 private PowerManager mPowerManager = null;
161 private StkCmdReceiver mStkCmdReceiver = null;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530162 private TonePlayer mTonePlayer = null;
163 private Vibrator mVibrator = null;
Preeti Ahuja95919342013-10-01 18:18:55 -0700164
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800165 // Used for setting FLAG_ACTIVITY_NO_USER_ACTION when
166 // creating an intent.
167 private enum InitiatedByUserAction {
168 yes, // The action was started via a user initiated action
169 unknown, // Not known for sure if user initated the action
170 }
171
172 // constants
173 static final String OPCODE = "op";
174 static final String CMD_MSG = "cmd message";
175 static final String RES_ID = "response id";
176 static final String MENU_SELECTION = "menu selection";
177 static final String INPUT = "input";
178 static final String HELP = "help";
179 static final String CONFIRMATION = "confirm";
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500180 static final String CHOICE = "choice";
Wink Savillee68857d2014-10-17 15:23:05 -0700181 static final String SLOT_ID = "SLOT_ID";
182 static final String STK_CMD = "STK CMD";
183 static final String STK_DIALOG_URI = "stk://com.android.stk/dialog/";
184 static final String STK_MENU_URI = "stk://com.android.stk/menu/";
185 static final String STK_INPUT_URI = "stk://com.android.stk/input/";
186 static final String STK_TONE_URI = "stk://com.android.stk/tone/";
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530187 static final String FINISH_TONE_ACTIVITY_ACTION =
188 "android.intent.action.stk.finish_activity";
Preeti Ahuja95919342013-10-01 18:18:55 -0700189
190 // These below constants are used for SETUP_EVENT_LIST
191 static final String SETUP_EVENT_TYPE = "event";
192 static final String SETUP_EVENT_CAUSE = "cause";
193
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800194 // operations ids for different service functionality.
195 static final int OP_CMD = 1;
196 static final int OP_RESPONSE = 2;
197 static final int OP_LAUNCH_APP = 3;
198 static final int OP_END_SESSION = 4;
199 static final int OP_BOOT_COMPLETED = 5;
200 private static final int OP_DELAYED_MSG = 6;
Wink Saville94e982b2014-07-11 07:38:14 -0700201 static final int OP_CARD_STATUS_CHANGED = 7;
Wink Savillee68857d2014-10-17 15:23:05 -0700202 static final int OP_SET_ACT_INST = 8;
203 static final int OP_SET_DAL_INST = 9;
204 static final int OP_SET_MAINACT_INST = 10;
Preeti Ahujab3d0e612014-11-20 13:29:25 -0800205 static final int OP_LOCALE_CHANGED = 11;
206 static final int OP_ALPHA_NOTIFY = 12;
Preeti Ahuja560be362014-11-25 19:38:24 -0800207 static final int OP_IDLE_SCREEN = 13;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800208
Preeti Ahuja95919342013-10-01 18:18:55 -0700209 //Invalid SetupEvent
210 static final int INVALID_SETUP_EVENT = 0xFF;
211
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530212 // Message id to signal stop tone due to play tone timeout.
213 private static final int OP_STOP_TONE = 16;
214
215 // Message id to signal stop tone on user keyback.
216 static final int OP_STOP_TONE_USER = 17;
217
218 // Message id to remove stop tone message from queue.
219 private static final int STOP_TONE_WHAT = 100;
220
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800221 // Response ids
222 static final int RES_ID_MENU_SELECTION = 11;
223 static final int RES_ID_INPUT = 12;
224 static final int RES_ID_CONFIRM = 13;
225 static final int RES_ID_DONE = 14;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500226 static final int RES_ID_CHOICE = 15;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800227
228 static final int RES_ID_TIMEOUT = 20;
229 static final int RES_ID_BACKWARD = 21;
230 static final int RES_ID_END_SESSION = 22;
231 static final int RES_ID_EXIT = 23;
Srikanth Chintalaba103002015-11-30 10:49:52 -0800232 static final int RES_ID_ERROR = 24;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800233
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500234 static final int YES = 1;
235 static final int NO = 0;
236
Wink Savillee68857d2014-10-17 15:23:05 -0700237 static final int STATE_UNKNOWN = -1;
238 static final int STATE_NOT_EXIST = 0;
239 static final int STATE_EXIST = 1;
Wink Saville79085fc2009-06-09 10:27:23 -0700240
Wink Savillee68857d2014-10-17 15:23:05 -0700241 private static final String PACKAGE_NAME = "com.android.stk";
242 private static final String STK_MENU_ACTIVITY_NAME = PACKAGE_NAME + ".StkMenuActivity";
243 private static final String STK_INPUT_ACTIVITY_NAME = PACKAGE_NAME + ".StkInputActivity";
244 private static final String STK_DIALOG_ACTIVITY_NAME = PACKAGE_NAME + ".StkDialogActivity";
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800245 // Notification id used to display Idle Mode text in NotificationManager.
246 private static final int STK_NOTIFICATION_ID = 333;
fionaxu2c91c752017-04-21 18:11:57 -0700247 // Notification channel containing all mobile service messages notifications.
248 private static final String STK_NOTIFICATION_CHANNEL_ID = "mobileServiceMessages";
249
Wink Savillee68857d2014-10-17 15:23:05 -0700250 private static final String LOG_TAG = new Object(){}.getClass().getEnclosingClass().getName();
Wink Saville79085fc2009-06-09 10:27:23 -0700251
252 // Inner class used for queuing telephony messages (proactive commands,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800253 // session end) while the service is busy processing a previous message.
254 private class DelayedCmd {
255 // members
256 int id;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700257 CatCmdMessage msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700258 int slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800259
Wink Savillee68857d2014-10-17 15:23:05 -0700260 DelayedCmd(int id, CatCmdMessage msg, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800261 this.id = id;
262 this.msg = msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700263 this.slotId = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800264 }
265 }
266
Preeti Ahujaa7cdca22013-10-01 18:20:56 -0700267 // system property to set the STK specific default url for launch browser proactive cmds
268 private static final String STK_BROWSER_DEFAULT_URL_SYSPROP = "persist.radio.stk.default_url";
269
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800270 @Override
271 public void onCreate() {
Wink Savillee68857d2014-10-17 15:23:05 -0700272 CatLog.d(LOG_TAG, "onCreate()+");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800273 // Initialize members
Wink Savillee68857d2014-10-17 15:23:05 -0700274 int i = 0;
275 mContext = getBaseContext();
276 mSimCount = TelephonyManager.from(mContext).getSimCount();
277 CatLog.d(LOG_TAG, "simCount: " + mSimCount);
278 mStkService = new AppInterface[mSimCount];
279 mStkContext = new StkContext[mSimCount];
Preeti Ahuja560be362014-11-25 19:38:24 -0800280 mPowerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
281 mStkCmdReceiver = new StkCmdReceiver();
282 registerReceiver(mStkCmdReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
Wink Savillee68857d2014-10-17 15:23:05 -0700283 for (i = 0; i < mSimCount; i++) {
284 CatLog.d(LOG_TAG, "slotId: " + i);
Legler Wuaeefef52014-10-27 00:57:18 +0800285 mStkService[i] = CatService.getInstance(i);
Wink Savillee68857d2014-10-17 15:23:05 -0700286 mStkContext[i] = new StkContext();
287 mStkContext[i].mSlotId = i;
288 mStkContext[i].mCmdsQ = new LinkedList<DelayedCmd>();
289 }
290
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800291 Thread serviceThread = new Thread(null, this, "Stk App Service");
292 serviceThread.start();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800293 mNotificationManager = (NotificationManager) mContext
294 .getSystemService(Context.NOTIFICATION_SERVICE);
295 sInstance = this;
296 }
297
298 @Override
299 public void onStart(Intent intent, int startId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700300 if (intent == null) {
301 CatLog.d(LOG_TAG, "StkAppService onStart intent is null so return");
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530302 return;
303 }
304
Wink Savillee68857d2014-10-17 15:23:05 -0700305 Bundle args = intent.getExtras();
306 if (args == null) {
307 CatLog.d(LOG_TAG, "StkAppService onStart args is null so return");
308 return;
309 }
310
311 int op = args.getInt(OPCODE);
312 int slotId = 0;
313 int i = 0;
314 if (op != OP_BOOT_COMPLETED) {
315 slotId = args.getInt(SLOT_ID);
316 }
Cuihtlauac ALVARADObde7f032015-05-29 16:25:12 +0200317 CatLog.d(LOG_TAG, "onStart sim id: " + slotId + ", op: " + op + ", *****");
Wink Savillee68857d2014-10-17 15:23:05 -0700318 if ((slotId >= 0 && slotId < mSimCount) && mStkService[slotId] == null) {
Legler Wuaeefef52014-10-27 00:57:18 +0800319 mStkService[slotId] = CatService.getInstance(slotId);
Wink Savillee68857d2014-10-17 15:23:05 -0700320 if (mStkService[slotId] == null) {
321 CatLog.d(LOG_TAG, "mStkService is: " + mStkContext[slotId].mStkServiceState);
322 mStkContext[slotId].mStkServiceState = STATE_NOT_EXIST;
323 //Check other StkService state.
324 //If all StkServices are not available, stop itself and uninstall apk.
325 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
326 if (i != slotId
Tsukasa Goto029332b2016-10-05 17:12:06 +0900327 && (mStkService[i] != null)
Wink Savillee68857d2014-10-17 15:23:05 -0700328 && (mStkContext[i].mStkServiceState == STATE_UNKNOWN
329 || mStkContext[i].mStkServiceState == STATE_EXIST)) {
330 break;
331 }
332 }
333 } else {
334 mStkContext[slotId].mStkServiceState = STATE_EXIST;
335 }
336 if (i == mSimCount) {
337 stopSelf();
338 StkAppInstaller.unInstall(mContext);
339 return;
340 }
341 }
342
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530343 waitForLooper();
John Wang62acae42009-10-08 11:20:23 -0700344
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800345 Message msg = mServiceHandler.obtainMessage();
Wink Savillee68857d2014-10-17 15:23:05 -0700346 msg.arg1 = op;
347 msg.arg2 = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800348 switch(msg.arg1) {
349 case OP_CMD:
350 msg.obj = args.getParcelable(CMD_MSG);
351 break;
352 case OP_RESPONSE:
Wink Saville94e982b2014-07-11 07:38:14 -0700353 case OP_CARD_STATUS_CHANGED:
Preeti Ahuja95919342013-10-01 18:18:55 -0700354 case OP_LOCALE_CHANGED:
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530355 case OP_ALPHA_NOTIFY:
Preeti Ahuja560be362014-11-25 19:38:24 -0800356 case OP_IDLE_SCREEN:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800357 msg.obj = args;
358 /* falls through */
359 case OP_LAUNCH_APP:
360 case OP_END_SESSION:
361 case OP_BOOT_COMPLETED:
362 break;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530363 case OP_STOP_TONE_USER:
364 msg.obj = args;
365 msg.what = STOP_TONE_WHAT;
366 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800367 default:
368 return;
369 }
370 mServiceHandler.sendMessage(msg);
371 }
372
373 @Override
374 public void onDestroy() {
Wink Savillee68857d2014-10-17 15:23:05 -0700375 CatLog.d(LOG_TAG, "onDestroy()");
Preeti Ahuja560be362014-11-25 19:38:24 -0800376 if (mStkCmdReceiver != null) {
377 unregisterReceiver(mStkCmdReceiver);
378 mStkCmdReceiver = null;
379 }
380 mPowerManager = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800381 waitForLooper();
382 mServiceLooper.quit();
383 }
384
385 @Override
386 public IBinder onBind(Intent intent) {
387 return null;
388 }
389
390 public void run() {
391 Looper.prepare();
392
393 mServiceLooper = Looper.myLooper();
394 mServiceHandler = new ServiceHandler();
395
396 Looper.loop();
397 }
398
399 /*
400 * Package api used by StkMenuActivity to indicate if its on the foreground.
401 */
Wink Savillee68857d2014-10-17 15:23:05 -0700402 void indicateMenuVisibility(boolean visibility, int slotId) {
403 if (slotId >= 0 && slotId < mSimCount) {
404 mStkContext[slotId].mMenuIsVisible = visibility;
405 }
406 }
407
Preeti Ahuja95919342013-10-01 18:18:55 -0700408 /*
409 * Package api used by StkDialogActivity to indicate if its on the foreground.
410 */
411 void setDisplayTextDlgVisibility(boolean visibility, int slotId) {
412 if (slotId >= 0 && slotId < mSimCount) {
413 mStkContext[slotId].mDisplayTextDlgIsVisibile = visibility;
414 }
415 }
416
Wink Savillee68857d2014-10-17 15:23:05 -0700417 boolean isInputPending(int slotId) {
418 if (slotId >= 0 && slotId < mSimCount) {
419 CatLog.d(LOG_TAG, "isInputFinishBySrv: " + mStkContext[slotId].mIsInputPending);
420 return mStkContext[slotId].mIsInputPending;
421 }
422 return false;
423 }
424
425 boolean isMenuPending(int slotId) {
426 if (slotId >= 0 && slotId < mSimCount) {
427 CatLog.d(LOG_TAG, "isMenuPending: " + mStkContext[slotId].mIsMenuPending);
428 return mStkContext[slotId].mIsMenuPending;
429 }
430 return false;
431 }
432
433 boolean isDialogPending(int slotId) {
434 if (slotId >= 0 && slotId < mSimCount) {
435 CatLog.d(LOG_TAG, "isDialogPending: " + mStkContext[slotId].mIsDialogPending);
436 return mStkContext[slotId].mIsDialogPending;
437 }
438 return false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800439 }
440
441 /*
442 * Package api used by StkMenuActivity to get its Menu parameter.
443 */
Wink Savillee68857d2014-10-17 15:23:05 -0700444 Menu getMenu(int slotId) {
445 CatLog.d(LOG_TAG, "StkAppService, getMenu, sim id: " + slotId);
446 if (slotId >=0 && slotId < mSimCount) {
447 return mStkContext[slotId].mCurrentMenu;
448 } else {
449 return null;
450 }
451 }
452
453 /*
454 * Package api used by StkMenuActivity to get its Main Menu parameter.
455 */
456 Menu getMainMenu(int slotId) {
457 CatLog.d(LOG_TAG, "StkAppService, getMainMenu, sim id: " + slotId);
w30234a08cffe2015-02-04 15:13:25 -0800458 if (slotId >=0 && slotId < mSimCount && (mStkContext[slotId].mMainCmd != null)) {
Takanori Nakanoc8054ba2016-08-15 19:18:16 +0900459 Menu menu = mStkContext[slotId].mMainCmd.getMenu();
460 if (menu != null && mSimCount > PhoneConstants.MAX_PHONE_COUNT_SINGLE_SIM) {
461 // If alpha identifier or icon identifier with the self-explanatory qualifier is
462 // specified in SET-UP MENU command, it should be more prioritized than preset ones.
463 if (menu.title == null
464 && (menu.titleIcon == null || !menu.titleIconSelfExplanatory)) {
465 StkMenuConfig config = StkMenuConfig.getInstance(getApplicationContext());
466 String label = config.getLabel(slotId);
467 Bitmap icon = config.getIcon(slotId);
468 if (label != null || icon != null) {
469 Parcel parcel = Parcel.obtain();
470 menu.writeToParcel(parcel, 0);
471 parcel.setDataPosition(0);
472 menu = Menu.CREATOR.createFromParcel(parcel);
473 parcel.recycle();
474 menu.title = label;
475 menu.titleIcon = icon;
476 menu.titleIconSelfExplanatory = false;
477 }
478 }
479 }
480 return menu;
Wink Savillee68857d2014-10-17 15:23:05 -0700481 } else {
482 return null;
483 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800484 }
485
486 /*
487 * Package api used by UI Activities and Dialogs to communicate directly
488 * with the service to deliver state information and parameters.
489 */
490 static StkAppService getInstance() {
491 return sInstance;
492 }
493
494 private void waitForLooper() {
495 while (mServiceHandler == null) {
496 synchronized (this) {
497 try {
498 wait(100);
499 } catch (InterruptedException e) {
500 }
501 }
502 }
503 }
504
505 private final class ServiceHandler extends Handler {
506 @Override
507 public void handleMessage(Message msg) {
Wink Savillee68857d2014-10-17 15:23:05 -0700508 if(null == msg) {
509 CatLog.d(LOG_TAG, "ServiceHandler handleMessage msg is null");
510 return;
511 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800512 int opcode = msg.arg1;
Wink Savillee68857d2014-10-17 15:23:05 -0700513 int slotId = msg.arg2;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800514
Wink Savillee68857d2014-10-17 15:23:05 -0700515 CatLog.d(LOG_TAG, "handleMessage opcode[" + opcode + "], sim id[" + slotId + "]");
516 if (opcode == OP_CMD && msg.obj != null &&
517 ((CatCmdMessage)msg.obj).getCmdType()!= null) {
518 CatLog.d(LOG_TAG, "cmdName[" + ((CatCmdMessage)msg.obj).getCmdType().name() + "]");
519 }
520 mStkContext[slotId].mOpCode = opcode;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800521 switch (opcode) {
522 case OP_LAUNCH_APP:
Wink Savillee68857d2014-10-17 15:23:05 -0700523 if (mStkContext[slotId].mMainCmd == null) {
524 CatLog.d(LOG_TAG, "mMainCmd is null");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800525 // nothing todo when no SET UP MENU command didn't arrive.
526 return;
527 }
Wink Savillee68857d2014-10-17 15:23:05 -0700528 CatLog.d(LOG_TAG, "handleMessage OP_LAUNCH_APP - mCmdInProgress[" +
529 mStkContext[slotId].mCmdInProgress + "]");
530
531 //If there is a pending activity for the slot id,
532 //just finish it and create a new one to handle the pending command.
533 cleanUpInstanceStackBySlot(slotId);
534
Wink Savillee68857d2014-10-17 15:23:05 -0700535 CatLog.d(LOG_TAG, "Current cmd type: " +
536 mStkContext[slotId].mCurrentCmd.getCmdType());
537 //Restore the last command from stack by slot id.
538 restoreInstanceFromStackBySlot(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800539 break;
540 case OP_CMD:
Wink Savillee68857d2014-10-17 15:23:05 -0700541 CatLog.d(LOG_TAG, "[OP_CMD]");
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700542 CatCmdMessage cmdMsg = (CatCmdMessage) msg.obj;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800543 // There are two types of commands:
544 // 1. Interactive - user's response is required.
545 // 2. Informative - display a message, no interaction with the user.
546 //
Wink Saville79085fc2009-06-09 10:27:23 -0700547 // Informative commands can be handled immediately without any delay.
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800548 // Interactive commands can't override each other. So if a command
549 // is already in progress, we need to queue the next command until
550 // the user has responded or a timeout expired.
551 if (!isCmdInteractive(cmdMsg)) {
Wink Savillee68857d2014-10-17 15:23:05 -0700552 handleCmd(cmdMsg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800553 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700554 if (!mStkContext[slotId].mCmdInProgress) {
555 mStkContext[slotId].mCmdInProgress = true;
556 handleCmd((CatCmdMessage) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800557 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700558 CatLog.d(LOG_TAG, "[Interactive][in progress]");
559 mStkContext[slotId].mCmdsQ.addLast(new DelayedCmd(OP_CMD,
560 (CatCmdMessage) msg.obj, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800561 }
562 }
563 break;
564 case OP_RESPONSE:
Preeti Ahuja414bc412013-06-25 19:31:49 -0700565 handleCmdResponse((Bundle) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800566 // call delayed commands if needed.
Wink Savillee68857d2014-10-17 15:23:05 -0700567 if (mStkContext[slotId].mCmdsQ.size() != 0) {
568 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800569 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700570 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800571 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800572 break;
573 case OP_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -0700574 if (!mStkContext[slotId].mCmdInProgress) {
575 mStkContext[slotId].mCmdInProgress = true;
576 handleSessionEnd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800577 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700578 mStkContext[slotId].mCmdsQ.addLast(
579 new DelayedCmd(OP_END_SESSION, null, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800580 }
581 break;
582 case OP_BOOT_COMPLETED:
Wink Savillee68857d2014-10-17 15:23:05 -0700583 CatLog.d(LOG_TAG, " OP_BOOT_COMPLETED");
584 int i = 0;
585 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
586 if (mStkContext[i].mMainCmd != null) {
587 break;
588 }
589 }
590 if (i == mSimCount) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800591 StkAppInstaller.unInstall(mContext);
592 }
593 break;
594 case OP_DELAYED_MSG:
Wink Savillee68857d2014-10-17 15:23:05 -0700595 handleDelayedCmd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800596 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700597 case OP_CARD_STATUS_CHANGED:
Wink Savillee68857d2014-10-17 15:23:05 -0700598 CatLog.d(LOG_TAG, "Card/Icc Status change received");
599 handleCardStatusChangeAndIccRefresh((Bundle) msg.obj, slotId);
600 break;
601 case OP_SET_ACT_INST:
Yoshiaki Naka28d7a722017-10-24 17:32:16 +0900602 Activity act = (Activity) msg.obj;
603 if (mStkContext[slotId].mActivityInstance != act) {
604 CatLog.d(LOG_TAG, "Set activity instance - " + act);
605 Activity previous = mStkContext[slotId].mActivityInstance;
606 mStkContext[slotId].mActivityInstance = act;
607 // Finish the previous one if it has not been finished yet somehow.
608 if (previous != null && !previous.isDestroyed() && !previous.isFinishing()) {
609 CatLog.d(LOG_TAG, "Finish the previous pending activity - " + previous);
610 previous.finish();
611 }
612 }
Wink Savillee68857d2014-10-17 15:23:05 -0700613 break;
614 case OP_SET_DAL_INST:
615 Activity dal = new Activity();
616 CatLog.d(LOG_TAG, "Set dialog instance. " + dal);
617 dal = (Activity) msg.obj;
618 mStkContext[slotId].mDialogInstance = dal;
619 break;
620 case OP_SET_MAINACT_INST:
621 Activity mainAct = new Activity();
622 mainAct = (Activity) msg.obj;
623 CatLog.d(LOG_TAG, "Set activity instance. " + mainAct);
624 mStkContext[slotId].mMainActivityInstance = mainAct;
Wink Saville94e982b2014-07-11 07:38:14 -0700625 break;
Preeti Ahuja95919342013-10-01 18:18:55 -0700626 case OP_LOCALE_CHANGED:
627 CatLog.d(this, "Locale Changed");
Yuta Ui1481b172016-02-03 15:34:31 +0900628 for (int slot = PhoneConstants.SIM_ID_1; slot < mSimCount; slot++) {
629 checkForSetupEvent(LANGUAGE_SELECTION_EVENT, (Bundle) msg.obj, slot);
630 }
fionaxu805eb572017-05-02 10:57:30 -0700631 // rename all registered notification channels on locale change
632 createAllChannels();
Preeti Ahuja95919342013-10-01 18:18:55 -0700633 break;
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530634 case OP_ALPHA_NOTIFY:
635 handleAlphaNotify((Bundle) msg.obj);
636 break;
Preeti Ahuja560be362014-11-25 19:38:24 -0800637 case OP_IDLE_SCREEN:
638 for (int slot = 0; slot < mSimCount; slot++) {
639 if (mStkContext[slot] != null) {
640 handleIdleScreen(slot);
641 }
642 }
643 break;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530644 case OP_STOP_TONE_USER:
645 case OP_STOP_TONE:
646 CatLog.d(this, "Stop tone");
647 handleStopTone(msg, slotId);
648 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700649 }
650 }
651
Wink Savillee68857d2014-10-17 15:23:05 -0700652 private void handleCardStatusChangeAndIccRefresh(Bundle args, int slotId) {
Wink Saville94e982b2014-07-11 07:38:14 -0700653 boolean cardStatus = args.getBoolean(AppInterface.CARD_STATUS);
654
Wink Savillee68857d2014-10-17 15:23:05 -0700655 CatLog.d(LOG_TAG, "CardStatus: " + cardStatus);
Wink Saville94e982b2014-07-11 07:38:14 -0700656 if (cardStatus == false) {
Wink Savillee68857d2014-10-17 15:23:05 -0700657 CatLog.d(LOG_TAG, "CARD is ABSENT");
Wink Saville94e982b2014-07-11 07:38:14 -0700658 // Uninstall STKAPP, Clear Idle text, Stop StkAppService
Wink Savillee68857d2014-10-17 15:23:05 -0700659 mNotificationManager.cancel(getNotificationId(slotId));
Srikanth Chintala7c5a04c2016-09-22 19:05:01 +0530660 mStkContext[slotId].mCurrentMenu = null;
661 mStkContext[slotId].mMainCmd = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700662 if (isAllOtherCardsAbsent(slotId)) {
663 CatLog.d(LOG_TAG, "All CARDs are ABSENT");
664 StkAppInstaller.unInstall(mContext);
665 stopSelf();
666 }
Wink Saville94e982b2014-07-11 07:38:14 -0700667 } else {
668 IccRefreshResponse state = new IccRefreshResponse();
669 state.refreshResult = args.getInt(AppInterface.REFRESH_RESULT);
670
Wink Savillee68857d2014-10-17 15:23:05 -0700671 CatLog.d(LOG_TAG, "Icc Refresh Result: "+ state.refreshResult);
Wink Saville94e982b2014-07-11 07:38:14 -0700672 if ((state.refreshResult == IccRefreshResponse.REFRESH_RESULT_INIT) ||
673 (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET)) {
674 // Clear Idle Text
Wink Savillee68857d2014-10-17 15:23:05 -0700675 mNotificationManager.cancel(getNotificationId(slotId));
Wink Saville94e982b2014-07-11 07:38:14 -0700676 }
677
678 if (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET) {
679 // Uninstall STkmenu
Wink Savillee68857d2014-10-17 15:23:05 -0700680 if (isAllOtherCardsAbsent(slotId)) {
681 StkAppInstaller.unInstall(mContext);
682 }
683 mStkContext[slotId].mCurrentMenu = null;
684 mStkContext[slotId].mMainCmd = null;
Wink Saville94e982b2014-07-11 07:38:14 -0700685 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800686 }
687 }
688 }
Wink Savillee68857d2014-10-17 15:23:05 -0700689 /*
690 * Check if all SIMs are absent except the id of slot equals "slotId".
691 */
692 private boolean isAllOtherCardsAbsent(int slotId) {
693 TelephonyManager mTm = (TelephonyManager) mContext.getSystemService(
694 Context.TELEPHONY_SERVICE);
695 int i = 0;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800696
Wink Savillee68857d2014-10-17 15:23:05 -0700697 for (i = 0; i < mSimCount; i++) {
698 if (i != slotId && mTm.hasIccCard(i)) {
699 break;
700 }
701 }
702 if (i == mSimCount) {
703 return true;
704 } else {
705 return false;
706 }
707 }
Preeti Ahuja95919342013-10-01 18:18:55 -0700708
Preeti Ahuja560be362014-11-25 19:38:24 -0800709 /*
710 * If the device is not in an interactive state, we can assume
711 * that the screen is idle.
712 */
713 private boolean isScreenIdle() {
714 return (!mPowerManager.isInteractive());
715 }
716
717 private void handleIdleScreen(int slotId) {
718
719 // If the idle screen event is present in the list need to send the
720 // response to SIM.
721 CatLog.d(this, "Need to send IDLE SCREEN Available event to SIM");
722 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId);
723
724 if (mStkContext[slotId].mIdleModeTextCmd != null) {
725 launchIdleText(slotId);
726 }
727 }
728
729 private void sendScreenBusyResponse(int slotId) {
730 if (mStkContext[slotId].mCurrentCmd == null) {
731 return;
732 }
733 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
734 CatLog.d(this, "SCREEN_BUSY");
735 resMsg.setResultCode(ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS);
736 mStkService[slotId].onCmdResponse(resMsg);
737 if (mStkContext[slotId].mCmdsQ.size() != 0) {
738 callDelayedMsg(slotId);
739 } else {
740 mStkContext[slotId].mCmdInProgress = false;
741 }
742 }
743
Preeti Ahuja95919342013-10-01 18:18:55 -0700744 private void sendResponse(int resId, int slotId, boolean confirm) {
745 Message msg = mServiceHandler.obtainMessage();
746 msg.arg1 = OP_RESPONSE;
Takanori Nakano49b12722016-02-16 14:34:14 +0900747 msg.arg2 = slotId;
Preeti Ahuja95919342013-10-01 18:18:55 -0700748 Bundle args = new Bundle();
749 args.putInt(StkAppService.RES_ID, resId);
Preeti Ahuja95919342013-10-01 18:18:55 -0700750 args.putBoolean(StkAppService.CONFIRMATION, confirm);
751 msg.obj = args;
752 mServiceHandler.sendMessage(msg);
753 }
754
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700755 private boolean isCmdInteractive(CatCmdMessage cmd) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800756 switch (cmd.getCmdType()) {
757 case SEND_DTMF:
758 case SEND_SMS:
759 case SEND_SS:
760 case SEND_USSD:
761 case SET_UP_IDLE_MODE_TEXT:
762 case SET_UP_MENU:
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500763 case CLOSE_CHANNEL:
764 case RECEIVE_DATA:
765 case SEND_DATA:
Preeti Ahuja95919342013-10-01 18:18:55 -0700766 case SET_UP_EVENT_LIST:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800767 return false;
768 }
769
770 return true;
771 }
772
Wink Savillee68857d2014-10-17 15:23:05 -0700773 private void handleDelayedCmd(int slotId) {
774 CatLog.d(LOG_TAG, "handleDelayedCmd, slotId: " + slotId);
775 if (mStkContext[slotId].mCmdsQ.size() != 0) {
776 DelayedCmd cmd = mStkContext[slotId].mCmdsQ.poll();
777 if (cmd != null) {
778 CatLog.d(LOG_TAG, "handleDelayedCmd - queue size: " +
779 mStkContext[slotId].mCmdsQ.size() +
780 " id: " + cmd.id + "sim id: " + cmd.slotId);
781 switch (cmd.id) {
782 case OP_CMD:
783 handleCmd(cmd.msg, cmd.slotId);
784 break;
785 case OP_END_SESSION:
786 handleSessionEnd(cmd.slotId);
787 break;
788 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800789 }
790 }
791 }
792
Wink Savillee68857d2014-10-17 15:23:05 -0700793 private void callDelayedMsg(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800794 Message msg = mServiceHandler.obtainMessage();
795 msg.arg1 = OP_DELAYED_MSG;
Wink Savillee68857d2014-10-17 15:23:05 -0700796 msg.arg2 = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800797 mServiceHandler.sendMessage(msg);
798 }
799
Wink Savillee68857d2014-10-17 15:23:05 -0700800 private void callSetActivityInstMsg(int inst_type, int slotId, Object obj) {
801 Message msg = mServiceHandler.obtainMessage();
802 msg.obj = obj;
803 msg.arg1 = inst_type;
804 msg.arg2 = slotId;
805 mServiceHandler.sendMessage(msg);
806 }
807
808 private void handleSessionEnd(int slotId) {
Legler Wuaeefef52014-10-27 00:57:18 +0800809 // We should finish all pending activity if receiving END SESSION command.
810 cleanUpInstanceStackBySlot(slotId);
811
Wink Savillee68857d2014-10-17 15:23:05 -0700812 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
813 CatLog.d(LOG_TAG, "[handleSessionEnd] - mCurrentCmd changed to mMainCmd!.");
814 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mMainCmd;
815 CatLog.d(LOG_TAG, "slotId: " + slotId + ", mMenuState: " +
816 mStkContext[slotId].mMenuState);
817
818 mStkContext[slotId].mIsInputPending = false;
819 mStkContext[slotId].mIsMenuPending = false;
820 mStkContext[slotId].mIsDialogPending = false;
821
Wink Savillee68857d2014-10-17 15:23:05 -0700822 if (mStkContext[slotId].mMainCmd == null) {
823 CatLog.d(LOG_TAG, "[handleSessionEnd][mMainCmd is null!]");
824 }
825 mStkContext[slotId].lastSelectedItem = null;
Wink Saville79085fc2009-06-09 10:27:23 -0700826 // In case of SET UP MENU command which removed the app, don't
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800827 // update the current menu member.
Wink Savillee68857d2014-10-17 15:23:05 -0700828 if (mStkContext[slotId].mCurrentMenu != null && mStkContext[slotId].mMainCmd != null) {
829 mStkContext[slotId].mCurrentMenu = mStkContext[slotId].mMainCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800830 }
Wink Savillee68857d2014-10-17 15:23:05 -0700831 CatLog.d(LOG_TAG, "[handleSessionEnd][mMenuState]" + mStkContext[slotId].mMenuIsVisible);
832 // In mutiple instance architecture, the main menu for slotId will be finished when user
833 // goes to the Stk menu of the other SIM. So, we should launch a new instance for the
834 // main menu if the main menu instance has been finished.
835 // If the current menu is secondary menu, we should launch main menu.
836 if (StkMenuActivity.STATE_SECONDARY == mStkContext[slotId].mMenuState) {
837 launchMenuActivity(null, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800838 }
Wink Savillee68857d2014-10-17 15:23:05 -0700839 if (mStkContext[slotId].mCmdsQ.size() != 0) {
840 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800841 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700842 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800843 }
844 // In case a launch browser command was just confirmed, launch that url.
Wink Savillee68857d2014-10-17 15:23:05 -0700845 if (mStkContext[slotId].launchBrowser) {
846 mStkContext[slotId].launchBrowser = false;
847 launchBrowser(mStkContext[slotId].mBrowserSettings);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800848 }
849 }
850
Preeti Ahuja560be362014-11-25 19:38:24 -0800851 // returns true if any Stk related activity already has focus on the screen
Yoshiaki Nakacec55b82017-10-20 15:53:43 +0900852 boolean isTopOfStack() {
pkanwareab12f32017-02-06 08:35:03 -0800853 ActivityManager mActivityManager = (ActivityManager) mContext
Preeti Ahuja560be362014-11-25 19:38:24 -0800854 .getSystemService(ACTIVITY_SERVICE);
pkanwareab12f32017-02-06 08:35:03 -0800855 String currentPackageName = null;
856 List<RunningTaskInfo> tasks = mActivityManager.getRunningTasks(1);
857 if (tasks == null || tasks.get(0).topActivity == null) {
858 return false;
859 }
860 currentPackageName = tasks.get(0).topActivity.getPackageName();
Preeti Ahuja560be362014-11-25 19:38:24 -0800861 if (null != currentPackageName) {
862 return currentPackageName.equals(PACKAGE_NAME);
863 }
Preeti Ahuja560be362014-11-25 19:38:24 -0800864 return false;
865 }
866
Sooraj Sasindrana4160472016-10-12 16:28:25 -0700867 /**
868 * Get the boolean config from carrier config manager.
869 *
870 * @param context the context to get carrier service
871 * @param key config key defined in CarrierConfigManager
872 * @return boolean value of corresponding key.
873 */
874 private static boolean getBooleanCarrierConfig(Context context, String key) {
875 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(
876 Context.CARRIER_CONFIG_SERVICE);
877 PersistableBundle b = null;
878 if (configManager != null) {
879 b = configManager.getConfig();
880 }
881 if (b != null) {
882 return b.getBoolean(key);
883 } else {
884 // Return static default defined in CarrierConfigManager.
885 return CarrierConfigManager.getDefaultConfig().getBoolean(key);
886 }
887 }
888
Wink Savillee68857d2014-10-17 15:23:05 -0700889 private void handleCmd(CatCmdMessage cmdMsg, int slotId) {
Preeti Ahuja95919342013-10-01 18:18:55 -0700890
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800891 if (cmdMsg == null) {
892 return;
893 }
894 // save local reference for state tracking.
Wink Savillee68857d2014-10-17 15:23:05 -0700895 mStkContext[slotId].mCurrentCmd = cmdMsg;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800896 boolean waitForUsersResponse = true;
897
Wink Savillee68857d2014-10-17 15:23:05 -0700898 mStkContext[slotId].mIsInputPending = false;
899 mStkContext[slotId].mIsMenuPending = false;
900 mStkContext[slotId].mIsDialogPending = false;
901
902 CatLog.d(LOG_TAG,"[handleCmd]" + cmdMsg.getCmdType().name());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800903 switch (cmdMsg.getCmdType()) {
904 case DISPLAY_TEXT:
905 TextMessage msg = cmdMsg.geTextMessage();
Jeevaka Badrappan854a25c2012-12-01 16:32:03 +0200906 waitForUsersResponse = msg.responseNeeded;
Wink Savillee68857d2014-10-17 15:23:05 -0700907 if (mStkContext[slotId].lastSelectedItem != null) {
908 msg.title = mStkContext[slotId].lastSelectedItem;
909 } else if (mStkContext[slotId].mMainCmd != null){
Yoshiaki Naka28313ba2017-08-04 12:20:53 +0900910 if (!getResources().getBoolean(R.bool.show_menu_title_only_on_menu)) {
911 msg.title = mStkContext[slotId].mMainCmd.getMenu().title;
912 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800913 }
Preeti Ahuja560be362014-11-25 19:38:24 -0800914 //If we receive a low priority Display Text and the device is
915 // not displaying any STK related activity and the screen is not idle
916 // ( that is, device is in an interactive state), then send a screen busy
917 // terminal response. Otherwise display the message. The existing
918 // displayed message shall be updated with the new display text
919 // proactive command (Refer to ETSI TS 102 384 section 27.22.4.1.4.4.2).
920 if (!(msg.isHighPriority || mStkContext[slotId].mMenuIsVisible
921 || mStkContext[slotId].mDisplayTextDlgIsVisibile || isTopOfStack())) {
922 if(!isScreenIdle()) {
923 CatLog.d(LOG_TAG, "Screen is not idle");
924 sendScreenBusyResponse(slotId);
925 } else {
926 launchTextDialog(slotId);
927 }
928 } else {
929 launchTextDialog(slotId);
930 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800931 break;
932 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -0700933 CatLog.d(LOG_TAG, "SELECT_ITEM +");
934 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
935 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
936 launchMenuActivity(cmdMsg.getMenu(), slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800937 break;
938 case SET_UP_MENU:
Wink Savillee68857d2014-10-17 15:23:05 -0700939 mStkContext[slotId].mCmdInProgress = false;
940 mStkContext[slotId].mMainCmd = mStkContext[slotId].mCurrentCmd;
941 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
942 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
943 CatLog.d(LOG_TAG, "SET_UP_MENU [" + removeMenu(slotId) + "]");
944
945 if (removeMenu(slotId)) {
946 int i = 0;
947 CatLog.d(LOG_TAG, "removeMenu() - Uninstall App");
948 mStkContext[slotId].mCurrentMenu = null;
Preeti Ahuja95919342013-10-01 18:18:55 -0700949 mStkContext[slotId].mMainCmd = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700950 //Check other setup menu state. If all setup menu are removed, uninstall apk.
951 for (i = PhoneConstants.SIM_ID_1; i < mSimCount; i++) {
952 if (i != slotId
Ryuto Sawadaf51e5e02016-11-25 17:12:49 +0900953 && (mStkContext[i].mSetupMenuState == STATE_UNKNOWN
954 || mStkContext[i].mSetupMenuState == STATE_EXIST)) {
Wink Savillee68857d2014-10-17 15:23:05 -0700955 CatLog.d(LOG_TAG, "Not Uninstall App:" + i + ","
Ryuto Sawadaf51e5e02016-11-25 17:12:49 +0900956 + mStkContext[i].mSetupMenuState);
Wink Savillee68857d2014-10-17 15:23:05 -0700957 break;
958 }
959 }
960 if (i == mSimCount) {
961 StkAppInstaller.unInstall(mContext);
962 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800963 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700964 CatLog.d(LOG_TAG, "install App");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800965 StkAppInstaller.install(mContext);
966 }
Wink Savillee68857d2014-10-17 15:23:05 -0700967 if (mStkContext[slotId].mMenuIsVisible) {
968 launchMenuActivity(null, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800969 }
970 break;
971 case GET_INPUT:
972 case GET_INKEY:
Wink Savillee68857d2014-10-17 15:23:05 -0700973 launchInputActivity(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800974 break;
975 case SET_UP_IDLE_MODE_TEXT:
976 waitForUsersResponse = false;
Preeti Ahuja560be362014-11-25 19:38:24 -0800977 mStkContext[slotId].mIdleModeTextCmd = mStkContext[slotId].mCurrentCmd;
978 TextMessage idleModeText = mStkContext[slotId].mCurrentCmd.geTextMessage();
979 if (idleModeText == null) {
980 launchIdleText(slotId);
981 mStkContext[slotId].mIdleModeTextCmd = null;
982 }
983 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
984 if ((mStkContext[slotId].mIdleModeTextCmd != null) && isScreenIdle()) {
985 CatLog.d(this, "set up idle mode");
986 launchIdleText(slotId);
987 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800988 break;
989 case SEND_DTMF:
990 case SEND_SMS:
991 case SEND_SS:
992 case SEND_USSD:
Preeti Ahuja95919342013-10-01 18:18:55 -0700993 case GET_CHANNEL_STATUS:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800994 waitForUsersResponse = false;
Wink Savillee68857d2014-10-17 15:23:05 -0700995 launchEventMessage(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800996 break;
997 case LAUNCH_BROWSER:
Ryuto Sawada0bdc7192016-04-18 12:10:56 +0900998 // The device setup process should not be interrupted by launching browser.
999 if (Settings.Global.getInt(mContext.getContentResolver(),
1000 Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
1001 CatLog.d(this, "The command is not performed if the setup has not been completed.");
1002 sendScreenBusyResponse(slotId);
1003 break;
1004 }
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001005
1006 /* Check if Carrier would not want to launch browser */
1007 if (getBooleanCarrierConfig(mContext,
1008 CarrierConfigManager.KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL)) {
1009 CatLog.d(this, "Browser is not launched as per carrier.");
1010 sendResponse(RES_ID_DONE, slotId, true);
1011 break;
1012 }
1013
Srikanth Chintalaba103002015-11-30 10:49:52 -08001014 mStkContext[slotId].mBrowserSettings =
1015 mStkContext[slotId].mCurrentCmd.getBrowserSettings();
1016 if (!isUrlAvailableToLaunchBrowser(mStkContext[slotId].mBrowserSettings)) {
1017 CatLog.d(this, "Browser url property is not set - send error");
1018 sendResponse(RES_ID_ERROR, slotId, true);
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001019 } else {
Srikanth Chintalaba103002015-11-30 10:49:52 -08001020 TextMessage alphaId = mStkContext[slotId].mCurrentCmd.geTextMessage();
1021 if ((alphaId == null) || TextUtils.isEmpty(alphaId.text)) {
1022 // don't need user confirmation in this case
1023 // just launch the browser or spawn a new tab
1024 CatLog.d(this, "user confirmation is not currently needed.\n" +
1025 "supressing confirmation dialogue and confirming silently...");
1026 mStkContext[slotId].launchBrowser = true;
1027 sendResponse(RES_ID_CONFIRM, slotId, true);
1028 } else {
1029 launchConfirmationDialog(alphaId, slotId);
1030 }
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001031 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001032 break;
1033 case SET_UP_CALL:
Preeti Ahujadd240102013-08-30 17:25:06 -07001034 TextMessage mesg = mStkContext[slotId].mCurrentCmd.getCallSettings().confirmMsg;
1035 if((mesg != null) && (mesg.text == null || mesg.text.length() == 0)) {
1036 mesg.text = getResources().getString(R.string.default_setup_call_msg);
1037 }
1038 CatLog.d(this, "SET_UP_CALL mesg.text " + mesg.text);
1039 launchConfirmationDialog(mesg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001040 break;
1041 case PLAY_TONE:
Srikanth Chintala89aa6602014-03-14 16:26:57 +05301042 handlePlayTone(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001043 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001044 case OPEN_CHANNEL:
Wink Savillee68857d2014-10-17 15:23:05 -07001045 launchOpenChannelDialog(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001046 break;
1047 case CLOSE_CHANNEL:
1048 case RECEIVE_DATA:
1049 case SEND_DATA:
Wink Savillee68857d2014-10-17 15:23:05 -07001050 TextMessage m = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001051
1052 if ((m != null) && (m.text == null)) {
1053 switch(cmdMsg.getCmdType()) {
1054 case CLOSE_CHANNEL:
1055 m.text = getResources().getString(R.string.default_close_channel_msg);
1056 break;
1057 case RECEIVE_DATA:
1058 m.text = getResources().getString(R.string.default_receive_data_msg);
1059 break;
1060 case SEND_DATA:
1061 m.text = getResources().getString(R.string.default_send_data_msg);
1062 break;
1063 }
1064 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001065 /*
1066 * Display indication in the form of a toast to the user if required.
1067 */
Wink Savillee68857d2014-10-17 15:23:05 -07001068 launchEventMessage(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001069 break;
Preeti Ahuja95919342013-10-01 18:18:55 -07001070 case SET_UP_EVENT_LIST:
1071 mStkContext[slotId].mSetupEventListSettings =
1072 mStkContext[slotId].mCurrentCmd.getSetEventList();
1073 mStkContext[slotId].mCurrentSetupEventCmd = mStkContext[slotId].mCurrentCmd;
1074 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
Preeti Ahuja560be362014-11-25 19:38:24 -08001075 if (isScreenIdle()) {
1076 CatLog.d(this," Check if IDLE_SCREEN_AVAILABLE_EVENT is present in List");
1077 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId);
1078 }
Preeti Ahuja95919342013-10-01 18:18:55 -07001079 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001080 }
1081
1082 if (!waitForUsersResponse) {
Wink Savillee68857d2014-10-17 15:23:05 -07001083 if (mStkContext[slotId].mCmdsQ.size() != 0) {
1084 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001085 } else {
Wink Savillee68857d2014-10-17 15:23:05 -07001086 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001087 }
1088 }
1089 }
1090
Wink Savillee68857d2014-10-17 15:23:05 -07001091 private void handleCmdResponse(Bundle args, int slotId) {
1092 CatLog.d(LOG_TAG, "handleCmdResponse, sim id: " + slotId);
1093 if (mStkContext[slotId].mCurrentCmd == null) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001094 return;
1095 }
Wink Savillee68857d2014-10-17 15:23:05 -07001096
1097 if (mStkService[slotId] == null) {
Legler Wuaeefef52014-10-27 00:57:18 +08001098 mStkService[slotId] = CatService.getInstance(slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07001099 if (mStkService[slotId] == null) {
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -07001100 // This should never happen (we should be responding only to a message
1101 // that arrived from StkService). It has to exist by this time
Wink Savillee68857d2014-10-17 15:23:05 -07001102 CatLog.d(LOG_TAG, "Exception! mStkService is null when we need to send response.");
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -07001103 throw new RuntimeException("mStkService is null when we need to send response");
1104 }
1105 }
1106
Wink Savillee68857d2014-10-17 15:23:05 -07001107 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001108
1109 // set result code
1110 boolean helpRequired = args.getBoolean(HELP, false);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001111 boolean confirmed = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001112
1113 switch(args.getInt(RES_ID)) {
1114 case RES_ID_MENU_SELECTION:
Wink Savillee68857d2014-10-17 15:23:05 -07001115 CatLog.d(LOG_TAG, "MENU_SELECTION=" + mStkContext[slotId].
1116 mCurrentMenuCmd.getCmdType());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001117 int menuSelection = args.getInt(MENU_SELECTION);
Wink Savillee68857d2014-10-17 15:23:05 -07001118 switch(mStkContext[slotId].mCurrentMenuCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001119 case SET_UP_MENU:
1120 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -07001121 mStkContext[slotId].lastSelectedItem = getItemName(menuSelection, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001122 if (helpRequired) {
1123 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
1124 } else {
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301125 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1126 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001127 }
1128 resMsg.setMenuSelection(menuSelection);
1129 break;
1130 }
1131 break;
1132 case RES_ID_INPUT:
Wink Savillee68857d2014-10-17 15:23:05 -07001133 CatLog.d(LOG_TAG, "RES_ID_INPUT");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001134 String input = args.getString(INPUT);
Wink Savillee68857d2014-10-17 15:23:05 -07001135 if (input != null && (null != mStkContext[slotId].mCurrentCmd.geInput()) &&
1136 (mStkContext[slotId].mCurrentCmd.geInput().yesNo)) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001137 boolean yesNoSelection = input
1138 .equals(StkInputActivity.YES_STR_RESPONSE);
1139 resMsg.setYesNo(yesNoSelection);
1140 } else {
1141 if (helpRequired) {
1142 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
1143 } else {
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301144 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1145 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001146 resMsg.setInput(input);
1147 }
1148 }
1149 break;
1150 case RES_ID_CONFIRM:
Alex Yakavenkad41f1d92010-07-12 14:13:13 -07001151 CatLog.d(this, "RES_ID_CONFIRM");
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001152 confirmed = args.getBoolean(CONFIRMATION);
Wink Savillee68857d2014-10-17 15:23:05 -07001153 switch (mStkContext[slotId].mCurrentCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001154 case DISPLAY_TEXT:
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301155 if (confirmed) {
1156 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1157 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
1158 } else {
1159 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
1160 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001161 break;
1162 case LAUNCH_BROWSER:
1163 resMsg.setResultCode(confirmed ? ResultCode.OK
1164 : ResultCode.UICC_SESSION_TERM_BY_USER);
1165 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -07001166 mStkContext[slotId].launchBrowser = true;
1167 mStkContext[slotId].mBrowserSettings =
1168 mStkContext[slotId].mCurrentCmd.getBrowserSettings();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001169 }
1170 break;
1171 case SET_UP_CALL:
1172 resMsg.setResultCode(ResultCode.OK);
1173 resMsg.setConfirmation(confirmed);
1174 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -07001175 launchEventMessage(slotId,
1176 mStkContext[slotId].mCurrentCmd.getCallSettings().callMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001177 }
1178 break;
1179 }
1180 break;
1181 case RES_ID_DONE:
1182 resMsg.setResultCode(ResultCode.OK);
1183 break;
1184 case RES_ID_BACKWARD:
Wink Savillee68857d2014-10-17 15:23:05 -07001185 CatLog.d(LOG_TAG, "RES_ID_BACKWARD");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001186 resMsg.setResultCode(ResultCode.BACKWARD_MOVE_BY_USER);
1187 break;
1188 case RES_ID_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -07001189 CatLog.d(LOG_TAG, "RES_ID_END_SESSION");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001190 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
1191 break;
1192 case RES_ID_TIMEOUT:
Wink Savillee68857d2014-10-17 15:23:05 -07001193 CatLog.d(LOG_TAG, "RES_ID_TIMEOUT");
Naveen Kallad5176892009-11-30 12:45:29 -08001194 // GCF test-case 27.22.4.1.1 Expected Sequence 1.5 (DISPLAY TEXT,
1195 // Clear message after delay, successful) expects result code OK.
1196 // If the command qualifier specifies no user response is required
1197 // then send OK instead of NO_RESPONSE_FROM_USER
Wink Savillee68857d2014-10-17 15:23:05 -07001198 if ((mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1199 AppInterface.CommandType.DISPLAY_TEXT.value())
1200 && (mStkContext[slotId].mCurrentCmd.geTextMessage().userClear == false)) {
Naveen Kallad5176892009-11-30 12:45:29 -08001201 resMsg.setResultCode(ResultCode.OK);
1202 } else {
1203 resMsg.setResultCode(ResultCode.NO_RESPONSE_FROM_USER);
1204 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001205 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001206 case RES_ID_CHOICE:
1207 int choice = args.getInt(CHOICE);
1208 CatLog.d(this, "User Choice=" + choice);
1209 switch (choice) {
1210 case YES:
1211 resMsg.setResultCode(ResultCode.OK);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001212 confirmed = true;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001213 break;
1214 case NO:
1215 resMsg.setResultCode(ResultCode.USER_NOT_ACCEPT);
1216 break;
1217 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001218
Wink Savillee68857d2014-10-17 15:23:05 -07001219 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1220 AppInterface.CommandType.OPEN_CHANNEL.value()) {
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001221 resMsg.setConfirmation(confirmed);
1222 }
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001223 break;
Srikanth Chintalaba103002015-11-30 10:49:52 -08001224 case RES_ID_ERROR:
1225 CatLog.d(LOG_TAG, "RES_ID_ERROR");
1226 switch (mStkContext[slotId].mCurrentCmd.getCmdType()) {
1227 case LAUNCH_BROWSER:
1228 resMsg.setResultCode(ResultCode.LAUNCH_BROWSER_ERROR);
1229 break;
1230 }
1231 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001232 default:
Wink Savillee68857d2014-10-17 15:23:05 -07001233 CatLog.d(LOG_TAG, "Unknown result id");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001234 return;
1235 }
Wink Savillee68857d2014-10-17 15:23:05 -07001236
1237 if (null != mStkContext[slotId].mCurrentCmd &&
1238 null != mStkContext[slotId].mCurrentCmd.getCmdType()) {
1239 CatLog.d(LOG_TAG, "handleCmdResponse- cmdName[" +
1240 mStkContext[slotId].mCurrentCmd.getCmdType().name() + "]");
1241 }
1242 mStkService[slotId].onCmdResponse(resMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001243 }
1244
1245 /**
1246 * Returns 0 or FLAG_ACTIVITY_NO_USER_ACTION, 0 means the user initiated the action.
1247 *
1248 * @param userAction If the userAction is yes then we always return 0 otherwise
1249 * mMenuIsVisible is used to determine what to return. If mMenuIsVisible is true
1250 * then we are the foreground app and we'll return 0 as from our perspective a
1251 * user action did cause. If it's false than we aren't the foreground app and
1252 * FLAG_ACTIVITY_NO_USER_ACTION is returned.
Wink Saville79085fc2009-06-09 10:27:23 -07001253 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001254 * @return 0 or FLAG_ACTIVITY_NO_USER_ACTION
1255 */
Wink Savillee68857d2014-10-17 15:23:05 -07001256 private int getFlagActivityNoUserAction(InitiatedByUserAction userAction, int slotId) {
1257 return ((userAction == InitiatedByUserAction.yes) | mStkContext[slotId].mMenuIsVisible)
1258 ? 0 : Intent.FLAG_ACTIVITY_NO_USER_ACTION;
1259 }
1260 /**
1261 * This method is used for cleaning up pending instances in stack.
1262 */
1263 private void cleanUpInstanceStackBySlot(int slotId) {
1264 Activity activity = mStkContext[slotId].getPendingActivityInstance();
1265 Activity dialog = mStkContext[slotId].getPendingDialogInstance();
1266 CatLog.d(LOG_TAG, "cleanUpInstanceStackBySlot slotId: " + slotId);
Legler Wuaeefef52014-10-27 00:57:18 +08001267 if (mStkContext[slotId].mCurrentCmd == null) {
1268 CatLog.d(LOG_TAG, "current cmd is null.");
1269 return;
1270 }
Wink Savillee68857d2014-10-17 15:23:05 -07001271 if (activity != null) {
1272 CatLog.d(LOG_TAG, "current cmd type: " +
1273 mStkContext[slotId].mCurrentCmd.getCmdType());
1274 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1275 AppInterface.CommandType.GET_INPUT.value() ||
1276 mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1277 AppInterface.CommandType.GET_INKEY.value()) {
1278 mStkContext[slotId].mIsInputPending = true;
1279 } else if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1280 AppInterface.CommandType.SET_UP_MENU.value() ||
1281 mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1282 AppInterface.CommandType.SELECT_ITEM.value()) {
1283 mStkContext[slotId].mIsMenuPending = true;
1284 } else {
1285 }
1286 CatLog.d(LOG_TAG, "finish pending activity.");
1287 activity.finish();
1288 mStkContext[slotId].mActivityInstance = null;
1289 }
1290 if (dialog != null) {
1291 CatLog.d(LOG_TAG, "finish pending dialog.");
1292 mStkContext[slotId].mIsDialogPending = true;
1293 dialog.finish();
1294 mStkContext[slotId].mDialogInstance = null;
1295 }
1296 }
1297 /**
1298 * This method is used for restoring pending instances from stack.
1299 */
1300 private void restoreInstanceFromStackBySlot(int slotId) {
1301 AppInterface.CommandType cmdType = mStkContext[slotId].mCurrentCmd.getCmdType();
1302
1303 CatLog.d(LOG_TAG, "restoreInstanceFromStackBySlot cmdType : " + cmdType);
1304 switch(cmdType) {
1305 case GET_INPUT:
1306 case GET_INKEY:
1307 launchInputActivity(slotId);
1308 //Set mMenuIsVisible to true for showing main menu for
1309 //following session end command.
1310 mStkContext[slotId].mMenuIsVisible = true;
1311 break;
1312 case DISPLAY_TEXT:
1313 launchTextDialog(slotId);
1314 break;
1315 case LAUNCH_BROWSER:
1316 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.geTextMessage(),
1317 slotId);
1318 break;
1319 case OPEN_CHANNEL:
1320 launchOpenChannelDialog(slotId);
1321 break;
1322 case SET_UP_CALL:
1323 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.getCallSettings().
1324 confirmMsg, slotId);
1325 break;
1326 case SET_UP_MENU:
1327 case SELECT_ITEM:
1328 launchMenuActivity(null, slotId);
1329 break;
1330 default:
1331 break;
1332 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001333 }
1334
Wink Savillee68857d2014-10-17 15:23:05 -07001335 private void launchMenuActivity(Menu menu, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001336 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001337 String targetActivity = STK_MENU_ACTIVITY_NAME;
1338 String uriString = STK_MENU_URI + System.currentTimeMillis();
1339 //Set unique URI to create a new instance of activity for different slotId.
1340 Uri uriData = Uri.parse(uriString);
1341
1342 CatLog.d(LOG_TAG, "launchMenuActivity, slotId: " + slotId + " , " +
1343 uriData.toString() + " , " + mStkContext[slotId].mOpCode + ", "
1344 + mStkContext[slotId].mMenuState);
1345 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1346 int intentFlags = Intent.FLAG_ACTIVITY_NEW_TASK;
1347
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001348 if (menu == null) {
1349 // We assume this was initiated by the user pressing the tool kit icon
Wink Savillee68857d2014-10-17 15:23:05 -07001350 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.yes, slotId);
1351 if (mStkContext[slotId].mOpCode == OP_END_SESSION) {
1352 CatLog.d(LOG_TAG, "launchMenuActivity, return OP_END_SESSION");
1353 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
1354 if (mStkContext[slotId].mMainActivityInstance != null) {
1355 CatLog.d(LOG_TAG, "launchMenuActivity, mMainActivityInstance is not null");
1356 return;
1357 }
Wink Savillee68857d2014-10-17 15:23:05 -07001358 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001359
Wink Savillee68857d2014-10-17 15:23:05 -07001360 //If the last pending menu is secondary menu, "STATE" should be "STATE_SECONDARY".
1361 //Otherwise, it should be "STATE_MAIN".
1362 if (mStkContext[slotId].mOpCode == OP_LAUNCH_APP &&
1363 mStkContext[slotId].mMenuState == StkMenuActivity.STATE_SECONDARY) {
1364 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
1365 } else {
1366 newIntent.putExtra("STATE", StkMenuActivity.STATE_MAIN);
1367 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
1368 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001369 } else {
1370 // We don't know and we'll let getFlagActivityNoUserAction decide.
Wink Savillee68857d2014-10-17 15:23:05 -07001371 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001372 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
Wink Savillee68857d2014-10-17 15:23:05 -07001373 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_SECONDARY;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001374 }
Wink Savillee68857d2014-10-17 15:23:05 -07001375 newIntent.putExtra(SLOT_ID, slotId);
1376 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001377 newIntent.setFlags(intentFlags);
1378 mContext.startActivity(newIntent);
1379 }
1380
Wink Savillee68857d2014-10-17 15:23:05 -07001381 private void launchInputActivity(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001382 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001383 String targetActivity = STK_INPUT_ACTIVITY_NAME;
1384 String uriString = STK_INPUT_URI + System.currentTimeMillis();
1385 //Set unique URI to create a new instance of activity for different slotId.
1386 Uri uriData = Uri.parse(uriString);
1387
1388 CatLog.d(LOG_TAG, "launchInputActivity, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001389 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
Wink Savillee68857d2014-10-17 15:23:05 -07001390 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1391 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1392 newIntent.putExtra("INPUT", mStkContext[slotId].mCurrentCmd.geInput());
1393 newIntent.putExtra(SLOT_ID, slotId);
1394 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001395 mContext.startActivity(newIntent);
1396 }
1397
Wink Savillee68857d2014-10-17 15:23:05 -07001398 private void launchTextDialog(int slotId) {
1399 CatLog.d(LOG_TAG, "launchTextDialog, slotId: " + slotId);
1400 Intent newIntent = new Intent();
1401 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1402 int action = getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
1403 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1404 //Set unique URI to create a new instance of activity for different slotId.
1405 Uri uriData = Uri.parse(uriString);
1406 if (newIntent != null) {
1407 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1408 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1409 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1410 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1411 newIntent.setData(uriData);
1412 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1413 newIntent.putExtra(SLOT_ID, slotId);
1414 startActivity(newIntent);
Preeti Ahuja414bc412013-06-25 19:31:49 -07001415 // For display texts with immediate response, send the terminal response
1416 // immediately. responseNeeded will be false, if display text command has
1417 // the immediate response tlv.
1418 if (!mStkContext[slotId].mCurrentCmd.geTextMessage().responseNeeded) {
1419 sendResponse(RES_ID_CONFIRM, slotId, true);
1420 }
Wink Savillee68857d2014-10-17 15:23:05 -07001421 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001422 }
1423
Wink Savillee68857d2014-10-17 15:23:05 -07001424 public boolean isStkDialogActivated(Context context) {
1425 String stkDialogActivity = "com.android.stk.StkDialogActivity";
1426 boolean activated = false;
1427 final ActivityManager am = (ActivityManager) context.getSystemService(
1428 Context.ACTIVITY_SERVICE);
1429 String topActivity = am.getRunningTasks(1).get(0).topActivity.getClassName();
1430
1431 CatLog.d(LOG_TAG, "isStkDialogActivated: " + topActivity);
1432 if (topActivity.equals(stkDialogActivity)) {
1433 activated = true;
1434 }
1435 CatLog.d(LOG_TAG, "activated : " + activated);
1436 return activated;
Johan Hellman3aec01c2011-02-10 10:15:28 +01001437 }
1438
Preeti Ahuja95919342013-10-01 18:18:55 -07001439 private void sendSetUpEventResponse(int event, byte[] addedInfo, int slotId) {
Preeti Ahuja414bc412013-06-25 19:31:49 -07001440 CatLog.d(this, "sendSetUpEventResponse: event : " + event + "slotId = " + slotId);
Preeti Ahuja95919342013-10-01 18:18:55 -07001441
1442 if (mStkContext[slotId].mCurrentSetupEventCmd == null){
1443 CatLog.e(this, "mCurrentSetupEventCmd is null");
1444 return;
1445 }
1446
1447 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentSetupEventCmd);
1448
1449 resMsg.setResultCode(ResultCode.OK);
1450 resMsg.setEventDownload(event, addedInfo);
1451
1452 mStkService[slotId].onCmdResponse(resMsg);
1453 }
1454
1455 private void checkForSetupEvent(int event, Bundle args, int slotId) {
1456 boolean eventPresent = false;
1457 byte[] addedInfo = null;
1458 CatLog.d(this, "Event :" + event);
1459
1460 if (mStkContext[slotId].mSetupEventListSettings != null) {
1461 /* Checks if the event is present in the EventList updated by last
1462 * SetupEventList Proactive Command */
1463 for (int i : mStkContext[slotId].mSetupEventListSettings.eventList) {
1464 if (event == i) {
1465 eventPresent = true;
1466 break;
1467 }
1468 }
1469
1470 /* If Event is present send the response to ICC */
1471 if (eventPresent == true) {
1472 CatLog.d(this, " Event " + event + "exists in the EventList");
1473
1474 switch (event) {
Preeti Ahuja560be362014-11-25 19:38:24 -08001475 case IDLE_SCREEN_AVAILABLE_EVENT:
1476 sendSetUpEventResponse(event, addedInfo, slotId);
1477 removeSetUpEvent(event, slotId);
1478 break;
Preeti Ahuja95919342013-10-01 18:18:55 -07001479 case LANGUAGE_SELECTION_EVENT:
1480 String language = mContext
1481 .getResources().getConfiguration().locale.getLanguage();
1482 CatLog.d(this, "language: " + language);
1483 // Each language code is a pair of alpha-numeric characters.
1484 // Each alpha-numeric character shall be coded on one byte
1485 // using the SMS default 7-bit coded alphabet
1486 addedInfo = GsmAlphabet.stringToGsm8BitPacked(language);
1487 sendSetUpEventResponse(event, addedInfo, slotId);
1488 break;
1489 default:
1490 break;
1491 }
1492 } else {
1493 CatLog.e(this, " Event does not exist in the EventList");
1494 }
1495 } else {
1496 CatLog.e(this, "SetupEventList is not received. Ignoring the event: " + event);
1497 }
1498 }
1499
1500 private void removeSetUpEvent(int event, int slotId) {
1501 CatLog.d(this, "Remove Event :" + event);
1502
1503 if (mStkContext[slotId].mSetupEventListSettings != null) {
1504 /*
1505 * Make new Eventlist without the event
1506 */
1507 for (int i = 0; i < mStkContext[slotId].mSetupEventListSettings.eventList.length; i++) {
1508 if (event == mStkContext[slotId].mSetupEventListSettings.eventList[i]) {
1509 mStkContext[slotId].mSetupEventListSettings.eventList[i] = INVALID_SETUP_EVENT;
1510 break;
1511 }
1512 }
1513 }
1514 }
1515
1516 private void launchEventMessage(int slotId) {
1517 launchEventMessage(slotId, mStkContext[slotId].mCurrentCmd.geTextMessage());
1518 }
1519
Wink Savillee68857d2014-10-17 15:23:05 -07001520 private void launchEventMessage(int slotId, TextMessage msg) {
1521 if (msg == null || (msg.text != null && msg.text.length() == 0)) {
1522 CatLog.d(LOG_TAG, "launchEventMessage return");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001523 return;
1524 }
Wink Savillee68857d2014-10-17 15:23:05 -07001525
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001526 Toast toast = new Toast(mContext.getApplicationContext());
1527 LayoutInflater inflate = (LayoutInflater) mContext
1528 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
1529 View v = inflate.inflate(R.layout.stk_event_msg, null);
1530 TextView tv = (TextView) v
1531 .findViewById(com.android.internal.R.id.message);
1532 ImageView iv = (ImageView) v
1533 .findViewById(com.android.internal.R.id.icon);
1534 if (msg.icon != null) {
1535 iv.setImageBitmap(msg.icon);
1536 } else {
1537 iv.setVisibility(View.GONE);
1538 }
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301539 /* In case of 'self explanatory' stkapp should display the specified
1540 * icon in proactive command (but not the alpha string).
1541 * If icon is non-self explanatory and if the icon could not be displayed
1542 * then alpha string or text data should be displayed
1543 * Ref: ETSI 102.223,section 6.5.4
1544 */
1545 if (mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ||
1546 msg.icon == null || !msg.iconSelfExplanatory) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001547 tv.setText(msg.text);
1548 }
1549
1550 toast.setView(v);
1551 toast.setDuration(Toast.LENGTH_LONG);
1552 toast.setGravity(Gravity.BOTTOM, 0, 0);
1553 toast.show();
1554 }
1555
Wink Savillee68857d2014-10-17 15:23:05 -07001556 private void launchConfirmationDialog(TextMessage msg, int slotId) {
1557 msg.title = mStkContext[slotId].lastSelectedItem;
1558 Intent newIntent = new Intent();
1559 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1560 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1561 //Set unique URI to create a new instance of activity for different slotId.
1562 Uri uriData = Uri.parse(uriString);
1563
1564 if (newIntent != null) {
1565 newIntent.setClassName(this, targetActivity);
1566 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1567 | Intent.FLAG_ACTIVITY_NO_HISTORY
1568 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1569 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1570 newIntent.putExtra("TEXT", msg);
1571 newIntent.putExtra(SLOT_ID, slotId);
1572 newIntent.setData(uriData);
1573 startActivity(newIntent);
1574 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001575 }
1576
1577 private void launchBrowser(BrowserSettings settings) {
1578 if (settings == null) {
1579 return;
1580 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001581
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001582 Uri data = null;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001583 String url;
1584 if (settings.url == null) {
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001585 // if the command did not contain a URL,
1586 // launch the browser to the default homepage.
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001587 CatLog.d(this, "no url data provided by proactive command." +
1588 " launching browser with stk default URL ... ");
1589 url = SystemProperties.get(STK_BROWSER_DEFAULT_URL_SYSPROP,
1590 "http://www.google.com");
1591 } else {
1592 CatLog.d(this, "launch browser command has attached url = " + settings.url);
1593 url = settings.url;
Abhishek Adappa840c82f2013-02-26 10:19:49 -08001594 }
David Brown7c03cfe2011-10-20 15:36:12 -07001595
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001596 if (url.startsWith("http://") || url.startsWith("https://")) {
1597 data = Uri.parse(url);
1598 CatLog.d(this, "launching browser with url = " + url);
1599 } else {
1600 String modifiedUrl = "http://" + url;
1601 data = Uri.parse(modifiedUrl);
1602 CatLog.d(this, "launching browser with modified url = " + modifiedUrl);
1603 }
1604
1605 Intent intent = new Intent(Intent.ACTION_VIEW);
1606 intent.setData(data);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001607 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1608 switch (settings.mode) {
1609 case USE_EXISTING_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001610 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1611 break;
1612 case LAUNCH_NEW_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001613 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
1614 break;
1615 case LAUNCH_IF_NOT_ALREADY_LAUNCHED:
1616 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
1617 break;
1618 }
1619 // start browser activity
1620 startActivity(intent);
1621 // a small delay, let the browser start, before processing the next command.
Wink Saville79085fc2009-06-09 10:27:23 -07001622 // this is good for scenarios where a related DISPLAY TEXT command is
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001623 // followed immediately.
1624 try {
Ryuto Sawada350aaa62016-06-13 14:47:22 +09001625 Thread.sleep(3000);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001626 } catch (InterruptedException e) {}
1627 }
1628
Wink Savillee68857d2014-10-17 15:23:05 -07001629 private void launchIdleText(int slotId) {
Preeti Ahuja560be362014-11-25 19:38:24 -08001630 TextMessage msg = mStkContext[slotId].mIdleModeTextCmd.geTextMessage();
dujin.cha2a0eb2a2011-11-11 15:03:57 +09001631
Preeti Ahuja95919342013-10-01 18:18:55 -07001632 if (msg == null || msg.text ==null) {
1633 CatLog.d(LOG_TAG, msg == null ? "mCurrent.getTextMessage is NULL"
1634 : "mCurrent.getTextMessage.text is NULL");
Wink Savillee68857d2014-10-17 15:23:05 -07001635 mNotificationManager.cancel(getNotificationId(slotId));
Wink Saville046db4b2011-11-01 20:42:54 -07001636 return;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001637 } else {
Preeti Ahuja95919342013-10-01 18:18:55 -07001638 CatLog.d(LOG_TAG, "launchIdleText - text[" + msg.text
1639 + "] iconSelfExplanatory[" + msg.iconSelfExplanatory
1640 + "] icon[" + msg.icon + "], sim id: " + slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07001641 CatLog.d(LOG_TAG, "Add IdleMode text");
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001642 PendingIntent pendingIntent = PendingIntent.getService(mContext, 0,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001643 new Intent(mContext, StkAppService.class), 0);
fionaxu805eb572017-05-02 10:57:30 -07001644 createAllChannels();
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001645 final Notification.Builder notificationBuilder = new Notification.Builder(
fionaxu2c91c752017-04-21 18:11:57 -07001646 StkAppService.this, STK_NOTIFICATION_CHANNEL_ID);
Wink Savillee68857d2014-10-17 15:23:05 -07001647 if (mStkContext[slotId].mMainCmd != null &&
1648 mStkContext[slotId].mMainCmd.getMenu() != null) {
1649 notificationBuilder.setContentTitle(mStkContext[slotId].mMainCmd.getMenu().title);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02001650 } else {
1651 notificationBuilder.setContentTitle("");
1652 }
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001653 notificationBuilder
1654 .setSmallIcon(com.android.internal.R.drawable.stat_notify_sim_toolkit);
1655 notificationBuilder.setContentIntent(pendingIntent);
1656 notificationBuilder.setOngoing(true);
1657 // Set text and icon for the status bar and notification body.
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301658 if (mStkContext[slotId].mIdleModeTextCmd.hasIconLoadFailed() ||
1659 !msg.iconSelfExplanatory) {
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001660 notificationBuilder.setContentText(msg.text);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02001661 notificationBuilder.setTicker(msg.text);
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01001662 }
1663 if (msg.icon != null) {
1664 notificationBuilder.setLargeIcon(msg.icon);
1665 } else {
1666 Bitmap bitmapIcon = BitmapFactory.decodeResource(StkAppService.this
1667 .getResources().getSystem(),
1668 com.android.internal.R.drawable.stat_notify_sim_toolkit);
1669 notificationBuilder.setLargeIcon(bitmapIcon);
1670 }
Selim Cinek62eb3fe2014-08-27 17:52:23 +02001671 notificationBuilder.setColor(mContext.getResources().getColor(
1672 com.android.internal.R.color.system_notification_accent_color));
Wink Savillee68857d2014-10-17 15:23:05 -07001673 mNotificationManager.notify(getNotificationId(slotId), notificationBuilder.build());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001674 }
1675 }
1676
fionaxu805eb572017-05-02 10:57:30 -07001677 /** Creates the notification channel and registers it with NotificationManager.
1678 * If a channel with the same ID is already registered, NotificationManager will
1679 * ignore this call.
1680 */
1681 private void createAllChannels() {
1682 mNotificationManager.createNotificationChannel(new NotificationChannel(
1683 STK_NOTIFICATION_CHANNEL_ID,
1684 getResources().getString(R.string.stk_channel_name),
1685 NotificationManager.IMPORTANCE_MIN));
1686 }
1687
Wink Savillee68857d2014-10-17 15:23:05 -07001688 private void launchToneDialog(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001689 Intent newIntent = new Intent(this, ToneDialog.class);
Wink Savillee68857d2014-10-17 15:23:05 -07001690 String uriString = STK_TONE_URI + slotId;
1691 Uri uriData = Uri.parse(uriString);
1692 //Set unique URI to create a new instance of activity for different slotId.
1693 CatLog.d(LOG_TAG, "launchToneDialog, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001694 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1695 | Intent.FLAG_ACTIVITY_NO_HISTORY
1696 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
Wink Savillee68857d2014-10-17 15:23:05 -07001697 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1698 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1699 newIntent.putExtra("TONE", mStkContext[slotId].mCurrentCmd.getToneSettings());
1700 newIntent.putExtra(SLOT_ID, slotId);
1701 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001702 startActivity(newIntent);
1703 }
1704
Srikanth Chintala89aa6602014-03-14 16:26:57 +05301705 private void handlePlayTone(int slotId) {
1706 TextMessage toneMsg = mStkContext[slotId].mCurrentCmd.geTextMessage();
1707
1708 boolean showUser = true;
1709 boolean displayDialog = true;
1710 Resources resource = Resources.getSystem();
1711 try {
1712 displayDialog = !resource.getBoolean(
1713 com.android.internal.R.bool.config_stkNoAlphaUsrCnf);
1714 } catch (NotFoundException e) {
1715 displayDialog = true;
1716 }
1717
1718 // As per the spec 3GPP TS 11.14, 6.4.5. Play Tone.
1719 // If there is no alpha identifier tlv present, UE may show the
1720 // user information. 'config_stkNoAlphaUsrCnf' value will decide
1721 // whether to show it or not.
1722 // If alpha identifier tlv is present and its data is null, play only tone
1723 // without showing user any information.
1724 // Alpha Id is Present, but the text data is null.
1725 if ((toneMsg.text != null ) && (toneMsg.text.equals(""))) {
1726 CatLog.d(this, "Alpha identifier data is null, play only tone");
1727 showUser = false;
1728 }
1729 // Alpha Id is not present AND we need to show info to the user.
1730 if (toneMsg.text == null && displayDialog) {
1731 CatLog.d(this, "toneMsg.text " + toneMsg.text
1732 + " Starting ToneDialog activity with default message.");
1733 toneMsg.text = getResources().getString(R.string.default_tone_dialog_msg);
1734 showUser = true;
1735 }
1736 // Dont show user info, if config setting is true.
1737 if (toneMsg.text == null && !displayDialog) {
1738 CatLog.d(this, "config value stkNoAlphaUsrCnf is true");
1739 showUser = false;
1740 }
1741
1742 CatLog.d(this, "toneMsg.text: " + toneMsg.text + "showUser: " +showUser +
1743 "displayDialog: " +displayDialog);
1744 playTone(showUser, slotId);
1745 }
1746
1747 private void playTone(boolean showUserInfo, int slotId) {
1748 // Start playing tone and vibration
1749 ToneSettings settings = mStkContext[slotId].mCurrentCmd.getToneSettings();
1750 if (null == settings) {
1751 CatLog.d(this, "null settings, not playing tone.");
1752 return;
1753 }
1754
1755 mVibrator = (Vibrator)getSystemService(VIBRATOR_SERVICE);
1756 mTonePlayer = new TonePlayer();
1757 mTonePlayer.play(settings.tone);
1758 int timeout = StkApp.calculateDurationInMilis(settings.duration);
1759 if (timeout == 0) {
1760 timeout = StkApp.TONE_DEFAULT_TIMEOUT;
1761 }
1762
1763 Message msg = mServiceHandler.obtainMessage();
1764 msg.arg1 = OP_STOP_TONE;
1765 msg.arg2 = slotId;
1766 msg.obj = (Integer)(showUserInfo ? 1 : 0);
1767 msg.what = STOP_TONE_WHAT;
1768 mServiceHandler.sendMessageDelayed(msg, timeout);
1769 if (settings.vibrate) {
1770 mVibrator.vibrate(timeout);
1771 }
1772
1773 // Start Tone dialog Activity to show user the information.
1774 if (showUserInfo) {
1775 Intent newIntent = new Intent(sInstance, ToneDialog.class);
1776 String uriString = STK_TONE_URI + slotId;
1777 Uri uriData = Uri.parse(uriString);
1778 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1779 | Intent.FLAG_ACTIVITY_NO_HISTORY
1780 | Intent.FLAG_ACTIVITY_SINGLE_TOP
1781 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
1782 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1783 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
1784 newIntent.putExtra(SLOT_ID, slotId);
1785 newIntent.setData(uriData);
1786 startActivity(newIntent);
1787 }
1788 }
1789
1790 private void finishToneDialogActivity() {
1791 Intent finishIntent = new Intent(FINISH_TONE_ACTIVITY_ACTION);
1792 sendBroadcast(finishIntent);
1793 }
1794
1795 private void handleStopTone(Message msg, int slotId) {
1796 int resId = 0;
1797
1798 // Stop the play tone in following cases:
1799 // 1.OP_STOP_TONE: play tone timer expires.
1800 // 2.STOP_TONE_USER: user pressed the back key.
1801 if (msg.arg1 == OP_STOP_TONE) {
1802 resId = RES_ID_DONE;
1803 // Dismiss Tone dialog, after finishing off playing the tone.
1804 int finishActivity = (Integer) msg.obj;
1805 if (finishActivity == 1) finishToneDialogActivity();
1806 } else if (msg.arg1 == OP_STOP_TONE_USER) {
1807 resId = RES_ID_END_SESSION;
1808 }
1809
1810 sendResponse(resId, slotId, true);
1811 mServiceHandler.removeMessages(STOP_TONE_WHAT);
1812 if (mTonePlayer != null) {
1813 mTonePlayer.stop();
1814 mTonePlayer.release();
1815 mTonePlayer = null;
1816 }
1817 if (mVibrator != null) {
1818 mVibrator.cancel();
1819 mVibrator = null;
1820 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001821 }
1822
Takanori Nakano49b12722016-02-16 14:34:14 +09001823 private void launchOpenChannelDialog(final int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -07001824 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001825 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001826 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001827 return;
1828 }
1829
1830 msg.title = getResources().getString(R.string.stk_dialog_title);
1831 if (msg.text == null) {
1832 msg.text = getResources().getString(R.string.default_open_channel_msg);
1833 }
1834
1835 final AlertDialog dialog = new AlertDialog.Builder(mContext)
1836 .setIconAttribute(android.R.attr.alertDialogIcon)
1837 .setTitle(msg.title)
1838 .setMessage(msg.text)
1839 .setCancelable(false)
1840 .setPositiveButton(getResources().getString(R.string.stk_dialog_accept),
1841 new DialogInterface.OnClickListener() {
1842 public void onClick(DialogInterface dialog, int which) {
1843 Bundle args = new Bundle();
1844 args.putInt(RES_ID, RES_ID_CHOICE);
1845 args.putInt(CHOICE, YES);
1846 Message message = mServiceHandler.obtainMessage();
1847 message.arg1 = OP_RESPONSE;
Takanori Nakano49b12722016-02-16 14:34:14 +09001848 message.arg2 = slotId;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001849 message.obj = args;
1850 mServiceHandler.sendMessage(message);
1851 }
1852 })
1853 .setNegativeButton(getResources().getString(R.string.stk_dialog_reject),
1854 new DialogInterface.OnClickListener() {
1855 public void onClick(DialogInterface dialog, int which) {
1856 Bundle args = new Bundle();
1857 args.putInt(RES_ID, RES_ID_CHOICE);
1858 args.putInt(CHOICE, NO);
1859 Message message = mServiceHandler.obtainMessage();
1860 message.arg1 = OP_RESPONSE;
Takanori Nakano49b12722016-02-16 14:34:14 +09001861 message.arg2 = slotId;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001862 message.obj = args;
1863 mServiceHandler.sendMessage(message);
1864 }
1865 })
1866 .create();
1867
1868 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1869 if (!mContext.getResources().getBoolean(
1870 com.android.internal.R.bool.config_sf_slowBlur)) {
1871 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
1872 }
1873
1874 dialog.show();
1875 }
1876
Wink Savillee68857d2014-10-17 15:23:05 -07001877 private void launchTransientEventMessage(int slotId) {
1878 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001879 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07001880 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001881 return;
1882 }
1883
1884 msg.title = getResources().getString(R.string.stk_dialog_title);
1885
1886 final AlertDialog dialog = new AlertDialog.Builder(mContext)
1887 .setIconAttribute(android.R.attr.alertDialogIcon)
1888 .setTitle(msg.title)
1889 .setMessage(msg.text)
1890 .setCancelable(false)
1891 .setPositiveButton(getResources().getString(android.R.string.ok),
1892 new DialogInterface.OnClickListener() {
1893 public void onClick(DialogInterface dialog, int which) {
1894 }
1895 })
1896 .create();
1897
1898 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1899 if (!mContext.getResources().getBoolean(
1900 com.android.internal.R.bool.config_sf_slowBlur)) {
1901 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
1902 }
1903
1904 dialog.show();
1905 }
1906
Wink Savillee68857d2014-10-17 15:23:05 -07001907 private int getNotificationId(int slotId) {
1908 int notifyId = STK_NOTIFICATION_ID;
1909 if (slotId >= 0 && slotId < mSimCount) {
1910 notifyId += slotId;
1911 } else {
1912 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
1913 }
1914 CatLog.d(LOG_TAG, "getNotificationId, slotId: " + slotId + ", notifyId: " + notifyId);
1915 return notifyId;
1916 }
1917
1918 private String getItemName(int itemId, int slotId) {
1919 Menu menu = mStkContext[slotId].mCurrentCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001920 if (menu == null) {
1921 return null;
1922 }
1923 for (Item item : menu.items) {
1924 if (item.id == itemId) {
1925 return item.text;
1926 }
1927 }
1928 return null;
1929 }
1930
Wink Savillee68857d2014-10-17 15:23:05 -07001931 private boolean removeMenu(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001932 try {
Wink Savillee68857d2014-10-17 15:23:05 -07001933 if (mStkContext[slotId].mCurrentMenu.items.size() == 1 &&
1934 mStkContext[slotId].mCurrentMenu.items.get(0) == null) {
1935 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001936 return true;
1937 }
1938 } catch (NullPointerException e) {
Wink Savillee68857d2014-10-17 15:23:05 -07001939 CatLog.d(LOG_TAG, "Unable to get Menu's items size");
1940 mStkContext[slotId].mSetupMenuState = STATE_NOT_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001941 return true;
1942 }
Wink Savillee68857d2014-10-17 15:23:05 -07001943 mStkContext[slotId].mSetupMenuState = STATE_EXIST;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001944 return false;
1945 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05301946
Wink Savillee68857d2014-10-17 15:23:05 -07001947 StkContext getStkContext(int slotId) {
1948 if (slotId >= 0 && slotId < mSimCount) {
1949 return mStkContext[slotId];
1950 } else {
1951 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
1952 return null;
1953 }
1954 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05301955
1956 private void handleAlphaNotify(Bundle args) {
1957 String alphaString = args.getString(AppInterface.ALPHA_STRING);
1958
1959 CatLog.d(this, "Alpha string received from card: " + alphaString);
1960 Toast toast = Toast.makeText(sInstance, alphaString, Toast.LENGTH_LONG);
1961 toast.setGravity(Gravity.TOP, 0, 0);
1962 toast.show();
1963 }
Srikanth Chintalaba103002015-11-30 10:49:52 -08001964
1965 private boolean isUrlAvailableToLaunchBrowser(BrowserSettings settings) {
1966 String url = SystemProperties.get(STK_BROWSER_DEFAULT_URL_SYSPROP, "");
1967 if (url == "" && settings.url == null) {
1968 return false;
1969 }
1970 return true;
1971 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001972}