blob: 52b06fb3fa25f047b55eb8c8a97a8301df7ca8a1 [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
Peter Wangc94b8e62019-12-30 17:09:10 -080019import static com.android.internal.telephony.cat.CatCmdMessage.SetupEventListConstants.IDLE_SCREEN_AVAILABLE_EVENT;
20import static com.android.internal.telephony.cat.CatCmdMessage.SetupEventListConstants.LANGUAGE_SELECTION_EVENT;
21import static com.android.internal.telephony.cat.CatCmdMessage.SetupEventListConstants.USER_ACTIVITY_EVENT;
22
23import android.app.Activity;
Preeti Ahuja95919342013-10-01 18:18:55 -070024import android.app.ActivityManager;
25import android.app.ActivityManager.RunningTaskInfo;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050026import android.app.AlertDialog;
Hall Liu9d5d5ee2020-10-06 14:15:40 -070027import android.app.HomeVisibilityListener;
Yuta Uife965802017-11-07 20:12:37 +090028import android.app.KeyguardManager;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080029import android.app.Notification;
fionaxu2c91c752017-04-21 18:11:57 -070030import android.app.NotificationChannel;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080031import android.app.NotificationManager;
32import android.app.PendingIntent;
33import android.app.Service;
Yuta Uife965802017-11-07 20:12:37 +090034import android.content.BroadcastReceiver;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080035import android.content.Context;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050036import android.content.DialogInterface;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080037import android.content.Intent;
Peter Wangc94b8e62019-12-30 17:09:10 -080038import android.content.IntentFilter;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +090039import android.content.pm.PackageManager;
40import android.content.pm.ResolveInfo;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053041import android.content.res.Resources;
42import android.content.res.Resources.NotFoundException;
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +010043import android.graphics.Bitmap;
44import android.graphics.BitmapFactory;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080045import android.net.Uri;
46import android.os.Bundle;
47import android.os.Handler;
48import android.os.IBinder;
49import android.os.Looper;
50import android.os.Message;
Takanori Nakanoc8054ba2016-08-15 19:18:16 +090051import android.os.Parcel;
Sooraj Sasindrana4160472016-10-12 16:28:25 -070052import android.os.PersistableBundle;
Preeti Ahuja560be362014-11-25 19:38:24 -080053import android.os.PowerManager;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +090054import android.os.RemoteException;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070055import android.os.SystemProperties;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053056import android.os.Vibrator;
Preeti Ahuja95919342013-10-01 18:18:55 -070057import android.provider.Settings;
Sooraj Sasindrana4160472016-10-12 16:28:25 -070058import android.telephony.CarrierConfigManager;
Yoshiaki Naka30d5a812018-11-12 12:43:34 +090059import android.telephony.SubscriptionInfo;
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +090060import android.telephony.SubscriptionManager;
Peter Wangc94b8e62019-12-30 17:09:10 -080061import android.telephony.TelephonyFrameworkInitializer;
Wink Saville56469d52009-04-02 01:37:03 -070062import android.telephony.TelephonyManager;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -070063import android.text.TextUtils;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080064import android.view.Gravity;
65import android.view.LayoutInflater;
66import android.view.View;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -050067import android.view.WindowManager;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080068import android.widget.ImageView;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080069import android.widget.TextView;
70import android.widget.Toast;
71
Peter Wang10da9292020-01-27 12:36:00 +080072import androidx.localbroadcastmanager.content.LocalBroadcastManager;
73
Peter Wangc94b8e62019-12-30 17:09:10 -080074import com.android.internal.telephony.GsmAlphabet;
Peter Wanga14d13d2020-01-15 14:13:51 -080075import com.android.internal.telephony.ITelephony;
Malcolm Chen616ea282019-10-24 19:53:48 -070076import com.android.internal.telephony.PhoneConfigurationManager;
Peter Wangc94b8e62019-12-30 17:09:10 -080077import com.android.internal.telephony.PhoneConstants;
Peter Wang10da9292020-01-27 12:36:00 +080078import com.android.internal.telephony.TelephonyIntents;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070079import com.android.internal.telephony.cat.AppInterface;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070080import com.android.internal.telephony.cat.CatCmdMessage;
81import com.android.internal.telephony.cat.CatCmdMessage.BrowserSettings;
Preeti Ahuja95919342013-10-01 18:18:55 -070082import com.android.internal.telephony.cat.CatCmdMessage.SetupEventListSettings;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070083import com.android.internal.telephony.cat.CatLog;
84import com.android.internal.telephony.cat.CatResponseMessage;
Peter Wangc94b8e62019-12-30 17:09:10 -080085import com.android.internal.telephony.cat.CatService;
86import com.android.internal.telephony.cat.Input;
87import com.android.internal.telephony.cat.Item;
88import com.android.internal.telephony.cat.Menu;
89import com.android.internal.telephony.cat.ResultCode;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -070090import com.android.internal.telephony.cat.TextMessage;
Srikanth Chintala89aa6602014-03-14 16:26:57 +053091import com.android.internal.telephony.cat.ToneSettings;
Wink Saville94e982b2014-07-11 07:38:14 -070092import com.android.internal.telephony.uicc.IccRefreshResponse;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080093
94import java.util.LinkedList;
Wink Savillee68857d2014-10-17 15:23:05 -070095import java.util.List;
Preeti Ahuja95919342013-10-01 18:18:55 -070096
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080097/**
98 * SIM toolkit application level service. Interacts with Telephopny messages,
99 * application's launch and user input from STK UI elements.
Wink Saville79085fc2009-06-09 10:27:23 -0700100 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800101 */
102public class StkAppService extends Service implements Runnable {
103
104 // members
Wink Savillee68857d2014-10-17 15:23:05 -0700105 protected class StkContext {
106 protected CatCmdMessage mMainCmd = null;
107 protected CatCmdMessage mCurrentCmd = null;
108 protected CatCmdMessage mCurrentMenuCmd = null;
109 protected Menu mCurrentMenu = null;
110 protected String lastSelectedItem = null;
111 protected boolean mMenuIsVisible = false;
112 protected boolean mIsInputPending = false;
113 protected boolean mIsMenuPending = false;
114 protected boolean mIsDialogPending = false;
Yuta Uife965802017-11-07 20:12:37 +0900115 protected boolean mNotificationOnKeyguard = false;
116 protected boolean mNoResponseFromUser = false;
Wink Savillee68857d2014-10-17 15:23:05 -0700117 protected boolean launchBrowser = false;
118 protected BrowserSettings mBrowserSettings = null;
119 protected LinkedList<DelayedCmd> mCmdsQ = null;
120 protected boolean mCmdInProgress = false;
121 protected int mStkServiceState = STATE_UNKNOWN;
Wink Savillee68857d2014-10-17 15:23:05 -0700122 protected int mMenuState = StkMenuActivity.STATE_INIT;
123 protected int mOpCode = -1;
124 private Activity mActivityInstance = null;
125 private Activity mDialogInstance = null;
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +0900126 private Activity mImmediateDialogInstance = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700127 private int mSlotId = 0;
Preeti Ahuja95919342013-10-01 18:18:55 -0700128 private SetupEventListSettings mSetupEventListSettings = null;
129 private boolean mClearSelectItem = false;
130 private boolean mDisplayTextDlgIsVisibile = false;
131 private CatCmdMessage mCurrentSetupEventCmd = null;
Preeti Ahuja560be362014-11-25 19:38:24 -0800132 private CatCmdMessage mIdleModeTextCmd = null;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900133 private boolean mIdleModeTextVisible = false;
Takanori Nakano43dacc02018-07-26 11:27:39 +0900134 // Determins whether the current session was initiated by user operation.
135 protected boolean mIsSessionFromUser = false;
Wink Savillee68857d2014-10-17 15:23:05 -0700136 final synchronized void setPendingActivityInstance(Activity act) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900137 CatLog.d(LOG_TAG, "setPendingActivityInstance act : " + mSlotId + ", " + act);
Wink Savillee68857d2014-10-17 15:23:05 -0700138 callSetActivityInstMsg(OP_SET_ACT_INST, mSlotId, act);
139 }
140 final synchronized Activity getPendingActivityInstance() {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900141 CatLog.d(LOG_TAG, "getPendingActivityInstance act : " + mSlotId + ", " +
Wink Savillee68857d2014-10-17 15:23:05 -0700142 mActivityInstance);
143 return mActivityInstance;
144 }
145 final synchronized void setPendingDialogInstance(Activity act) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900146 CatLog.d(LOG_TAG, "setPendingDialogInstance act : " + mSlotId + ", " + act);
Wink Savillee68857d2014-10-17 15:23:05 -0700147 callSetActivityInstMsg(OP_SET_DAL_INST, mSlotId, act);
148 }
149 final synchronized Activity getPendingDialogInstance() {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900150 CatLog.d(LOG_TAG, "getPendingDialogInstance act : " + mSlotId + ", " +
Wink Savillee68857d2014-10-17 15:23:05 -0700151 mDialogInstance);
152 return mDialogInstance;
153 }
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +0900154 final synchronized void setImmediateDialogInstance(Activity act) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900155 CatLog.d(LOG_TAG, "setImmediateDialogInstance act : " + mSlotId + ", " + act);
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +0900156 callSetActivityInstMsg(OP_SET_IMMED_DAL_INST, mSlotId, act);
157 }
158 final synchronized Activity getImmediateDialogInstance() {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900159 CatLog.d(LOG_TAG, "getImmediateDialogInstance act : " + mSlotId + ", " +
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +0900160 mImmediateDialogInstance);
161 return mImmediateDialogInstance;
162 }
Wink Savillee68857d2014-10-17 15:23:05 -0700163 }
164
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800165 private volatile Looper mServiceLooper;
166 private volatile ServiceHandler mServiceHandler;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800167 private Context mContext = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800168 private NotificationManager mNotificationManager = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800169 static StkAppService sInstance = null;
Wink Savillee68857d2014-10-17 15:23:05 -0700170 private AppInterface[] mStkService = null;
171 private StkContext[] mStkContext = null;
172 private int mSimCount = 0;
Hall Liu9d5d5ee2020-10-06 14:15:40 -0700173 private HomeVisibilityListener mHomeVisibilityListener = null;
Yoshiaki Naka0c2d2ba2017-11-17 21:51:55 +0900174 private BroadcastReceiver mLocaleChangeReceiver = null;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530175 private TonePlayer mTonePlayer = null;
176 private Vibrator mVibrator = null;
Yoshiaki Nakafb997252017-09-19 20:14:58 +0900177 private BroadcastReceiver mUserActivityReceiver = null;
arunvoddu8c8f5042022-05-23 09:38:20 +0000178 private AlertDialog mAlertDialog = null;
Preeti Ahuja95919342013-10-01 18:18:55 -0700179
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800180 // Used for setting FLAG_ACTIVITY_NO_USER_ACTION when
181 // creating an intent.
182 private enum InitiatedByUserAction {
183 yes, // The action was started via a user initiated action
184 unknown, // Not known for sure if user initated the action
185 }
186
187 // constants
188 static final String OPCODE = "op";
189 static final String CMD_MSG = "cmd message";
190 static final String RES_ID = "response id";
191 static final String MENU_SELECTION = "menu selection";
192 static final String INPUT = "input";
193 static final String HELP = "help";
194 static final String CONFIRMATION = "confirm";
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500195 static final String CHOICE = "choice";
Wink Savillee68857d2014-10-17 15:23:05 -0700196 static final String SLOT_ID = "SLOT_ID";
197 static final String STK_CMD = "STK CMD";
198 static final String STK_DIALOG_URI = "stk://com.android.stk/dialog/";
199 static final String STK_MENU_URI = "stk://com.android.stk/menu/";
200 static final String STK_INPUT_URI = "stk://com.android.stk/input/";
201 static final String STK_TONE_URI = "stk://com.android.stk/tone/";
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530202 static final String FINISH_TONE_ACTIVITY_ACTION =
203 "android.intent.action.stk.finish_activity";
Preeti Ahuja95919342013-10-01 18:18:55 -0700204
205 // These below constants are used for SETUP_EVENT_LIST
206 static final String SETUP_EVENT_TYPE = "event";
207 static final String SETUP_EVENT_CAUSE = "cause";
208
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800209 // operations ids for different service functionality.
210 static final int OP_CMD = 1;
211 static final int OP_RESPONSE = 2;
212 static final int OP_LAUNCH_APP = 3;
213 static final int OP_END_SESSION = 4;
214 static final int OP_BOOT_COMPLETED = 5;
215 private static final int OP_DELAYED_MSG = 6;
Wink Saville94e982b2014-07-11 07:38:14 -0700216 static final int OP_CARD_STATUS_CHANGED = 7;
Wink Savillee68857d2014-10-17 15:23:05 -0700217 static final int OP_SET_ACT_INST = 8;
218 static final int OP_SET_DAL_INST = 9;
Ryuto Sawada08c821c2016-08-08 18:29:02 +0900219 static final int OP_LOCALE_CHANGED = 10;
220 static final int OP_ALPHA_NOTIFY = 11;
221 static final int OP_IDLE_SCREEN = 12;
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +0900222 static final int OP_SET_IMMED_DAL_INST = 13;
Anna Suzukib1cee232019-02-21 12:52:27 +0900223 static final int OP_HOME_KEY_PRESSED = 14;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800224
Preeti Ahuja95919342013-10-01 18:18:55 -0700225 //Invalid SetupEvent
226 static final int INVALID_SETUP_EVENT = 0xFF;
227
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530228 // Message id to signal stop tone due to play tone timeout.
229 private static final int OP_STOP_TONE = 16;
230
231 // Message id to signal stop tone on user keyback.
232 static final int OP_STOP_TONE_USER = 17;
233
Yoshiaki Nakafb997252017-09-19 20:14:58 +0900234 // Message id to send user activity event to card.
235 private static final int OP_USER_ACTIVITY = 20;
236
Malcolm Chen616ea282019-10-24 19:53:48 -0700237 // Message id that multi-SIM config has changed (ss <-> ds).
238 private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 21;
239
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800240 // Response ids
241 static final int RES_ID_MENU_SELECTION = 11;
242 static final int RES_ID_INPUT = 12;
243 static final int RES_ID_CONFIRM = 13;
244 static final int RES_ID_DONE = 14;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500245 static final int RES_ID_CHOICE = 15;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800246
247 static final int RES_ID_TIMEOUT = 20;
248 static final int RES_ID_BACKWARD = 21;
249 static final int RES_ID_END_SESSION = 22;
250 static final int RES_ID_EXIT = 23;
Srikanth Chintalaba103002015-11-30 10:49:52 -0800251 static final int RES_ID_ERROR = 24;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800252
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500253 static final int YES = 1;
254 static final int NO = 0;
255
Wink Savillee68857d2014-10-17 15:23:05 -0700256 static final int STATE_UNKNOWN = -1;
257 static final int STATE_NOT_EXIST = 0;
258 static final int STATE_EXIST = 1;
Wink Saville79085fc2009-06-09 10:27:23 -0700259
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +0900260 private static final Integer PLAY_TONE_ONLY = 0;
261 private static final Integer PLAY_TONE_WITH_DIALOG = 1;
262
Wink Savillee68857d2014-10-17 15:23:05 -0700263 private static final String PACKAGE_NAME = "com.android.stk";
264 private static final String STK_MENU_ACTIVITY_NAME = PACKAGE_NAME + ".StkMenuActivity";
265 private static final String STK_INPUT_ACTIVITY_NAME = PACKAGE_NAME + ".StkInputActivity";
266 private static final String STK_DIALOG_ACTIVITY_NAME = PACKAGE_NAME + ".StkDialogActivity";
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800267 // Notification id used to display Idle Mode text in NotificationManager.
268 private static final int STK_NOTIFICATION_ID = 333;
fionaxu2c91c752017-04-21 18:11:57 -0700269 // Notification channel containing all mobile service messages notifications.
270 private static final String STK_NOTIFICATION_CHANNEL_ID = "mobileServiceMessages";
271
Jared Dukebec572d2022-04-13 13:13:52 -0700272 private static final String LOG_TAG = StkAppService.class.getSimpleName();
Wink Saville79085fc2009-06-09 10:27:23 -0700273
Takanori Nakano3776e2c2016-10-14 16:54:28 +0900274 static final String SESSION_ENDED = "session_ended";
275
Wink Saville79085fc2009-06-09 10:27:23 -0700276 // Inner class used for queuing telephony messages (proactive commands,
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800277 // session end) while the service is busy processing a previous message.
278 private class DelayedCmd {
279 // members
280 int id;
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700281 CatCmdMessage msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700282 int slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800283
Wink Savillee68857d2014-10-17 15:23:05 -0700284 DelayedCmd(int id, CatCmdMessage msg, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800285 this.id = id;
286 this.msg = msg;
Wink Savillee68857d2014-10-17 15:23:05 -0700287 this.slotId = slotId;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800288 }
289 }
290
Preeti Ahujaa7cdca22013-10-01 18:20:56 -0700291 // system property to set the STK specific default url for launch browser proactive cmds
292 private static final String STK_BROWSER_DEFAULT_URL_SYSPROP = "persist.radio.stk.default_url";
293
Yuta Uife965802017-11-07 20:12:37 +0900294 private static final int NOTIFICATION_ON_KEYGUARD = 1;
295 private static final long[] VIBRATION_PATTERN = new long[] { 0, 350, 250, 350 };
296 private BroadcastReceiver mUserPresentReceiver = null;
297
Anna Suzukib1cee232019-02-21 12:52:27 +0900298 // The reason based on Intent.ACTION_CLOSE_SYSTEM_DIALOGS.
299 private static final String SYSTEM_DIALOG_REASON_KEY = "reason";
300 private static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
Jordan Liu79fa1022020-08-04 11:34:03 -0700301 private static final String SYSTEM_DIALOG_REASON_RECENTAPPS_KEY = "recentapps";
Anna Suzukib1cee232019-02-21 12:52:27 +0900302 private BroadcastReceiver mHomeKeyEventReceiver = null;
303
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800304 @Override
305 public void onCreate() {
Wink Savillee68857d2014-10-17 15:23:05 -0700306 CatLog.d(LOG_TAG, "onCreate()+");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800307 // Initialize members
Wink Savillee68857d2014-10-17 15:23:05 -0700308 int i = 0;
309 mContext = getBaseContext();
Malcolm Chen616ea282019-10-24 19:53:48 -0700310 mSimCount = TelephonyManager.from(mContext).getActiveModemCount();
311 int maxSimCount = TelephonyManager.from(mContext).getSupportedModemCount();
Wink Savillee68857d2014-10-17 15:23:05 -0700312 CatLog.d(LOG_TAG, "simCount: " + mSimCount);
Malcolm Chen616ea282019-10-24 19:53:48 -0700313 mStkService = new AppInterface[maxSimCount];
314 mStkContext = new StkContext[maxSimCount];
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900315
Wink Savillee68857d2014-10-17 15:23:05 -0700316 for (i = 0; i < mSimCount; i++) {
317 CatLog.d(LOG_TAG, "slotId: " + i);
Legler Wuaeefef52014-10-27 00:57:18 +0800318 mStkService[i] = CatService.getInstance(i);
Wink Savillee68857d2014-10-17 15:23:05 -0700319 mStkContext[i] = new StkContext();
320 mStkContext[i].mSlotId = i;
321 mStkContext[i].mCmdsQ = new LinkedList<DelayedCmd>();
322 }
323
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800324 Thread serviceThread = new Thread(null, this, "Stk App Service");
325 serviceThread.start();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800326 mNotificationManager = (NotificationManager) mContext
327 .getSystemService(Context.NOTIFICATION_SERVICE);
328 sInstance = this;
329 }
330
331 @Override
332 public void onStart(Intent intent, int startId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700333 if (intent == null) {
334 CatLog.d(LOG_TAG, "StkAppService onStart intent is null so return");
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530335 return;
336 }
337
Wink Savillee68857d2014-10-17 15:23:05 -0700338 Bundle args = intent.getExtras();
339 if (args == null) {
340 CatLog.d(LOG_TAG, "StkAppService onStart args is null so return");
341 return;
342 }
343
344 int op = args.getInt(OPCODE);
345 int slotId = 0;
346 int i = 0;
347 if (op != OP_BOOT_COMPLETED) {
348 slotId = args.getInt(SLOT_ID);
349 }
Cuihtlauac ALVARADObde7f032015-05-29 16:25:12 +0200350 CatLog.d(LOG_TAG, "onStart sim id: " + slotId + ", op: " + op + ", *****");
Wink Savillee68857d2014-10-17 15:23:05 -0700351 if ((slotId >= 0 && slotId < mSimCount) && mStkService[slotId] == null) {
Legler Wuaeefef52014-10-27 00:57:18 +0800352 mStkService[slotId] = CatService.getInstance(slotId);
Wink Savillee68857d2014-10-17 15:23:05 -0700353 if (mStkService[slotId] == null) {
354 CatLog.d(LOG_TAG, "mStkService is: " + mStkContext[slotId].mStkServiceState);
355 mStkContext[slotId].mStkServiceState = STATE_NOT_EXIST;
356 //Check other StkService state.
357 //If all StkServices are not available, stop itself and uninstall apk.
Yoshiaki Naka8b960fb2019-10-31 10:44:07 +0900358 for (i = 0; i < mSimCount; i++) {
Wink Savillee68857d2014-10-17 15:23:05 -0700359 if (i != slotId
Tsukasa Goto029332b2016-10-05 17:12:06 +0900360 && (mStkService[i] != null)
Wink Savillee68857d2014-10-17 15:23:05 -0700361 && (mStkContext[i].mStkServiceState == STATE_UNKNOWN
362 || mStkContext[i].mStkServiceState == STATE_EXIST)) {
363 break;
364 }
365 }
366 } else {
367 mStkContext[slotId].mStkServiceState = STATE_EXIST;
368 }
369 if (i == mSimCount) {
370 stopSelf();
Yoshiaki Naka835e3002020-05-11 18:15:12 +0900371 StkAppInstaller.uninstall(this);
Wink Savillee68857d2014-10-17 15:23:05 -0700372 return;
373 }
374 }
375
Banavathu, Srinivas Naik87cda962012-07-17 15:32:44 +0530376 waitForLooper();
John Wang62acae42009-10-08 11:20:23 -0700377
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +0900378 Message msg = mServiceHandler.obtainMessage(op, 0, slotId);
379 switch (op) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800380 case OP_CMD:
381 msg.obj = args.getParcelable(CMD_MSG);
382 break;
383 case OP_RESPONSE:
Wink Saville94e982b2014-07-11 07:38:14 -0700384 case OP_CARD_STATUS_CHANGED:
Preeti Ahuja95919342013-10-01 18:18:55 -0700385 case OP_LOCALE_CHANGED:
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530386 case OP_ALPHA_NOTIFY:
Preeti Ahuja560be362014-11-25 19:38:24 -0800387 case OP_IDLE_SCREEN:
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +0900388 case OP_STOP_TONE_USER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800389 msg.obj = args;
390 /* falls through */
391 case OP_LAUNCH_APP:
392 case OP_END_SESSION:
393 case OP_BOOT_COMPLETED:
394 break;
395 default:
396 return;
397 }
398 mServiceHandler.sendMessage(msg);
399 }
400
401 @Override
402 public void onDestroy() {
Wink Savillee68857d2014-10-17 15:23:05 -0700403 CatLog.d(LOG_TAG, "onDestroy()");
Yoshiaki Nakafb997252017-09-19 20:14:58 +0900404 unregisterUserActivityReceiver();
Malcolm Chen549e21a2020-01-10 15:57:10 -0800405 unregisterHomeVisibilityObserver();
Yoshiaki Naka0c2d2ba2017-11-17 21:51:55 +0900406 unregisterLocaleChangeReceiver();
Anna Suzukib1cee232019-02-21 12:52:27 +0900407 unregisterHomeKeyEventReceiver();
arunvoddu8c8f5042022-05-23 09:38:20 +0000408 // close the AlertDialog if any is showing upon sim remove etc cases
409 if (mAlertDialog != null && mAlertDialog.isShowing()) {
410 mAlertDialog.dismiss();
411 mAlertDialog = null;
412 }
Tsukasa Gotou54afbdd2016-01-07 16:30:20 +0900413 sInstance = null;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800414 waitForLooper();
Yoshiaki Nakaf70e3732020-01-24 18:57:22 +0900415 PhoneConfigurationManager.unregisterForMultiSimConfigChange(mServiceHandler);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800416 mServiceLooper.quit();
417 }
418
419 @Override
420 public IBinder onBind(Intent intent) {
421 return null;
422 }
423
424 public void run() {
425 Looper.prepare();
426
427 mServiceLooper = Looper.myLooper();
428 mServiceHandler = new ServiceHandler();
429
Yoshiaki Nakaf70e3732020-01-24 18:57:22 +0900430 PhoneConfigurationManager.registerForMultiSimConfigChange(mServiceHandler,
431 EVENT_MULTI_SIM_CONFIG_CHANGED, null);
432
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800433 Looper.loop();
434 }
435
436 /*
437 * Package api used by StkMenuActivity to indicate if its on the foreground.
438 */
Malcolm Chen616ea282019-10-24 19:53:48 -0700439 synchronized void indicateMenuVisibility(boolean visibility, int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700440 if (slotId >= 0 && slotId < mSimCount) {
441 mStkContext[slotId].mMenuIsVisible = visibility;
442 }
443 }
444
Preeti Ahuja95919342013-10-01 18:18:55 -0700445 /*
446 * Package api used by StkDialogActivity to indicate if its on the foreground.
447 */
Malcolm Chen616ea282019-10-24 19:53:48 -0700448 synchronized void setDisplayTextDlgVisibility(boolean visibility, int slotId) {
Preeti Ahuja95919342013-10-01 18:18:55 -0700449 if (slotId >= 0 && slotId < mSimCount) {
450 mStkContext[slotId].mDisplayTextDlgIsVisibile = visibility;
451 }
452 }
453
Malcolm Chen616ea282019-10-24 19:53:48 -0700454 synchronized boolean isInputPending(int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700455 if (slotId >= 0 && slotId < mSimCount) {
456 CatLog.d(LOG_TAG, "isInputFinishBySrv: " + mStkContext[slotId].mIsInputPending);
457 return mStkContext[slotId].mIsInputPending;
458 }
459 return false;
460 }
461
Malcolm Chen616ea282019-10-24 19:53:48 -0700462 synchronized boolean isMenuPending(int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700463 if (slotId >= 0 && slotId < mSimCount) {
464 CatLog.d(LOG_TAG, "isMenuPending: " + mStkContext[slotId].mIsMenuPending);
465 return mStkContext[slotId].mIsMenuPending;
466 }
467 return false;
468 }
469
Malcolm Chen616ea282019-10-24 19:53:48 -0700470 synchronized boolean isDialogPending(int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700471 if (slotId >= 0 && slotId < mSimCount) {
472 CatLog.d(LOG_TAG, "isDialogPending: " + mStkContext[slotId].mIsDialogPending);
473 return mStkContext[slotId].mIsDialogPending;
474 }
475 return false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800476 }
477
Malcolm Chen616ea282019-10-24 19:53:48 -0700478 synchronized boolean isMainMenuAvailable(int slotId) {
Takanori Nakano3776e2c2016-10-14 16:54:28 +0900479 if (slotId >= 0 && slotId < mSimCount) {
480 // The main menu can handle the next user operation if the previous session finished.
481 return (mStkContext[slotId].lastSelectedItem == null) ? true : false;
482 }
483 return false;
484 }
485
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800486 /*
487 * Package api used by StkMenuActivity to get its Menu parameter.
488 */
Malcolm Chen616ea282019-10-24 19:53:48 -0700489 synchronized Menu getMenu(int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700490 CatLog.d(LOG_TAG, "StkAppService, getMenu, sim id: " + slotId);
491 if (slotId >=0 && slotId < mSimCount) {
492 return mStkContext[slotId].mCurrentMenu;
493 } else {
494 return null;
495 }
496 }
497
498 /*
499 * Package api used by StkMenuActivity to get its Main Menu parameter.
500 */
Malcolm Chen616ea282019-10-24 19:53:48 -0700501 synchronized Menu getMainMenu(int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -0700502 CatLog.d(LOG_TAG, "StkAppService, getMainMenu, sim id: " + slotId);
w30234a08cffe2015-02-04 15:13:25 -0800503 if (slotId >=0 && slotId < mSimCount && (mStkContext[slotId].mMainCmd != null)) {
Takanori Nakanoc8054ba2016-08-15 19:18:16 +0900504 Menu menu = mStkContext[slotId].mMainCmd.getMenu();
Yoshiaki Naka835e3002020-05-11 18:15:12 +0900505 if (menu != null) {
Takanori Nakanoc8054ba2016-08-15 19:18:16 +0900506 // If alpha identifier or icon identifier with the self-explanatory qualifier is
507 // specified in SET-UP MENU command, it should be more prioritized than preset ones.
508 if (menu.title == null
509 && (menu.titleIcon == null || !menu.titleIconSelfExplanatory)) {
510 StkMenuConfig config = StkMenuConfig.getInstance(getApplicationContext());
511 String label = config.getLabel(slotId);
512 Bitmap icon = config.getIcon(slotId);
513 if (label != null || icon != null) {
514 Parcel parcel = Parcel.obtain();
515 menu.writeToParcel(parcel, 0);
516 parcel.setDataPosition(0);
517 menu = Menu.CREATOR.createFromParcel(parcel);
518 parcel.recycle();
519 menu.title = label;
520 menu.titleIcon = icon;
521 menu.titleIconSelfExplanatory = false;
522 }
523 }
524 }
525 return menu;
Wink Savillee68857d2014-10-17 15:23:05 -0700526 } else {
527 return null;
528 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800529 }
530
531 /*
532 * Package api used by UI Activities and Dialogs to communicate directly
533 * with the service to deliver state information and parameters.
534 */
535 static StkAppService getInstance() {
536 return sInstance;
537 }
538
539 private void waitForLooper() {
540 while (mServiceHandler == null) {
541 synchronized (this) {
542 try {
543 wait(100);
544 } catch (InterruptedException e) {
545 }
546 }
547 }
548 }
549
550 private final class ServiceHandler extends Handler {
551 @Override
552 public void handleMessage(Message msg) {
Wink Savillee68857d2014-10-17 15:23:05 -0700553 if(null == msg) {
554 CatLog.d(LOG_TAG, "ServiceHandler handleMessage msg is null");
555 return;
556 }
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +0900557 int opcode = msg.what;
Wink Savillee68857d2014-10-17 15:23:05 -0700558 int slotId = msg.arg2;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800559
Wink Savillee68857d2014-10-17 15:23:05 -0700560 CatLog.d(LOG_TAG, "handleMessage opcode[" + opcode + "], sim id[" + slotId + "]");
561 if (opcode == OP_CMD && msg.obj != null &&
562 ((CatCmdMessage)msg.obj).getCmdType()!= null) {
563 CatLog.d(LOG_TAG, "cmdName[" + ((CatCmdMessage)msg.obj).getCmdType().name() + "]");
564 }
Malcolm Chen7a9f2ad2019-11-06 11:07:09 -0800565 if (slotId >= mStkContext.length || mStkContext[slotId] == null) {
566 CatLog.d(LOG_TAG, "invalid slotId " + slotId);
567 return;
568 }
Malcolm Chen5e576402019-11-05 16:09:18 -0800569
Wink Savillee68857d2014-10-17 15:23:05 -0700570 mStkContext[slotId].mOpCode = opcode;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800571 switch (opcode) {
572 case OP_LAUNCH_APP:
Wink Savillee68857d2014-10-17 15:23:05 -0700573 if (mStkContext[slotId].mMainCmd == null) {
574 CatLog.d(LOG_TAG, "mMainCmd is null");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800575 // nothing todo when no SET UP MENU command didn't arrive.
576 return;
577 }
Wink Savillee68857d2014-10-17 15:23:05 -0700578 CatLog.d(LOG_TAG, "handleMessage OP_LAUNCH_APP - mCmdInProgress[" +
579 mStkContext[slotId].mCmdInProgress + "]");
580
581 //If there is a pending activity for the slot id,
582 //just finish it and create a new one to handle the pending command.
583 cleanUpInstanceStackBySlot(slotId);
584
Wink Savillee68857d2014-10-17 15:23:05 -0700585 CatLog.d(LOG_TAG, "Current cmd type: " +
586 mStkContext[slotId].mCurrentCmd.getCmdType());
587 //Restore the last command from stack by slot id.
588 restoreInstanceFromStackBySlot(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800589 break;
590 case OP_CMD:
Wink Savillee68857d2014-10-17 15:23:05 -0700591 CatLog.d(LOG_TAG, "[OP_CMD]");
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700592 CatCmdMessage cmdMsg = (CatCmdMessage) msg.obj;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800593 // There are two types of commands:
594 // 1. Interactive - user's response is required.
595 // 2. Informative - display a message, no interaction with the user.
596 //
Wink Saville79085fc2009-06-09 10:27:23 -0700597 // Informative commands can be handled immediately without any delay.
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800598 // Interactive commands can't override each other. So if a command
599 // is already in progress, we need to queue the next command until
600 // the user has responded or a timeout expired.
601 if (!isCmdInteractive(cmdMsg)) {
Wink Savillee68857d2014-10-17 15:23:05 -0700602 handleCmd(cmdMsg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800603 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700604 if (!mStkContext[slotId].mCmdInProgress) {
605 mStkContext[slotId].mCmdInProgress = true;
606 handleCmd((CatCmdMessage) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800607 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700608 CatLog.d(LOG_TAG, "[Interactive][in progress]");
609 mStkContext[slotId].mCmdsQ.addLast(new DelayedCmd(OP_CMD,
610 (CatCmdMessage) msg.obj, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800611 }
612 }
613 break;
614 case OP_RESPONSE:
Preeti Ahuja414bc412013-06-25 19:31:49 -0700615 handleCmdResponse((Bundle) msg.obj, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800616 // call delayed commands if needed.
Wink Savillee68857d2014-10-17 15:23:05 -0700617 if (mStkContext[slotId].mCmdsQ.size() != 0) {
618 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800619 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700620 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800621 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800622 break;
623 case OP_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -0700624 if (!mStkContext[slotId].mCmdInProgress) {
625 mStkContext[slotId].mCmdInProgress = true;
626 handleSessionEnd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800627 } else {
Wink Savillee68857d2014-10-17 15:23:05 -0700628 mStkContext[slotId].mCmdsQ.addLast(
629 new DelayedCmd(OP_END_SESSION, null, slotId));
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800630 }
631 break;
632 case OP_BOOT_COMPLETED:
Wink Savillee68857d2014-10-17 15:23:05 -0700633 CatLog.d(LOG_TAG, " OP_BOOT_COMPLETED");
Yoshiaki Naka58e07652019-04-26 17:58:52 +0900634 uninstallIfUnnecessary();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800635 break;
636 case OP_DELAYED_MSG:
Wink Savillee68857d2014-10-17 15:23:05 -0700637 handleDelayedCmd(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800638 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700639 case OP_CARD_STATUS_CHANGED:
Wink Savillee68857d2014-10-17 15:23:05 -0700640 CatLog.d(LOG_TAG, "Card/Icc Status change received");
641 handleCardStatusChangeAndIccRefresh((Bundle) msg.obj, slotId);
642 break;
643 case OP_SET_ACT_INST:
Yoshiaki Naka28d7a722017-10-24 17:32:16 +0900644 Activity act = (Activity) msg.obj;
645 if (mStkContext[slotId].mActivityInstance != act) {
Yoshiaki Naka03a79d92018-08-09 18:41:31 +0900646 CatLog.d(LOG_TAG, "Set pending activity instance - " + act);
Yoshiaki Naka28d7a722017-10-24 17:32:16 +0900647 Activity previous = mStkContext[slotId].mActivityInstance;
648 mStkContext[slotId].mActivityInstance = act;
Yoshiaki Naka03a79d92018-08-09 18:41:31 +0900649 // Finish the previous one if it was replaced with new one
650 // but it has not been finished yet somehow.
651 if (act != null && previous != null && !previous.isDestroyed()
652 && !previous.isFinishing()) {
Yoshiaki Naka28d7a722017-10-24 17:32:16 +0900653 CatLog.d(LOG_TAG, "Finish the previous pending activity - " + previous);
654 previous.finish();
655 }
Anna Suzuki35309b02019-02-15 16:24:59 +0900656 }
657 // Clear pending dialog instance if it has not been cleared yet.
658 Activity dialog = mStkContext[slotId].getPendingDialogInstance();
659 if (dialog != null && (dialog.isDestroyed() || dialog.isFinishing())) {
660 CatLog.d(LOG_TAG, "Clear pending dialog instance - " + dialog);
661 mStkContext[slotId].mDialogInstance = null;
Yoshiaki Naka28d7a722017-10-24 17:32:16 +0900662 }
Wink Savillee68857d2014-10-17 15:23:05 -0700663 break;
664 case OP_SET_DAL_INST:
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +0900665 Activity dal = (Activity) msg.obj;
Yoshiaki Nakaa1cea462018-08-09 20:33:36 +0900666 if (mStkContext[slotId].mDialogInstance != dal) {
667 CatLog.d(LOG_TAG, "Set pending dialog instance - " + dal);
668 mStkContext[slotId].mDialogInstance = dal;
669 }
Wink Savillee68857d2014-10-17 15:23:05 -0700670 break;
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +0900671 case OP_SET_IMMED_DAL_INST:
672 Activity immedDal = (Activity) msg.obj;
673 CatLog.d(LOG_TAG, "Set dialog instance for immediate response. " + immedDal);
674 mStkContext[slotId].mImmediateDialogInstance = immedDal;
675 break;
Preeti Ahuja95919342013-10-01 18:18:55 -0700676 case OP_LOCALE_CHANGED:
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900677 CatLog.d(LOG_TAG, "Locale Changed");
Yoshiaki Naka8b960fb2019-10-31 10:44:07 +0900678 for (int slot = 0; slot < mSimCount; slot++) {
Yuta Ui1481b172016-02-03 15:34:31 +0900679 checkForSetupEvent(LANGUAGE_SELECTION_EVENT, (Bundle) msg.obj, slot);
680 }
fionaxu805eb572017-05-02 10:57:30 -0700681 // rename all registered notification channels on locale change
682 createAllChannels();
Preeti Ahuja95919342013-10-01 18:18:55 -0700683 break;
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +0530684 case OP_ALPHA_NOTIFY:
685 handleAlphaNotify((Bundle) msg.obj);
686 break;
Preeti Ahuja560be362014-11-25 19:38:24 -0800687 case OP_IDLE_SCREEN:
688 for (int slot = 0; slot < mSimCount; slot++) {
689 if (mStkContext[slot] != null) {
690 handleIdleScreen(slot);
691 }
692 }
693 break;
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530694 case OP_STOP_TONE_USER:
695 case OP_STOP_TONE:
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900696 CatLog.d(LOG_TAG, "Stop tone");
Srikanth Chintala89aa6602014-03-14 16:26:57 +0530697 handleStopTone(msg, slotId);
698 break;
Yoshiaki Nakafb997252017-09-19 20:14:58 +0900699 case OP_USER_ACTIVITY:
Yoshiaki Naka8b960fb2019-10-31 10:44:07 +0900700 for (int slot = 0; slot < mSimCount; slot++) {
Yoshiaki Nakafb997252017-09-19 20:14:58 +0900701 checkForSetupEvent(USER_ACTIVITY_EVENT, null, slot);
702 }
703 break;
Malcolm Chen616ea282019-10-24 19:53:48 -0700704 case EVENT_MULTI_SIM_CONFIG_CHANGED:
705 handleMultiSimConfigChanged();
706 break;
Anna Suzukib1cee232019-02-21 12:52:27 +0900707 case OP_HOME_KEY_PRESSED:
708 CatLog.d(LOG_TAG, "Process the home key pressed event");
709 for (int slot = 0; slot < mSimCount; slot++) {
710 if (mStkContext[slot] != null) {
711 handleHomeKeyPressed(slot);
712 }
713 }
714 break;
Wink Saville94e982b2014-07-11 07:38:14 -0700715 }
716 }
717
Wink Savillee68857d2014-10-17 15:23:05 -0700718 private void handleCardStatusChangeAndIccRefresh(Bundle args, int slotId) {
Wink Saville94e982b2014-07-11 07:38:14 -0700719 boolean cardStatus = args.getBoolean(AppInterface.CARD_STATUS);
720
Wink Savillee68857d2014-10-17 15:23:05 -0700721 CatLog.d(LOG_TAG, "CardStatus: " + cardStatus);
Wink Saville94e982b2014-07-11 07:38:14 -0700722 if (cardStatus == false) {
Wink Savillee68857d2014-10-17 15:23:05 -0700723 CatLog.d(LOG_TAG, "CARD is ABSENT");
Wink Saville94e982b2014-07-11 07:38:14 -0700724 // Uninstall STKAPP, Clear Idle text, Stop StkAppService
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900725 cancelIdleText(slotId);
Srikanth Chintala7c5a04c2016-09-22 19:05:01 +0530726 mStkContext[slotId].mCurrentMenu = null;
727 mStkContext[slotId].mMainCmd = null;
Sandeep Gutta670b7a92018-09-17 18:55:34 +0530728 mStkService[slotId] = null;
Takanori Nakanob82c8752019-04-01 14:47:07 +0900729 // Stop the tone currently being played if the relevant SIM is removed or disabled.
730 if (mStkContext[slotId].mCurrentCmd != null
731 && mStkContext[slotId].mCurrentCmd.getCmdType().value()
732 == AppInterface.CommandType.PLAY_TONE.value()) {
733 terminateTone(slotId);
734 }
Yoshiaki Naka2d10bbb2019-05-09 15:35:21 +0900735 if (!uninstallIfUnnecessary()) {
736 addToMenuSystemOrUpdateLabel();
737 }
Wink Savillee68857d2014-10-17 15:23:05 -0700738 if (isAllOtherCardsAbsent(slotId)) {
739 CatLog.d(LOG_TAG, "All CARDs are ABSENT");
Wink Savillee68857d2014-10-17 15:23:05 -0700740 stopSelf();
741 }
Wink Saville94e982b2014-07-11 07:38:14 -0700742 } else {
743 IccRefreshResponse state = new IccRefreshResponse();
744 state.refreshResult = args.getInt(AppInterface.REFRESH_RESULT);
745
Wink Savillee68857d2014-10-17 15:23:05 -0700746 CatLog.d(LOG_TAG, "Icc Refresh Result: "+ state.refreshResult);
Wink Saville94e982b2014-07-11 07:38:14 -0700747 if ((state.refreshResult == IccRefreshResponse.REFRESH_RESULT_INIT) ||
748 (state.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET)) {
749 // Clear Idle Text
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900750 cancelIdleText(slotId);
Wink Saville94e982b2014-07-11 07:38:14 -0700751 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800752 }
753 }
754 }
Malcolm Chen616ea282019-10-24 19:53:48 -0700755
756 private synchronized void handleMultiSimConfigChanged() {
757 int oldSimCount = mSimCount;
758 mSimCount = TelephonyManager.from(mContext).getActiveModemCount();
759 for (int i = oldSimCount; i < mSimCount; i++) {
760 CatLog.d(LOG_TAG, "slotId: " + i);
761 mStkService[i] = CatService.getInstance(i);
762 mStkContext[i] = new StkContext();
763 mStkContext[i].mSlotId = i;
764 mStkContext[i].mCmdsQ = new LinkedList<DelayedCmd>();
765 }
766
767 for (int i = mSimCount; i < oldSimCount; i++) {
768 CatLog.d(LOG_TAG, "slotId: " + i);
769 if (mStkService[i] != null) {
770 mStkService[i].dispose();
771 mStkService[i] = null;
772 }
773 mStkContext[i] = null;
774 }
775 }
776
Wink Savillee68857d2014-10-17 15:23:05 -0700777 /*
778 * Check if all SIMs are absent except the id of slot equals "slotId".
779 */
780 private boolean isAllOtherCardsAbsent(int slotId) {
781 TelephonyManager mTm = (TelephonyManager) mContext.getSystemService(
782 Context.TELEPHONY_SERVICE);
783 int i = 0;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800784
Wink Savillee68857d2014-10-17 15:23:05 -0700785 for (i = 0; i < mSimCount; i++) {
786 if (i != slotId && mTm.hasIccCard(i)) {
787 break;
788 }
789 }
790 if (i == mSimCount) {
791 return true;
792 } else {
793 return false;
794 }
795 }
Preeti Ahuja95919342013-10-01 18:18:55 -0700796
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900797 /* package */ boolean isScreenIdle() {
798 ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
799 List<RunningTaskInfo> tasks = am.getRunningTasks(1);
800 if (tasks == null || tasks.isEmpty()) {
801 return false;
802 }
803
804 String top = tasks.get(0).topActivity.getPackageName();
805 if (top == null) {
806 return false;
807 }
808
809 // We can assume that the screen is idle if the home application is in the foreground.
810 final Intent intent = new Intent(Intent.ACTION_MAIN, null);
811 intent.addCategory(Intent.CATEGORY_HOME);
812
813 ResolveInfo info = getPackageManager().resolveActivity(intent,
814 PackageManager.MATCH_DEFAULT_ONLY);
815 if (info != null) {
816 if (top.equals(info.activityInfo.packageName)) {
817 return true;
818 }
819 }
820
821 return false;
Preeti Ahuja560be362014-11-25 19:38:24 -0800822 }
823
Anna Suzukib1cee232019-02-21 12:52:27 +0900824 private synchronized void startToObserveHomeKeyEvent(int slotId) {
825 if (mStkContext[slotId].mIsSessionFromUser || mHomeKeyEventReceiver != null) {
826 return;
827 }
828 mHomeKeyEventReceiver = new BroadcastReceiver() {
829 @Override public void onReceive(Context context, Intent intent) {
Jordan Liu79fa1022020-08-04 11:34:03 -0700830 final String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
831 // gesture-based launchers may interpret swipe-up as "recent apps" instead of
832 // "home" so we accept both here
833 if (SYSTEM_DIALOG_REASON_HOME_KEY.equals(reason)
834 || SYSTEM_DIALOG_REASON_RECENTAPPS_KEY.equals(reason)) {
Jordan Liu468951a2020-08-21 09:16:23 -0700835 Message message = mServiceHandler.obtainMessage(OP_HOME_KEY_PRESSED);
Anna Suzukib1cee232019-02-21 12:52:27 +0900836 mServiceHandler.sendMessage(message);
Takanori Nakano43dacc02018-07-26 11:27:39 +0900837 }
Anna Suzukib1cee232019-02-21 12:52:27 +0900838 }
839 };
840 CatLog.d(LOG_TAG, "Started to observe home key event");
841 registerReceiver(mHomeKeyEventReceiver,
Jacob Hobbiecd68c492021-11-02 21:25:18 +0000842 new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), Context.RECEIVER_EXPORTED);
Anna Suzukib1cee232019-02-21 12:52:27 +0900843 }
844
845 private synchronized void unregisterHomeKeyEventReceiver() {
846 if (mHomeKeyEventReceiver != null) {
847 CatLog.d(LOG_TAG, "Stopped to observe home key event");
848 unregisterReceiver(mHomeKeyEventReceiver);
849 mHomeKeyEventReceiver = null;
850 }
851 if (mServiceHandler != null) {
852 mServiceHandler.removeMessages(OP_HOME_KEY_PRESSED);
853 }
854 }
855
856 private void handleHomeKeyPressed(int slotId) {
857 // It might be hard for user to recognize that the dialog or screens belong to SIM Toolkit
858 // application if the current session was not initiated by user but by the SIM card,
859 // so it is recommended to send TERMINAL RESPONSE if user press the home key.
860 if (!mStkContext[slotId].mIsSessionFromUser) {
861 Activity dialog = mStkContext[slotId].getPendingDialogInstance();
862 Activity activity = mStkContext[slotId].getPendingActivityInstance();
863 if (dialog != null) {
864 dialog.finish();
865 mStkContext[slotId].mDialogInstance = null;
866 } else if (activity != null) {
867 activity.finish();
868 mStkContext[slotId].mActivityInstance = null;
Takanori Nakano43dacc02018-07-26 11:27:39 +0900869 }
870 }
871 }
Preeti Ahuja560be362014-11-25 19:38:24 -0800872
Takanori Nakano43dacc02018-07-26 11:27:39 +0900873 private void handleIdleScreen(int slotId) {
Preeti Ahuja560be362014-11-25 19:38:24 -0800874 // If the idle screen event is present in the list need to send the
875 // response to SIM.
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900876 CatLog.d(LOG_TAG, "Need to send IDLE SCREEN Available event to SIM");
Preeti Ahuja560be362014-11-25 19:38:24 -0800877 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId);
878
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +0900879 if (mStkContext[slotId].mIdleModeTextCmd != null
880 && !mStkContext[slotId].mIdleModeTextVisible) {
881 launchIdleText(slotId);
Preeti Ahuja560be362014-11-25 19:38:24 -0800882 }
883 }
884
885 private void sendScreenBusyResponse(int slotId) {
886 if (mStkContext[slotId].mCurrentCmd == null) {
887 return;
888 }
889 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
Yoshiaki Naka3a980db2019-10-30 17:11:33 +0900890 CatLog.d(LOG_TAG, "SCREEN_BUSY");
Preeti Ahuja560be362014-11-25 19:38:24 -0800891 resMsg.setResultCode(ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS);
892 mStkService[slotId].onCmdResponse(resMsg);
893 if (mStkContext[slotId].mCmdsQ.size() != 0) {
894 callDelayedMsg(slotId);
895 } else {
896 mStkContext[slotId].mCmdInProgress = false;
897 }
898 }
899
Takanori Nakano43dacc02018-07-26 11:27:39 +0900900 /**
901 * Sends TERMINAL RESPONSE or ENVELOPE
902 *
903 * @param args detailed parameters of the response
904 * @param slotId slot identifier
905 */
906 public void sendResponse(Bundle args, int slotId) {
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +0900907 Message msg = mServiceHandler.obtainMessage(OP_RESPONSE, 0, slotId, args);
Takanori Nakano43dacc02018-07-26 11:27:39 +0900908 mServiceHandler.sendMessage(msg);
909 }
910
Preeti Ahuja95919342013-10-01 18:18:55 -0700911 private void sendResponse(int resId, int slotId, boolean confirm) {
Preeti Ahuja95919342013-10-01 18:18:55 -0700912 Bundle args = new Bundle();
913 args.putInt(StkAppService.RES_ID, resId);
Preeti Ahuja95919342013-10-01 18:18:55 -0700914 args.putBoolean(StkAppService.CONFIRMATION, confirm);
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +0900915 sendResponse(args, slotId);
Preeti Ahuja95919342013-10-01 18:18:55 -0700916 }
917
Takanori Nakanob82c8752019-04-01 14:47:07 +0900918 private void terminateTone(int slotId) {
919 Message msg = new Message();
920 msg.what = OP_STOP_TONE;
921 msg.obj = mServiceHandler.hasMessages(OP_STOP_TONE, PLAY_TONE_WITH_DIALOG)
922 ? PLAY_TONE_WITH_DIALOG : PLAY_TONE_ONLY;
923 handleStopTone(msg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800924 }
925
Alex Yakavenkad41f1d92010-07-12 14:13:13 -0700926 private boolean isCmdInteractive(CatCmdMessage cmd) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800927 switch (cmd.getCmdType()) {
928 case SEND_DTMF:
929 case SEND_SMS:
Yoshiaki.Naka7f74e022017-11-25 16:42:39 +0900930 case REFRESH:
Avinash Nalluri3fcea522017-10-18 16:20:49 -0700931 case RUN_AT:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800932 case SEND_SS:
933 case SEND_USSD:
934 case SET_UP_IDLE_MODE_TEXT:
935 case SET_UP_MENU:
Kazuhiro Ondo764167c2011-10-21 16:05:05 -0500936 case CLOSE_CHANNEL:
937 case RECEIVE_DATA:
938 case SEND_DATA:
Preeti Ahuja95919342013-10-01 18:18:55 -0700939 case SET_UP_EVENT_LIST:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800940 return false;
941 }
942
943 return true;
944 }
945
Wink Savillee68857d2014-10-17 15:23:05 -0700946 private void handleDelayedCmd(int slotId) {
947 CatLog.d(LOG_TAG, "handleDelayedCmd, slotId: " + slotId);
948 if (mStkContext[slotId].mCmdsQ.size() != 0) {
949 DelayedCmd cmd = mStkContext[slotId].mCmdsQ.poll();
950 if (cmd != null) {
951 CatLog.d(LOG_TAG, "handleDelayedCmd - queue size: " +
952 mStkContext[slotId].mCmdsQ.size() +
953 " id: " + cmd.id + "sim id: " + cmd.slotId);
954 switch (cmd.id) {
955 case OP_CMD:
956 handleCmd(cmd.msg, cmd.slotId);
957 break;
958 case OP_END_SESSION:
959 handleSessionEnd(cmd.slotId);
960 break;
961 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800962 }
963 }
964 }
965
Wink Savillee68857d2014-10-17 15:23:05 -0700966 private void callDelayedMsg(int slotId) {
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +0900967 Message msg = mServiceHandler.obtainMessage(OP_DELAYED_MSG, 0, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800968 mServiceHandler.sendMessage(msg);
969 }
970
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +0900971 private void callSetActivityInstMsg(int opcode, int slotId, Object obj) {
972 Message msg = mServiceHandler.obtainMessage(opcode, 0, slotId, obj);
Wink Savillee68857d2014-10-17 15:23:05 -0700973 mServiceHandler.sendMessage(msg);
974 }
975
976 private void handleSessionEnd(int slotId) {
Legler Wuaeefef52014-10-27 00:57:18 +0800977 // We should finish all pending activity if receiving END SESSION command.
978 cleanUpInstanceStackBySlot(slotId);
979
Wink Savillee68857d2014-10-17 15:23:05 -0700980 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
981 CatLog.d(LOG_TAG, "[handleSessionEnd] - mCurrentCmd changed to mMainCmd!.");
982 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mMainCmd;
983 CatLog.d(LOG_TAG, "slotId: " + slotId + ", mMenuState: " +
984 mStkContext[slotId].mMenuState);
985
986 mStkContext[slotId].mIsInputPending = false;
987 mStkContext[slotId].mIsMenuPending = false;
988 mStkContext[slotId].mIsDialogPending = false;
Yuta Uife965802017-11-07 20:12:37 +0900989 mStkContext[slotId].mNoResponseFromUser = false;
Wink Savillee68857d2014-10-17 15:23:05 -0700990
Wink Savillee68857d2014-10-17 15:23:05 -0700991 if (mStkContext[slotId].mMainCmd == null) {
992 CatLog.d(LOG_TAG, "[handleSessionEnd][mMainCmd is null!]");
993 }
994 mStkContext[slotId].lastSelectedItem = null;
Takanori Nakano43dacc02018-07-26 11:27:39 +0900995 mStkContext[slotId].mIsSessionFromUser = false;
Wink Saville79085fc2009-06-09 10:27:23 -0700996 // In case of SET UP MENU command which removed the app, don't
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800997 // update the current menu member.
Wink Savillee68857d2014-10-17 15:23:05 -0700998 if (mStkContext[slotId].mCurrentMenu != null && mStkContext[slotId].mMainCmd != null) {
999 mStkContext[slotId].mCurrentMenu = mStkContext[slotId].mMainCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001000 }
Wink Savillee68857d2014-10-17 15:23:05 -07001001 CatLog.d(LOG_TAG, "[handleSessionEnd][mMenuState]" + mStkContext[slotId].mMenuIsVisible);
Ryuto Sawada08c821c2016-08-08 18:29:02 +09001002
Wink Savillee68857d2014-10-17 15:23:05 -07001003 if (StkMenuActivity.STATE_SECONDARY == mStkContext[slotId].mMenuState) {
Ryuto Sawada08c821c2016-08-08 18:29:02 +09001004 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001005 }
Takanori Nakano3776e2c2016-10-14 16:54:28 +09001006
1007 // Send a local broadcast as a notice that this service handled the session end event.
1008 Intent intent = new Intent(SESSION_ENDED);
1009 intent.putExtra(SLOT_ID, slotId);
1010 LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
1011
Wink Savillee68857d2014-10-17 15:23:05 -07001012 if (mStkContext[slotId].mCmdsQ.size() != 0) {
1013 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001014 } else {
Wink Savillee68857d2014-10-17 15:23:05 -07001015 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001016 }
1017 // In case a launch browser command was just confirmed, launch that url.
Wink Savillee68857d2014-10-17 15:23:05 -07001018 if (mStkContext[slotId].launchBrowser) {
1019 mStkContext[slotId].launchBrowser = false;
1020 launchBrowser(mStkContext[slotId].mBrowserSettings);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001021 }
1022 }
1023
Preeti Ahuja560be362014-11-25 19:38:24 -08001024 // returns true if any Stk related activity already has focus on the screen
Yoshiaki Nakacec55b82017-10-20 15:53:43 +09001025 boolean isTopOfStack() {
pkanwareab12f32017-02-06 08:35:03 -08001026 ActivityManager mActivityManager = (ActivityManager) mContext
Preeti Ahuja560be362014-11-25 19:38:24 -08001027 .getSystemService(ACTIVITY_SERVICE);
pkanwareab12f32017-02-06 08:35:03 -08001028 String currentPackageName = null;
1029 List<RunningTaskInfo> tasks = mActivityManager.getRunningTasks(1);
1030 if (tasks == null || tasks.get(0).topActivity == null) {
1031 return false;
1032 }
1033 currentPackageName = tasks.get(0).topActivity.getPackageName();
Preeti Ahuja560be362014-11-25 19:38:24 -08001034 if (null != currentPackageName) {
1035 return currentPackageName.equals(PACKAGE_NAME);
1036 }
Preeti Ahuja560be362014-11-25 19:38:24 -08001037 return false;
1038 }
1039
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001040 /**
1041 * Get the boolean config from carrier config manager.
1042 *
Yukiko Fujimura913c1432019-02-21 17:14:30 +09001043 * @param context the context to get carrier service
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001044 * @param key config key defined in CarrierConfigManager
Yoshiaki Naka028bb092018-08-30 16:57:47 +09001045 * @param slotId slot ID.
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001046 * @return boolean value of corresponding key.
1047 */
Yukiko Fujimura913c1432019-02-21 17:14:30 +09001048 /* package */ static boolean getBooleanCarrierConfig(Context context, String key, int slotId) {
1049 CarrierConfigManager ccm = (CarrierConfigManager) context.getSystemService(
1050 Context.CARRIER_CONFIG_SERVICE);
1051 SubscriptionManager sm = (SubscriptionManager) context.getSystemService(
Yoshiaki Naka30d5a812018-11-12 12:43:34 +09001052 Context.TELEPHONY_SUBSCRIPTION_SERVICE);
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001053 PersistableBundle b = null;
Yoshiaki Naka30d5a812018-11-12 12:43:34 +09001054 if (ccm != null && sm != null) {
1055 SubscriptionInfo info = sm.getActiveSubscriptionInfoForSimSlotIndex(slotId);
1056 if (info != null) {
1057 b = ccm.getConfigForSubId(info.getSubscriptionId());
1058 }
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001059 }
1060 if (b != null) {
1061 return b.getBoolean(key);
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001062 }
Yoshiaki Naka028bb092018-08-30 16:57:47 +09001063 // Return static default defined in CarrierConfigManager.
1064 return CarrierConfigManager.getDefaultConfig().getBoolean(key);
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001065 }
1066
Yukiko Fujimura913c1432019-02-21 17:14:30 +09001067 private boolean getBooleanCarrierConfig(String key, int slotId) {
1068 return getBooleanCarrierConfig(this, key, slotId);
1069 }
1070
Wink Savillee68857d2014-10-17 15:23:05 -07001071 private void handleCmd(CatCmdMessage cmdMsg, int slotId) {
Preeti Ahuja95919342013-10-01 18:18:55 -07001072
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001073 if (cmdMsg == null) {
1074 return;
1075 }
1076 // save local reference for state tracking.
Wink Savillee68857d2014-10-17 15:23:05 -07001077 mStkContext[slotId].mCurrentCmd = cmdMsg;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001078 boolean waitForUsersResponse = true;
1079
Wink Savillee68857d2014-10-17 15:23:05 -07001080 mStkContext[slotId].mIsInputPending = false;
1081 mStkContext[slotId].mIsMenuPending = false;
1082 mStkContext[slotId].mIsDialogPending = false;
1083
1084 CatLog.d(LOG_TAG,"[handleCmd]" + cmdMsg.getCmdType().name());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001085 switch (cmdMsg.getCmdType()) {
1086 case DISPLAY_TEXT:
1087 TextMessage msg = cmdMsg.geTextMessage();
Jeevaka Badrappan854a25c2012-12-01 16:32:03 +02001088 waitForUsersResponse = msg.responseNeeded;
Preeti Ahuja560be362014-11-25 19:38:24 -08001089 //If we receive a low priority Display Text and the device is
1090 // not displaying any STK related activity and the screen is not idle
1091 // ( that is, device is in an interactive state), then send a screen busy
1092 // terminal response. Otherwise display the message. The existing
1093 // displayed message shall be updated with the new display text
1094 // proactive command (Refer to ETSI TS 102 384 section 27.22.4.1.4.4.2).
1095 if (!(msg.isHighPriority || mStkContext[slotId].mMenuIsVisible
1096 || mStkContext[slotId].mDisplayTextDlgIsVisibile || isTopOfStack())) {
1097 if(!isScreenIdle()) {
1098 CatLog.d(LOG_TAG, "Screen is not idle");
1099 sendScreenBusyResponse(slotId);
1100 } else {
1101 launchTextDialog(slotId);
1102 }
1103 } else {
1104 launchTextDialog(slotId);
1105 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001106 break;
1107 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -07001108 CatLog.d(LOG_TAG, "SELECT_ITEM +");
1109 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
1110 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
1111 launchMenuActivity(cmdMsg.getMenu(), slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001112 break;
1113 case SET_UP_MENU:
Wink Savillee68857d2014-10-17 15:23:05 -07001114 mStkContext[slotId].mCmdInProgress = false;
1115 mStkContext[slotId].mMainCmd = mStkContext[slotId].mCurrentCmd;
1116 mStkContext[slotId].mCurrentMenuCmd = mStkContext[slotId].mCurrentCmd;
1117 mStkContext[slotId].mCurrentMenu = cmdMsg.getMenu();
1118 CatLog.d(LOG_TAG, "SET_UP_MENU [" + removeMenu(slotId) + "]");
1119
1120 if (removeMenu(slotId)) {
Wink Savillee68857d2014-10-17 15:23:05 -07001121 mStkContext[slotId].mCurrentMenu = null;
Preeti Ahuja95919342013-10-01 18:18:55 -07001122 mStkContext[slotId].mMainCmd = null;
Wink Savillee68857d2014-10-17 15:23:05 -07001123 //Check other setup menu state. If all setup menu are removed, uninstall apk.
Yoshiaki Naka58e07652019-04-26 17:58:52 +09001124 if (!uninstallIfUnnecessary()) {
Yoshiaki Naka835e3002020-05-11 18:15:12 +09001125 addToMenuSystemOrUpdateLabel();
Wink Savillee68857d2014-10-17 15:23:05 -07001126 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001127 } else {
Yoshiaki Naka835e3002020-05-11 18:15:12 +09001128 addToMenuSystemOrUpdateLabel();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001129 }
Wink Savillee68857d2014-10-17 15:23:05 -07001130 if (mStkContext[slotId].mMenuIsVisible) {
1131 launchMenuActivity(null, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001132 }
1133 break;
1134 case GET_INPUT:
1135 case GET_INKEY:
Wink Savillee68857d2014-10-17 15:23:05 -07001136 launchInputActivity(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001137 break;
1138 case SET_UP_IDLE_MODE_TEXT:
1139 waitForUsersResponse = false;
Preeti Ahuja560be362014-11-25 19:38:24 -08001140 mStkContext[slotId].mIdleModeTextCmd = mStkContext[slotId].mCurrentCmd;
1141 TextMessage idleModeText = mStkContext[slotId].mCurrentCmd.geTextMessage();
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001142 if (idleModeText == null || TextUtils.isEmpty(idleModeText.text)) {
1143 cancelIdleText(slotId);
Preeti Ahuja560be362014-11-25 19:38:24 -08001144 }
1145 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001146 if (mStkContext[slotId].mIdleModeTextCmd != null) {
1147 if (mStkContext[slotId].mIdleModeTextVisible || isScreenIdle()) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001148 CatLog.d(LOG_TAG, "set up idle mode");
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001149 launchIdleText(slotId);
1150 } else {
Malcolm Chen549e21a2020-01-10 15:57:10 -08001151 registerHomeVisibilityObserver();
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001152 }
Preeti Ahuja560be362014-11-25 19:38:24 -08001153 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001154 break;
1155 case SEND_DTMF:
1156 case SEND_SMS:
Yoshiaki.Naka7f74e022017-11-25 16:42:39 +09001157 case REFRESH:
Avinash Nalluri3fcea522017-10-18 16:20:49 -07001158 case RUN_AT:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001159 case SEND_SS:
1160 case SEND_USSD:
Preeti Ahuja95919342013-10-01 18:18:55 -07001161 case GET_CHANNEL_STATUS:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001162 waitForUsersResponse = false;
Wink Savillee68857d2014-10-17 15:23:05 -07001163 launchEventMessage(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001164 break;
1165 case LAUNCH_BROWSER:
Ryuto Sawada0bdc7192016-04-18 12:10:56 +09001166 // The device setup process should not be interrupted by launching browser.
1167 if (Settings.Global.getInt(mContext.getContentResolver(),
1168 Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001169 CatLog.d(LOG_TAG, "Not perform if the setup process has not been completed.");
Ryuto Sawada0bdc7192016-04-18 12:10:56 +09001170 sendScreenBusyResponse(slotId);
1171 break;
1172 }
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001173
1174 /* Check if Carrier would not want to launch browser */
Yoshiaki Naka028bb092018-08-30 16:57:47 +09001175 if (getBooleanCarrierConfig(CarrierConfigManager.KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL,
1176 slotId)) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001177 CatLog.d(LOG_TAG, "Browser is not launched as per carrier.");
Sooraj Sasindrana4160472016-10-12 16:28:25 -07001178 sendResponse(RES_ID_DONE, slotId, true);
1179 break;
1180 }
1181
Srikanth Chintalaba103002015-11-30 10:49:52 -08001182 mStkContext[slotId].mBrowserSettings =
1183 mStkContext[slotId].mCurrentCmd.getBrowserSettings();
1184 if (!isUrlAvailableToLaunchBrowser(mStkContext[slotId].mBrowserSettings)) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001185 CatLog.d(LOG_TAG, "Browser url property is not set - send error");
Srikanth Chintalaba103002015-11-30 10:49:52 -08001186 sendResponse(RES_ID_ERROR, slotId, true);
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001187 } else {
Srikanth Chintalaba103002015-11-30 10:49:52 -08001188 TextMessage alphaId = mStkContext[slotId].mCurrentCmd.geTextMessage();
1189 if ((alphaId == null) || TextUtils.isEmpty(alphaId.text)) {
1190 // don't need user confirmation in this case
1191 // just launch the browser or spawn a new tab
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001192 CatLog.d(LOG_TAG, "user confirmation is not currently needed.\n" +
Srikanth Chintalaba103002015-11-30 10:49:52 -08001193 "supressing confirmation dialogue and confirming silently...");
1194 mStkContext[slotId].launchBrowser = true;
1195 sendResponse(RES_ID_CONFIRM, slotId, true);
1196 } else {
1197 launchConfirmationDialog(alphaId, slotId);
1198 }
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07001199 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001200 break;
1201 case SET_UP_CALL:
Preeti Ahujadd240102013-08-30 17:25:06 -07001202 TextMessage mesg = mStkContext[slotId].mCurrentCmd.getCallSettings().confirmMsg;
1203 if((mesg != null) && (mesg.text == null || mesg.text.length() == 0)) {
1204 mesg.text = getResources().getString(R.string.default_setup_call_msg);
1205 }
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001206 CatLog.d(LOG_TAG, "SET_UP_CALL mesg.text " + mesg.text);
Preeti Ahujadd240102013-08-30 17:25:06 -07001207 launchConfirmationDialog(mesg, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001208 break;
1209 case PLAY_TONE:
Srikanth Chintala89aa6602014-03-14 16:26:57 +05301210 handlePlayTone(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001211 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001212 case OPEN_CHANNEL:
Wink Savillee68857d2014-10-17 15:23:05 -07001213 launchOpenChannelDialog(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001214 break;
1215 case CLOSE_CHANNEL:
1216 case RECEIVE_DATA:
1217 case SEND_DATA:
Wink Savillee68857d2014-10-17 15:23:05 -07001218 TextMessage m = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001219
1220 if ((m != null) && (m.text == null)) {
1221 switch(cmdMsg.getCmdType()) {
1222 case CLOSE_CHANNEL:
1223 m.text = getResources().getString(R.string.default_close_channel_msg);
1224 break;
1225 case RECEIVE_DATA:
1226 m.text = getResources().getString(R.string.default_receive_data_msg);
1227 break;
1228 case SEND_DATA:
1229 m.text = getResources().getString(R.string.default_send_data_msg);
1230 break;
1231 }
1232 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001233 /*
1234 * Display indication in the form of a toast to the user if required.
1235 */
Wink Savillee68857d2014-10-17 15:23:05 -07001236 launchEventMessage(slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001237 break;
Preeti Ahuja95919342013-10-01 18:18:55 -07001238 case SET_UP_EVENT_LIST:
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001239 replaceEventList(slotId);
Preeti Ahuja560be362014-11-25 19:38:24 -08001240 if (isScreenIdle()) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001241 CatLog.d(LOG_TAG," Check if IDLE_SCREEN_AVAILABLE_EVENT is present in List");
Preeti Ahuja560be362014-11-25 19:38:24 -08001242 checkForSetupEvent(IDLE_SCREEN_AVAILABLE_EVENT, null, slotId);
1243 }
Preeti Ahuja95919342013-10-01 18:18:55 -07001244 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001245 }
1246
1247 if (!waitForUsersResponse) {
Wink Savillee68857d2014-10-17 15:23:05 -07001248 if (mStkContext[slotId].mCmdsQ.size() != 0) {
1249 callDelayedMsg(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001250 } else {
Wink Savillee68857d2014-10-17 15:23:05 -07001251 mStkContext[slotId].mCmdInProgress = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001252 }
1253 }
1254 }
1255
Yoshiaki Naka835e3002020-05-11 18:15:12 +09001256 private void addToMenuSystemOrUpdateLabel() {
1257 String candidateLabel = null;
1258
1259 for (int slotId = 0; slotId < mSimCount; slotId++) {
1260 Menu menu = getMainMenu(slotId);
1261 if (menu != null) {
1262 if (!TextUtils.isEmpty(candidateLabel)) {
1263 if (!TextUtils.equals(menu.title, candidateLabel)) {
1264 // We should not display the alpha identifier of SET-UP MENU command
1265 // as the application label on the application launcher
1266 // if different alpha identifiers are provided by multiple SIMs.
1267 candidateLabel = null;
1268 break;
1269 }
1270 } else {
1271 if (TextUtils.isEmpty(menu.title)) {
1272 break;
1273 }
1274 candidateLabel = menu.title;
1275 }
1276 }
1277 }
1278
1279 StkAppInstaller.installOrUpdate(this, candidateLabel);
1280 }
1281
Takanori Nakano43dacc02018-07-26 11:27:39 +09001282 @SuppressWarnings("FallThrough")
Wink Savillee68857d2014-10-17 15:23:05 -07001283 private void handleCmdResponse(Bundle args, int slotId) {
1284 CatLog.d(LOG_TAG, "handleCmdResponse, sim id: " + slotId);
Anna Suzukib1cee232019-02-21 12:52:27 +09001285 unregisterHomeKeyEventReceiver();
Wink Savillee68857d2014-10-17 15:23:05 -07001286 if (mStkContext[slotId].mCurrentCmd == null) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001287 return;
1288 }
Wink Savillee68857d2014-10-17 15:23:05 -07001289
1290 if (mStkService[slotId] == null) {
Legler Wuaeefef52014-10-27 00:57:18 +08001291 mStkService[slotId] = CatService.getInstance(slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07001292 if (mStkService[slotId] == null) {
Takanori Nakanoeeed5db2019-04-08 12:21:29 +09001293 // CatService is disposed when the relevant SIM is removed or disabled.
1294 // StkAppService can also be stopped when the absent state is notified,
1295 // so this situation can happen.
1296 CatLog.d(LOG_TAG, "No response is sent back to the missing CatService.");
1297 return;
Alex Yakavenkad8e2ecd2012-04-20 17:10:15 -07001298 }
1299 }
1300
Wink Savillee68857d2014-10-17 15:23:05 -07001301 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentCmd);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001302
1303 // set result code
1304 boolean helpRequired = args.getBoolean(HELP, false);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001305 boolean confirmed = false;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001306
1307 switch(args.getInt(RES_ID)) {
1308 case RES_ID_MENU_SELECTION:
Wink Savillee68857d2014-10-17 15:23:05 -07001309 CatLog.d(LOG_TAG, "MENU_SELECTION=" + mStkContext[slotId].
1310 mCurrentMenuCmd.getCmdType());
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001311 int menuSelection = args.getInt(MENU_SELECTION);
Wink Savillee68857d2014-10-17 15:23:05 -07001312 switch(mStkContext[slotId].mCurrentMenuCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001313 case SET_UP_MENU:
Takanori Nakano43dacc02018-07-26 11:27:39 +09001314 mStkContext[slotId].mIsSessionFromUser = true;
1315 // Fall through
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001316 case SELECT_ITEM:
Wink Savillee68857d2014-10-17 15:23:05 -07001317 mStkContext[slotId].lastSelectedItem = getItemName(menuSelection, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001318 if (helpRequired) {
1319 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
1320 } else {
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301321 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1322 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001323 }
1324 resMsg.setMenuSelection(menuSelection);
1325 break;
1326 }
1327 break;
1328 case RES_ID_INPUT:
Wink Savillee68857d2014-10-17 15:23:05 -07001329 CatLog.d(LOG_TAG, "RES_ID_INPUT");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001330 String input = args.getString(INPUT);
Wink Savillee68857d2014-10-17 15:23:05 -07001331 if (input != null && (null != mStkContext[slotId].mCurrentCmd.geInput()) &&
1332 (mStkContext[slotId].mCurrentCmd.geInput().yesNo)) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001333 boolean yesNoSelection = input
1334 .equals(StkInputActivity.YES_STR_RESPONSE);
1335 resMsg.setYesNo(yesNoSelection);
1336 } else {
1337 if (helpRequired) {
1338 resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);
1339 } else {
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301340 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1341 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001342 resMsg.setInput(input);
1343 }
1344 }
1345 break;
1346 case RES_ID_CONFIRM:
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001347 CatLog.d(LOG_TAG, "RES_ID_CONFIRM");
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001348 confirmed = args.getBoolean(CONFIRMATION);
Wink Savillee68857d2014-10-17 15:23:05 -07001349 switch (mStkContext[slotId].mCurrentCmd.getCmdType()) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001350 case DISPLAY_TEXT:
Preeti Ahujaf33bf392013-09-28 19:11:31 +05301351 if (confirmed) {
1352 resMsg.setResultCode(mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ?
1353 ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK);
1354 } else {
1355 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
1356 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001357 break;
1358 case LAUNCH_BROWSER:
1359 resMsg.setResultCode(confirmed ? ResultCode.OK
1360 : ResultCode.UICC_SESSION_TERM_BY_USER);
1361 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -07001362 mStkContext[slotId].launchBrowser = true;
1363 mStkContext[slotId].mBrowserSettings =
1364 mStkContext[slotId].mCurrentCmd.getBrowserSettings();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001365 }
1366 break;
1367 case SET_UP_CALL:
1368 resMsg.setResultCode(ResultCode.OK);
1369 resMsg.setConfirmation(confirmed);
1370 if (confirmed) {
Wink Savillee68857d2014-10-17 15:23:05 -07001371 launchEventMessage(slotId,
1372 mStkContext[slotId].mCurrentCmd.getCallSettings().callMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001373 }
1374 break;
1375 }
1376 break;
1377 case RES_ID_DONE:
1378 resMsg.setResultCode(ResultCode.OK);
1379 break;
1380 case RES_ID_BACKWARD:
Wink Savillee68857d2014-10-17 15:23:05 -07001381 CatLog.d(LOG_TAG, "RES_ID_BACKWARD");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001382 resMsg.setResultCode(ResultCode.BACKWARD_MOVE_BY_USER);
1383 break;
1384 case RES_ID_END_SESSION:
Wink Savillee68857d2014-10-17 15:23:05 -07001385 CatLog.d(LOG_TAG, "RES_ID_END_SESSION");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001386 resMsg.setResultCode(ResultCode.UICC_SESSION_TERM_BY_USER);
1387 break;
1388 case RES_ID_TIMEOUT:
Wink Savillee68857d2014-10-17 15:23:05 -07001389 CatLog.d(LOG_TAG, "RES_ID_TIMEOUT");
Naveen Kallad5176892009-11-30 12:45:29 -08001390 // GCF test-case 27.22.4.1.1 Expected Sequence 1.5 (DISPLAY TEXT,
1391 // Clear message after delay, successful) expects result code OK.
1392 // If the command qualifier specifies no user response is required
1393 // then send OK instead of NO_RESPONSE_FROM_USER
Wink Savillee68857d2014-10-17 15:23:05 -07001394 if ((mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1395 AppInterface.CommandType.DISPLAY_TEXT.value())
1396 && (mStkContext[slotId].mCurrentCmd.geTextMessage().userClear == false)) {
Naveen Kallad5176892009-11-30 12:45:29 -08001397 resMsg.setResultCode(ResultCode.OK);
1398 } else {
1399 resMsg.setResultCode(ResultCode.NO_RESPONSE_FROM_USER);
1400 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001401 break;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001402 case RES_ID_CHOICE:
1403 int choice = args.getInt(CHOICE);
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001404 CatLog.d(LOG_TAG, "User Choice=" + choice);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001405 switch (choice) {
1406 case YES:
1407 resMsg.setResultCode(ResultCode.OK);
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001408 confirmed = true;
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001409 break;
1410 case NO:
1411 resMsg.setResultCode(ResultCode.USER_NOT_ACCEPT);
1412 break;
1413 }
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001414
Wink Savillee68857d2014-10-17 15:23:05 -07001415 if (mStkContext[slotId].mCurrentCmd.getCmdType().value() ==
1416 AppInterface.CommandType.OPEN_CHANNEL.value()) {
Siddartha Pothapragadacacf7b82012-04-16 19:42:38 -07001417 resMsg.setConfirmation(confirmed);
1418 }
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05001419 break;
Srikanth Chintalaba103002015-11-30 10:49:52 -08001420 case RES_ID_ERROR:
1421 CatLog.d(LOG_TAG, "RES_ID_ERROR");
1422 switch (mStkContext[slotId].mCurrentCmd.getCmdType()) {
1423 case LAUNCH_BROWSER:
1424 resMsg.setResultCode(ResultCode.LAUNCH_BROWSER_ERROR);
1425 break;
1426 }
1427 break;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001428 default:
Wink Savillee68857d2014-10-17 15:23:05 -07001429 CatLog.d(LOG_TAG, "Unknown result id");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001430 return;
1431 }
Wink Savillee68857d2014-10-17 15:23:05 -07001432
Yuta Uife965802017-11-07 20:12:37 +09001433 switch (args.getInt(RES_ID)) {
1434 case RES_ID_MENU_SELECTION:
1435 case RES_ID_INPUT:
1436 case RES_ID_CONFIRM:
1437 case RES_ID_CHOICE:
1438 case RES_ID_BACKWARD:
1439 case RES_ID_END_SESSION:
1440 mStkContext[slotId].mNoResponseFromUser = false;
1441 break;
1442 case RES_ID_TIMEOUT:
1443 cancelNotificationOnKeyguard(slotId);
1444 mStkContext[slotId].mNoResponseFromUser = true;
1445 break;
1446 default:
1447 // The other IDs cannot be used to judge if there is no response from user.
1448 break;
1449 }
1450
Wink Savillee68857d2014-10-17 15:23:05 -07001451 if (null != mStkContext[slotId].mCurrentCmd &&
1452 null != mStkContext[slotId].mCurrentCmd.getCmdType()) {
1453 CatLog.d(LOG_TAG, "handleCmdResponse- cmdName[" +
1454 mStkContext[slotId].mCurrentCmd.getCmdType().name() + "]");
1455 }
1456 mStkService[slotId].onCmdResponse(resMsg);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001457 }
1458
1459 /**
1460 * Returns 0 or FLAG_ACTIVITY_NO_USER_ACTION, 0 means the user initiated the action.
1461 *
1462 * @param userAction If the userAction is yes then we always return 0 otherwise
1463 * mMenuIsVisible is used to determine what to return. If mMenuIsVisible is true
1464 * then we are the foreground app and we'll return 0 as from our perspective a
1465 * user action did cause. If it's false than we aren't the foreground app and
1466 * FLAG_ACTIVITY_NO_USER_ACTION is returned.
Wink Saville79085fc2009-06-09 10:27:23 -07001467 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001468 * @return 0 or FLAG_ACTIVITY_NO_USER_ACTION
1469 */
Wink Savillee68857d2014-10-17 15:23:05 -07001470 private int getFlagActivityNoUserAction(InitiatedByUserAction userAction, int slotId) {
1471 return ((userAction == InitiatedByUserAction.yes) | mStkContext[slotId].mMenuIsVisible)
1472 ? 0 : Intent.FLAG_ACTIVITY_NO_USER_ACTION;
1473 }
1474 /**
1475 * This method is used for cleaning up pending instances in stack.
Takanori Nakano28ce8b62018-02-22 12:10:44 +09001476 * No terminal response will be sent for pending instances.
Wink Savillee68857d2014-10-17 15:23:05 -07001477 */
1478 private void cleanUpInstanceStackBySlot(int slotId) {
1479 Activity activity = mStkContext[slotId].getPendingActivityInstance();
1480 Activity dialog = mStkContext[slotId].getPendingDialogInstance();
1481 CatLog.d(LOG_TAG, "cleanUpInstanceStackBySlot slotId: " + slotId);
1482 if (activity != null) {
Takanori Nakano28ce8b62018-02-22 12:10:44 +09001483 if (mStkContext[slotId].mCurrentCmd != null) {
1484 CatLog.d(LOG_TAG, "current cmd type: " +
1485 mStkContext[slotId].mCurrentCmd.getCmdType());
1486 if (mStkContext[slotId].mCurrentCmd.getCmdType().value()
1487 == AppInterface.CommandType.GET_INPUT.value()
1488 || mStkContext[slotId].mCurrentCmd.getCmdType().value()
1489 == AppInterface.CommandType.GET_INKEY.value()) {
1490 mStkContext[slotId].mIsInputPending = true;
1491 } else if (mStkContext[slotId].mCurrentCmd.getCmdType().value()
1492 == AppInterface.CommandType.SET_UP_MENU.value()
1493 || mStkContext[slotId].mCurrentCmd.getCmdType().value()
1494 == AppInterface.CommandType.SELECT_ITEM.value()) {
1495 mStkContext[slotId].mIsMenuPending = true;
1496 }
Wink Savillee68857d2014-10-17 15:23:05 -07001497 }
1498 CatLog.d(LOG_TAG, "finish pending activity.");
1499 activity.finish();
1500 mStkContext[slotId].mActivityInstance = null;
1501 }
1502 if (dialog != null) {
1503 CatLog.d(LOG_TAG, "finish pending dialog.");
1504 mStkContext[slotId].mIsDialogPending = true;
1505 dialog.finish();
1506 mStkContext[slotId].mDialogInstance = null;
1507 }
1508 }
1509 /**
1510 * This method is used for restoring pending instances from stack.
1511 */
1512 private void restoreInstanceFromStackBySlot(int slotId) {
1513 AppInterface.CommandType cmdType = mStkContext[slotId].mCurrentCmd.getCmdType();
1514
1515 CatLog.d(LOG_TAG, "restoreInstanceFromStackBySlot cmdType : " + cmdType);
1516 switch(cmdType) {
1517 case GET_INPUT:
1518 case GET_INKEY:
1519 launchInputActivity(slotId);
1520 //Set mMenuIsVisible to true for showing main menu for
1521 //following session end command.
1522 mStkContext[slotId].mMenuIsVisible = true;
1523 break;
1524 case DISPLAY_TEXT:
1525 launchTextDialog(slotId);
1526 break;
1527 case LAUNCH_BROWSER:
1528 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.geTextMessage(),
1529 slotId);
1530 break;
1531 case OPEN_CHANNEL:
1532 launchOpenChannelDialog(slotId);
1533 break;
1534 case SET_UP_CALL:
1535 launchConfirmationDialog(mStkContext[slotId].mCurrentCmd.getCallSettings().
1536 confirmMsg, slotId);
1537 break;
1538 case SET_UP_MENU:
1539 case SELECT_ITEM:
1540 launchMenuActivity(null, slotId);
1541 break;
1542 default:
1543 break;
1544 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001545 }
1546
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +09001547 @Override
1548 public void startActivity(Intent intent) {
1549 int slotId = intent.getIntExtra(SLOT_ID, SubscriptionManager.INVALID_SIM_SLOT_INDEX);
1550 // Close the dialog displayed for DISPLAY TEXT command with an immediate response object
1551 // before new dialog is displayed.
1552 if (SubscriptionManager.isValidSlotIndex(slotId)) {
1553 Activity dialog = mStkContext[slotId].getImmediateDialogInstance();
1554 if (dialog != null) {
1555 CatLog.d(LOG_TAG, "finish dialog for immediate response.");
1556 dialog.finish();
1557 }
1558 }
1559 super.startActivity(intent);
1560 }
1561
Wink Savillee68857d2014-10-17 15:23:05 -07001562 private void launchMenuActivity(Menu menu, int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001563 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001564 String targetActivity = STK_MENU_ACTIVITY_NAME;
1565 String uriString = STK_MENU_URI + System.currentTimeMillis();
1566 //Set unique URI to create a new instance of activity for different slotId.
1567 Uri uriData = Uri.parse(uriString);
1568
1569 CatLog.d(LOG_TAG, "launchMenuActivity, slotId: " + slotId + " , " +
1570 uriData.toString() + " , " + mStkContext[slotId].mOpCode + ", "
1571 + mStkContext[slotId].mMenuState);
1572 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1573 int intentFlags = Intent.FLAG_ACTIVITY_NEW_TASK;
1574
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001575 if (menu == null) {
1576 // We assume this was initiated by the user pressing the tool kit icon
Wink Savillee68857d2014-10-17 15:23:05 -07001577 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.yes, slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07001578 //If the last pending menu is secondary menu, "STATE" should be "STATE_SECONDARY".
1579 //Otherwise, it should be "STATE_MAIN".
1580 if (mStkContext[slotId].mOpCode == OP_LAUNCH_APP &&
1581 mStkContext[slotId].mMenuState == StkMenuActivity.STATE_SECONDARY) {
1582 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
1583 } else {
1584 newIntent.putExtra("STATE", StkMenuActivity.STATE_MAIN);
1585 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_MAIN;
1586 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001587 } else {
1588 // We don't know and we'll let getFlagActivityNoUserAction decide.
Wink Savillee68857d2014-10-17 15:23:05 -07001589 intentFlags |= getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001590 newIntent.putExtra("STATE", StkMenuActivity.STATE_SECONDARY);
Wink Savillee68857d2014-10-17 15:23:05 -07001591 mStkContext[slotId].mMenuState = StkMenuActivity.STATE_SECONDARY;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001592 }
Anna Suzuki35309b02019-02-15 16:24:59 +09001593 if (mStkContext[slotId].mMenuState == StkMenuActivity.STATE_SECONDARY) {
Anna Suzukib1cee232019-02-21 12:52:27 +09001594 startToObserveHomeKeyEvent(slotId);
Anna Suzuki35309b02019-02-15 16:24:59 +09001595 }
Wink Savillee68857d2014-10-17 15:23:05 -07001596 newIntent.putExtra(SLOT_ID, slotId);
1597 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001598 newIntent.setFlags(intentFlags);
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +09001599 startActivity(newIntent);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001600 }
1601
Wink Savillee68857d2014-10-17 15:23:05 -07001602 private void launchInputActivity(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001603 Intent newIntent = new Intent(Intent.ACTION_VIEW);
Wink Savillee68857d2014-10-17 15:23:05 -07001604 String targetActivity = STK_INPUT_ACTIVITY_NAME;
1605 String uriString = STK_INPUT_URI + System.currentTimeMillis();
1606 //Set unique URI to create a new instance of activity for different slotId.
1607 Uri uriData = Uri.parse(uriString);
Yuta Uife965802017-11-07 20:12:37 +09001608 Input input = mStkContext[slotId].mCurrentCmd.geInput();
Wink Savillee68857d2014-10-17 15:23:05 -07001609
1610 CatLog.d(LOG_TAG, "launchInputActivity, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001611 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
Wink Savillee68857d2014-10-17 15:23:05 -07001612 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1613 newIntent.setClassName(PACKAGE_NAME, targetActivity);
Yuta Uife965802017-11-07 20:12:37 +09001614 newIntent.putExtra("INPUT", input);
Wink Savillee68857d2014-10-17 15:23:05 -07001615 newIntent.putExtra(SLOT_ID, slotId);
1616 newIntent.setData(uriData);
Yuta Uife965802017-11-07 20:12:37 +09001617
1618 if (input != null) {
1619 notifyUserIfNecessary(slotId, input.text);
1620 }
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +09001621 startActivity(newIntent);
Anna Suzukib1cee232019-02-21 12:52:27 +09001622 startToObserveHomeKeyEvent(slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001623 }
1624
Wink Savillee68857d2014-10-17 15:23:05 -07001625 private void launchTextDialog(int slotId) {
1626 CatLog.d(LOG_TAG, "launchTextDialog, slotId: " + slotId);
1627 Intent newIntent = new Intent();
1628 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
1629 int action = getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId);
1630 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
1631 //Set unique URI to create a new instance of activity for different slotId.
1632 Uri uriData = Uri.parse(uriString);
Yuta Uife965802017-11-07 20:12:37 +09001633 TextMessage textMessage = mStkContext[slotId].mCurrentCmd.geTextMessage();
1634
1635 newIntent.setClassName(PACKAGE_NAME, targetActivity);
1636 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
Yuta Uife965802017-11-07 20:12:37 +09001637 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
1638 newIntent.setData(uriData);
1639 newIntent.putExtra("TEXT", textMessage);
1640 newIntent.putExtra(SLOT_ID, slotId);
1641
1642 if (textMessage != null) {
1643 notifyUserIfNecessary(slotId, textMessage.text);
1644 }
1645 startActivity(newIntent);
1646 // For display texts with immediate response, send the terminal response
1647 // immediately. responseNeeded will be false, if display text command has
1648 // the immediate response tlv.
1649 if (!mStkContext[slotId].mCurrentCmd.geTextMessage().responseNeeded) {
1650 sendResponse(RES_ID_CONFIRM, slotId, true);
Anna Suzuki35309b02019-02-15 16:24:59 +09001651 } else {
Anna Suzukib1cee232019-02-21 12:52:27 +09001652 startToObserveHomeKeyEvent(slotId);
Yuta Uife965802017-11-07 20:12:37 +09001653 }
1654 }
1655
1656 private void notifyUserIfNecessary(int slotId, String message) {
1657 createAllChannels();
1658
1659 if (mStkContext[slotId].mNoResponseFromUser) {
1660 // No response from user was observed in the current session.
1661 // Do nothing in that case in order to avoid turning on the screen again and again
1662 // when the card repeatedly sends the same command in its retry procedure.
1663 return;
1664 }
1665
1666 PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
1667
1668 if (((KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE)).isKeyguardLocked()) {
1669 // Display the notification on the keyguard screen
1670 // if user cannot see the message from the card right now because of it.
1671 // The notification can be dismissed if user removed the keyguard screen.
1672 launchNotificationOnKeyguard(slotId, message);
Wink Savillee68857d2014-10-17 15:23:05 -07001673 }
Yuta Uife965802017-11-07 20:12:37 +09001674
1675 // Turn on the screen.
1676 PowerManager.WakeLock wakelock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK
1677 | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, LOG_TAG);
1678 wakelock.acquire();
1679 wakelock.release();
1680 }
1681
1682 private void launchNotificationOnKeyguard(int slotId, String message) {
1683 Notification.Builder builder = new Notification.Builder(this, STK_NOTIFICATION_CHANNEL_ID);
Yoshiaki Naka8143ee92020-08-15 14:34:00 +09001684 setNotificationTitle(slotId, builder);
Yuta Uife965802017-11-07 20:12:37 +09001685
1686 builder.setStyle(new Notification.BigTextStyle(builder).bigText(message));
1687 builder.setContentText(message);
Sooraj Sasindran2b44d5b2020-01-29 15:17:48 -08001688 builder.setSmallIcon(R.drawable.stat_notify_sim_toolkit);
Yuta Uife965802017-11-07 20:12:37 +09001689 builder.setOngoing(true);
1690 builder.setOnlyAlertOnce(true);
1691 builder.setColor(getResources().getColor(
1692 com.android.internal.R.color.system_notification_accent_color));
1693
1694 registerUserPresentReceiver();
1695 mNotificationManager.notify(getNotificationId(NOTIFICATION_ON_KEYGUARD, slotId),
1696 builder.build());
1697 mStkContext[slotId].mNotificationOnKeyguard = true;
1698 }
1699
1700 private void cancelNotificationOnKeyguard(int slotId) {
1701 mNotificationManager.cancel(getNotificationId(NOTIFICATION_ON_KEYGUARD, slotId));
1702 mStkContext[slotId].mNotificationOnKeyguard = false;
1703 unregisterUserPresentReceiver(slotId);
1704 }
1705
1706 private synchronized void registerUserPresentReceiver() {
1707 if (mUserPresentReceiver == null) {
1708 mUserPresentReceiver = new BroadcastReceiver() {
1709 @Override public void onReceive(Context context, Intent intent) {
1710 if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
1711 for (int slot = 0; slot < mSimCount; slot++) {
1712 cancelNotificationOnKeyguard(slot);
1713 }
1714 }
1715 }
1716 };
1717 registerReceiver(mUserPresentReceiver, new IntentFilter(Intent.ACTION_USER_PRESENT));
1718 }
1719 }
1720
1721 private synchronized void unregisterUserPresentReceiver(int slotId) {
1722 if (mUserPresentReceiver != null) {
Yoshiaki Naka8b960fb2019-10-31 10:44:07 +09001723 for (int slot = 0; slot < mSimCount; slot++) {
Yuta Uife965802017-11-07 20:12:37 +09001724 if (slot != slotId) {
1725 if (mStkContext[slot].mNotificationOnKeyguard) {
1726 // The broadcast receiver is still necessary for other SIM card.
1727 return;
1728 }
1729 }
1730 }
1731 unregisterReceiver(mUserPresentReceiver);
1732 mUserPresentReceiver = null;
1733 }
1734 }
1735
1736 private int getNotificationId(int notificationType, int slotId) {
1737 return getNotificationId(slotId) + (notificationType * mSimCount);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08001738 }
1739
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001740 private void replaceEventList(int slotId) {
1741 if (mStkContext[slotId].mSetupEventListSettings != null) {
1742 for (int current : mStkContext[slotId].mSetupEventListSettings.eventList) {
1743 if (current != INVALID_SETUP_EVENT) {
1744 // Cancel the event notification if it is not listed in the new event list.
1745 if ((mStkContext[slotId].mCurrentCmd.getSetEventList() == null)
1746 || !findEvent(current, mStkContext[slotId].mCurrentCmd
1747 .getSetEventList().eventList)) {
1748 unregisterEvent(current, slotId);
1749 }
1750 }
1751 }
1752 }
1753 mStkContext[slotId].mSetupEventListSettings
1754 = mStkContext[slotId].mCurrentCmd.getSetEventList();
1755 mStkContext[slotId].mCurrentSetupEventCmd = mStkContext[slotId].mCurrentCmd;
1756 mStkContext[slotId].mCurrentCmd = mStkContext[slotId].mMainCmd;
1757 registerEvents(slotId);
1758 }
1759
1760 private boolean findEvent(int event, int[] eventList) {
1761 for (int content : eventList) {
1762 if (content == event) return true;
1763 }
1764 return false;
1765 }
1766
1767 private void unregisterEvent(int event, int slotId) {
Yoshiaki Naka8b960fb2019-10-31 10:44:07 +09001768 for (int slot = 0; slot < mSimCount; slot++) {
Yoshiaki Naka0c2d2ba2017-11-17 21:51:55 +09001769 if (slot != slotId) {
1770 if (mStkContext[slot].mSetupEventListSettings != null) {
1771 if (findEvent(event, mStkContext[slot].mSetupEventListSettings.eventList)) {
1772 // The specified event shall never be canceled
1773 // if there is any other SIM card which requests the event.
1774 return;
1775 }
1776 }
1777 }
1778 }
1779
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001780 switch (event) {
Yoshiaki Nakafb997252017-09-19 20:14:58 +09001781 case USER_ACTIVITY_EVENT:
1782 unregisterUserActivityReceiver();
1783 break;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001784 case IDLE_SCREEN_AVAILABLE_EVENT:
Malcolm Chen549e21a2020-01-10 15:57:10 -08001785 unregisterHomeVisibilityObserver(AppInterface.CommandType.SET_UP_EVENT_LIST, slotId);
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001786 break;
1787 case LANGUAGE_SELECTION_EVENT:
Yoshiaki Naka0c2d2ba2017-11-17 21:51:55 +09001788 unregisterLocaleChangeReceiver();
1789 break;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001790 default:
1791 break;
1792 }
1793 }
1794
1795 private void registerEvents(int slotId) {
1796 if (mStkContext[slotId].mSetupEventListSettings == null) {
1797 return;
1798 }
1799 for (int event : mStkContext[slotId].mSetupEventListSettings.eventList) {
1800 switch (event) {
Yoshiaki Nakafb997252017-09-19 20:14:58 +09001801 case USER_ACTIVITY_EVENT:
1802 registerUserActivityReceiver();
1803 break;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001804 case IDLE_SCREEN_AVAILABLE_EVENT:
Malcolm Chen549e21a2020-01-10 15:57:10 -08001805 registerHomeVisibilityObserver();
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001806 break;
1807 case LANGUAGE_SELECTION_EVENT:
Yoshiaki Naka0c2d2ba2017-11-17 21:51:55 +09001808 registerLocaleChangeReceiver();
1809 break;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001810 default:
1811 break;
1812 }
1813 }
1814 }
1815
Yoshiaki Nakafb997252017-09-19 20:14:58 +09001816 private synchronized void registerUserActivityReceiver() {
1817 if (mUserActivityReceiver == null) {
1818 mUserActivityReceiver = new BroadcastReceiver() {
1819 @Override public void onReceive(Context context, Intent intent) {
Peter Wang10da9292020-01-27 12:36:00 +08001820 if (TelephonyIntents.ACTION_USER_ACTIVITY_NOTIFICATION.equals(
Yoshiaki Nakafb997252017-09-19 20:14:58 +09001821 intent.getAction())) {
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +09001822 Message message = mServiceHandler.obtainMessage(OP_USER_ACTIVITY);
Yoshiaki Nakafb997252017-09-19 20:14:58 +09001823 mServiceHandler.sendMessage(message);
1824 unregisterUserActivityReceiver();
1825 }
1826 }
1827 };
1828 registerReceiver(mUserActivityReceiver, new IntentFilter(
Peter Wang10da9292020-01-27 12:36:00 +08001829 TelephonyIntents.ACTION_USER_ACTIVITY_NOTIFICATION));
Yoshiaki Nakafb997252017-09-19 20:14:58 +09001830 try {
Peter Wanga14d13d2020-01-15 14:13:51 -08001831 ITelephony telephony = ITelephony.Stub.asInterface(
Peter Wangc94b8e62019-12-30 17:09:10 -08001832 TelephonyFrameworkInitializer
1833 .getTelephonyServiceManager()
Peter Wanga14d13d2020-01-15 14:13:51 -08001834 .getTelephonyServiceRegisterer()
Peter Wangc94b8e62019-12-30 17:09:10 -08001835 .get());
Peter Wanga14d13d2020-01-15 14:13:51 -08001836 telephony.requestUserActivityNotification();
Yoshiaki Nakafb997252017-09-19 20:14:58 +09001837 } catch (RemoteException e) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001838 CatLog.e(LOG_TAG, "failed to init WindowManager:" + e);
Yoshiaki Nakafb997252017-09-19 20:14:58 +09001839 }
1840 }
1841 }
1842
1843 private synchronized void unregisterUserActivityReceiver() {
1844 if (mUserActivityReceiver != null) {
1845 unregisterReceiver(mUserActivityReceiver);
1846 mUserActivityReceiver = null;
1847 }
1848 }
1849
Malcolm Chen549e21a2020-01-10 15:57:10 -08001850 private synchronized void registerHomeVisibilityObserver() {
Hall Liu9d5d5ee2020-10-06 14:15:40 -07001851 if (mHomeVisibilityListener == null) {
1852 mHomeVisibilityListener = new HomeVisibilityListener() {
Malcolm Chen549e21a2020-01-10 15:57:10 -08001853 @Override
1854 public void onHomeVisibilityChanged(boolean isHomeActivityVisible) {
1855 if (isHomeActivityVisible) {
1856 Message message = mServiceHandler.obtainMessage(OP_IDLE_SCREEN);
1857 mServiceHandler.sendMessage(message);
1858 unregisterHomeVisibilityObserver();
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001859 }
Malcolm Chen549e21a2020-01-10 15:57:10 -08001860 }
1861 };
1862 ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
Hall Liu9d5d5ee2020-10-06 14:15:40 -07001863 am.addHomeVisibilityListener(Runnable::run, mHomeVisibilityListener);
Malcolm Chen549e21a2020-01-10 15:57:10 -08001864 CatLog.d(LOG_TAG, "Started to observe the foreground activity");
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001865 }
1866 }
1867
Malcolm Chen549e21a2020-01-10 15:57:10 -08001868 private void unregisterHomeVisibilityObserver(AppInterface.CommandType command, int slotId) {
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001869 // Check if there is any pending command which still needs the process observer
1870 // except for the current command and slot.
Yoshiaki Naka8b960fb2019-10-31 10:44:07 +09001871 for (int slot = 0; slot < mSimCount; slot++) {
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001872 if (command != AppInterface.CommandType.SET_UP_IDLE_MODE_TEXT || slot != slotId) {
1873 if (mStkContext[slot].mIdleModeTextCmd != null
1874 && !mStkContext[slot].mIdleModeTextVisible) {
1875 // Keep the process observer registered
1876 // as there is an idle mode text which has not been visible yet.
1877 return;
1878 }
1879 }
1880 if (command != AppInterface.CommandType.SET_UP_EVENT_LIST || slot != slotId) {
1881 if (mStkContext[slot].mSetupEventListSettings != null) {
1882 if (findEvent(IDLE_SCREEN_AVAILABLE_EVENT,
1883 mStkContext[slot].mSetupEventListSettings.eventList)) {
1884 // Keep the process observer registered
1885 // as there is a SIM card which still want IDLE SCREEN AVAILABLE event.
1886 return;
1887 }
1888 }
1889 }
1890 }
Malcolm Chen549e21a2020-01-10 15:57:10 -08001891 unregisterHomeVisibilityObserver();
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001892 }
1893
Malcolm Chen549e21a2020-01-10 15:57:10 -08001894 private synchronized void unregisterHomeVisibilityObserver() {
Hall Liu9d5d5ee2020-10-06 14:15:40 -07001895 if (mHomeVisibilityListener != null) {
Malcolm Chen549e21a2020-01-10 15:57:10 -08001896 ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
Hall Liu9d5d5ee2020-10-06 14:15:40 -07001897 am.removeHomeVisibilityListener(mHomeVisibilityListener);
Malcolm Chen549e21a2020-01-10 15:57:10 -08001898 CatLog.d(LOG_TAG, "Stopped to observe the foreground activity");
Hall Liu9d5d5ee2020-10-06 14:15:40 -07001899 mHomeVisibilityListener = null;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001900 }
1901 }
1902
Yoshiaki Naka0c2d2ba2017-11-17 21:51:55 +09001903 private synchronized void registerLocaleChangeReceiver() {
1904 if (mLocaleChangeReceiver == null) {
1905 mLocaleChangeReceiver = new BroadcastReceiver() {
1906 @Override public void onReceive(Context context, Intent intent) {
1907 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +09001908 Message message = mServiceHandler.obtainMessage(OP_LOCALE_CHANGED);
Yoshiaki Naka0c2d2ba2017-11-17 21:51:55 +09001909 mServiceHandler.sendMessage(message);
1910 }
1911 }
1912 };
1913 registerReceiver(mLocaleChangeReceiver, new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
1914 }
1915 }
1916
1917 private synchronized void unregisterLocaleChangeReceiver() {
1918 if (mLocaleChangeReceiver != null) {
1919 unregisterReceiver(mLocaleChangeReceiver);
1920 mLocaleChangeReceiver = null;
1921 }
1922 }
1923
Preeti Ahuja95919342013-10-01 18:18:55 -07001924 private void sendSetUpEventResponse(int event, byte[] addedInfo, int slotId) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001925 CatLog.d(LOG_TAG, "sendSetUpEventResponse: event : " + event + "slotId = " + slotId);
Preeti Ahuja95919342013-10-01 18:18:55 -07001926
1927 if (mStkContext[slotId].mCurrentSetupEventCmd == null){
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001928 CatLog.e(LOG_TAG, "mCurrentSetupEventCmd is null");
Preeti Ahuja95919342013-10-01 18:18:55 -07001929 return;
1930 }
1931
1932 CatResponseMessage resMsg = new CatResponseMessage(mStkContext[slotId].mCurrentSetupEventCmd);
1933
1934 resMsg.setResultCode(ResultCode.OK);
1935 resMsg.setEventDownload(event, addedInfo);
1936
1937 mStkService[slotId].onCmdResponse(resMsg);
1938 }
1939
1940 private void checkForSetupEvent(int event, Bundle args, int slotId) {
1941 boolean eventPresent = false;
1942 byte[] addedInfo = null;
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001943 CatLog.d(LOG_TAG, "Event :" + event);
Preeti Ahuja95919342013-10-01 18:18:55 -07001944
1945 if (mStkContext[slotId].mSetupEventListSettings != null) {
1946 /* Checks if the event is present in the EventList updated by last
1947 * SetupEventList Proactive Command */
1948 for (int i : mStkContext[slotId].mSetupEventListSettings.eventList) {
1949 if (event == i) {
1950 eventPresent = true;
1951 break;
1952 }
1953 }
1954
1955 /* If Event is present send the response to ICC */
1956 if (eventPresent == true) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001957 CatLog.d(LOG_TAG, " Event " + event + "exists in the EventList");
Preeti Ahuja95919342013-10-01 18:18:55 -07001958
1959 switch (event) {
Yoshiaki Nakafb997252017-09-19 20:14:58 +09001960 case USER_ACTIVITY_EVENT:
Preeti Ahuja560be362014-11-25 19:38:24 -08001961 case IDLE_SCREEN_AVAILABLE_EVENT:
1962 sendSetUpEventResponse(event, addedInfo, slotId);
1963 removeSetUpEvent(event, slotId);
1964 break;
Preeti Ahuja95919342013-10-01 18:18:55 -07001965 case LANGUAGE_SELECTION_EVENT:
1966 String language = mContext
1967 .getResources().getConfiguration().locale.getLanguage();
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001968 CatLog.d(LOG_TAG, "language: " + language);
Preeti Ahuja95919342013-10-01 18:18:55 -07001969 // Each language code is a pair of alpha-numeric characters.
1970 // Each alpha-numeric character shall be coded on one byte
1971 // using the SMS default 7-bit coded alphabet
1972 addedInfo = GsmAlphabet.stringToGsm8BitPacked(language);
1973 sendSetUpEventResponse(event, addedInfo, slotId);
1974 break;
1975 default:
1976 break;
1977 }
1978 } else {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001979 CatLog.e(LOG_TAG, " Event does not exist in the EventList");
Preeti Ahuja95919342013-10-01 18:18:55 -07001980 }
1981 } else {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001982 CatLog.e(LOG_TAG, "SetupEventList is not received. Ignoring the event: " + event);
Preeti Ahuja95919342013-10-01 18:18:55 -07001983 }
1984 }
1985
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001986 private void removeSetUpEvent(int event, int slotId) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09001987 CatLog.d(LOG_TAG, "Remove Event :" + event);
Preeti Ahuja95919342013-10-01 18:18:55 -07001988
1989 if (mStkContext[slotId].mSetupEventListSettings != null) {
1990 /*
1991 * Make new Eventlist without the event
1992 */
1993 for (int i = 0; i < mStkContext[slotId].mSetupEventListSettings.eventList.length; i++) {
1994 if (event == mStkContext[slotId].mSetupEventListSettings.eventList[i]) {
1995 mStkContext[slotId].mSetupEventListSettings.eventList[i] = INVALID_SETUP_EVENT;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09001996
1997 switch (event) {
Yoshiaki Nakafb997252017-09-19 20:14:58 +09001998 case USER_ACTIVITY_EVENT:
1999 // The broadcast receiver can be unregistered
2000 // as the event has already been sent to the card.
2001 unregisterUserActivityReceiver();
2002 break;
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09002003 case IDLE_SCREEN_AVAILABLE_EVENT:
2004 // The process observer can be unregistered
2005 // as the idle screen has already been available.
Malcolm Chen549e21a2020-01-10 15:57:10 -08002006 unregisterHomeVisibilityObserver();
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09002007 break;
2008 default:
2009 break;
2010 }
Preeti Ahuja95919342013-10-01 18:18:55 -07002011 break;
2012 }
2013 }
2014 }
2015 }
2016
2017 private void launchEventMessage(int slotId) {
2018 launchEventMessage(slotId, mStkContext[slotId].mCurrentCmd.geTextMessage());
2019 }
2020
Wink Savillee68857d2014-10-17 15:23:05 -07002021 private void launchEventMessage(int slotId, TextMessage msg) {
Ryuto Sawada2ba20cc2015-12-28 17:10:35 +01002022 if (msg == null || msg.text == null || (msg.text != null && msg.text.length() == 0)) {
Wink Savillee68857d2014-10-17 15:23:05 -07002023 CatLog.d(LOG_TAG, "launchEventMessage return");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002024 return;
2025 }
Wink Savillee68857d2014-10-17 15:23:05 -07002026
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002027 Toast toast = new Toast(mContext.getApplicationContext());
2028 LayoutInflater inflate = (LayoutInflater) mContext
2029 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
2030 View v = inflate.inflate(R.layout.stk_event_msg, null);
2031 TextView tv = (TextView) v
2032 .findViewById(com.android.internal.R.id.message);
2033 ImageView iv = (ImageView) v
2034 .findViewById(com.android.internal.R.id.icon);
2035 if (msg.icon != null) {
2036 iv.setImageBitmap(msg.icon);
2037 } else {
2038 iv.setVisibility(View.GONE);
2039 }
Preeti Ahujaf33bf392013-09-28 19:11:31 +05302040 /* In case of 'self explanatory' stkapp should display the specified
2041 * icon in proactive command (but not the alpha string).
2042 * If icon is non-self explanatory and if the icon could not be displayed
2043 * then alpha string or text data should be displayed
2044 * Ref: ETSI 102.223,section 6.5.4
2045 */
2046 if (mStkContext[slotId].mCurrentCmd.hasIconLoadFailed() ||
2047 msg.icon == null || !msg.iconSelfExplanatory) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002048 tv.setText(msg.text);
2049 }
2050
2051 toast.setView(v);
2052 toast.setDuration(Toast.LENGTH_LONG);
2053 toast.setGravity(Gravity.BOTTOM, 0, 0);
2054 toast.show();
2055 }
2056
Wink Savillee68857d2014-10-17 15:23:05 -07002057 private void launchConfirmationDialog(TextMessage msg, int slotId) {
2058 msg.title = mStkContext[slotId].lastSelectedItem;
2059 Intent newIntent = new Intent();
2060 String targetActivity = STK_DIALOG_ACTIVITY_NAME;
2061 String uriString = STK_DIALOG_URI + System.currentTimeMillis();
2062 //Set unique URI to create a new instance of activity for different slotId.
2063 Uri uriData = Uri.parse(uriString);
2064
Yuta Uife965802017-11-07 20:12:37 +09002065 newIntent.setClassName(this, targetActivity);
2066 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
2067 | Intent.FLAG_ACTIVITY_NO_HISTORY
2068 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
2069 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
2070 newIntent.putExtra("TEXT", msg);
2071 newIntent.putExtra(SLOT_ID, slotId);
2072 newIntent.setData(uriData);
2073 startActivity(newIntent);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002074 }
2075
2076 private void launchBrowser(BrowserSettings settings) {
2077 if (settings == null) {
2078 return;
2079 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002080
Abhishek Adappa840c82f2013-02-26 10:19:49 -08002081 Uri data = null;
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07002082 String url;
2083 if (settings.url == null) {
Abhishek Adappa840c82f2013-02-26 10:19:49 -08002084 // if the command did not contain a URL,
2085 // launch the browser to the default homepage.
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002086 CatLog.d(LOG_TAG, "no url data provided by proactive command." +
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07002087 " launching browser with stk default URL ... ");
2088 url = SystemProperties.get(STK_BROWSER_DEFAULT_URL_SYSPROP,
2089 "http://www.google.com");
2090 } else {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002091 CatLog.d(LOG_TAG, "launch browser command has attached url = " + settings.url);
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07002092 url = settings.url;
Abhishek Adappa840c82f2013-02-26 10:19:49 -08002093 }
David Brown7c03cfe2011-10-20 15:36:12 -07002094
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07002095 if (url.startsWith("http://") || url.startsWith("https://")) {
2096 data = Uri.parse(url);
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002097 CatLog.d(LOG_TAG, "launching browser with url = " + url);
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07002098 } else {
2099 String modifiedUrl = "http://" + url;
2100 data = Uri.parse(modifiedUrl);
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002101 CatLog.d(LOG_TAG, "launching browser with modified url = " + modifiedUrl);
Preeti Ahujaa7cdca22013-10-01 18:20:56 -07002102 }
2103
2104 Intent intent = new Intent(Intent.ACTION_VIEW);
2105 intent.setData(data);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002106 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2107 switch (settings.mode) {
2108 case USE_EXISTING_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002109 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
2110 break;
2111 case LAUNCH_NEW_BROWSER:
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002112 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
2113 break;
2114 case LAUNCH_IF_NOT_ALREADY_LAUNCHED:
2115 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
2116 break;
2117 }
2118 // start browser activity
2119 startActivity(intent);
2120 // a small delay, let the browser start, before processing the next command.
Wink Saville79085fc2009-06-09 10:27:23 -07002121 // this is good for scenarios where a related DISPLAY TEXT command is
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002122 // followed immediately.
2123 try {
Ryuto Sawada350aaa62016-06-13 14:47:22 +09002124 Thread.sleep(3000);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002125 } catch (InterruptedException e) {}
2126 }
2127
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09002128 private void cancelIdleText(int slotId) {
Malcolm Chen549e21a2020-01-10 15:57:10 -08002129 unregisterHomeVisibilityObserver(AppInterface.CommandType.SET_UP_IDLE_MODE_TEXT, slotId);
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09002130 mNotificationManager.cancel(getNotificationId(slotId));
2131 mStkContext[slotId].mIdleModeTextCmd = null;
2132 mStkContext[slotId].mIdleModeTextVisible = false;
2133 }
2134
Wink Savillee68857d2014-10-17 15:23:05 -07002135 private void launchIdleText(int slotId) {
Preeti Ahuja560be362014-11-25 19:38:24 -08002136 TextMessage msg = mStkContext[slotId].mIdleModeTextCmd.geTextMessage();
dujin.cha2a0eb2a2011-11-11 15:03:57 +09002137
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09002138 if (msg != null && !TextUtils.isEmpty(msg.text)) {
Preeti Ahuja95919342013-10-01 18:18:55 -07002139 CatLog.d(LOG_TAG, "launchIdleText - text[" + msg.text
2140 + "] iconSelfExplanatory[" + msg.iconSelfExplanatory
2141 + "] icon[" + msg.icon + "], sim id: " + slotId);
Wink Savillee68857d2014-10-17 15:23:05 -07002142 CatLog.d(LOG_TAG, "Add IdleMode text");
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01002143 PendingIntent pendingIntent = PendingIntent.getService(mContext, 0,
Jordan Liu79bc9422021-02-19 15:29:14 -08002144 new Intent(mContext, StkAppService.class), PendingIntent.FLAG_IMMUTABLE);
fionaxu805eb572017-05-02 10:57:30 -07002145 createAllChannels();
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01002146 final Notification.Builder notificationBuilder = new Notification.Builder(
fionaxu2c91c752017-04-21 18:11:57 -07002147 StkAppService.this, STK_NOTIFICATION_CHANNEL_ID);
Yoshiaki Naka8143ee92020-08-15 14:34:00 +09002148 setNotificationTitle(slotId, notificationBuilder);
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01002149 notificationBuilder
Sooraj Sasindran2b44d5b2020-01-29 15:17:48 -08002150 .setSmallIcon(R.drawable.stat_notify_sim_toolkit);
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01002151 notificationBuilder.setContentIntent(pendingIntent);
2152 notificationBuilder.setOngoing(true);
Yuta Uife965802017-11-07 20:12:37 +09002153 notificationBuilder.setOnlyAlertOnce(true);
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01002154 // Set text and icon for the status bar and notification body.
Preeti Ahujaf33bf392013-09-28 19:11:31 +05302155 if (mStkContext[slotId].mIdleModeTextCmd.hasIconLoadFailed() ||
2156 !msg.iconSelfExplanatory) {
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01002157 notificationBuilder.setContentText(msg.text);
Christopher Posselwhite2ad2ab72013-05-27 07:51:06 +02002158 notificationBuilder.setTicker(msg.text);
samalinc7f3bdf2018-04-26 15:04:31 +08002159 notificationBuilder.setStyle(new Notification.BigTextStyle(notificationBuilder)
2160 .bigText(msg.text));
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01002161 }
2162 if (msg.icon != null) {
2163 notificationBuilder.setLargeIcon(msg.icon);
2164 } else {
2165 Bitmap bitmapIcon = BitmapFactory.decodeResource(StkAppService.this
2166 .getResources().getSystem(),
Sooraj Sasindran2b44d5b2020-01-29 15:17:48 -08002167 R.drawable.stat_notify_sim_toolkit);
Alex Khlivnuik50e0a1d2013-01-25 12:50:48 +01002168 notificationBuilder.setLargeIcon(bitmapIcon);
2169 }
Selim Cinek62eb3fe2014-08-27 17:52:23 +02002170 notificationBuilder.setColor(mContext.getResources().getColor(
2171 com.android.internal.R.color.system_notification_accent_color));
Wink Savillee68857d2014-10-17 15:23:05 -07002172 mNotificationManager.notify(getNotificationId(slotId), notificationBuilder.build());
Yoshiaki Naka62bfb0d2017-10-07 16:42:08 +09002173 mStkContext[slotId].mIdleModeTextVisible = true;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002174 }
2175 }
2176
Yoshiaki Naka8143ee92020-08-15 14:34:00 +09002177 private void setNotificationTitle(int slotId, Notification.Builder builder) {
2178 Menu menu = getMainMenu(slotId);
2179 if (menu == null || TextUtils.isEmpty(menu.title)
2180 || TextUtils.equals(menu.title, getResources().getString(R.string.app_name))) {
2181 // No need to set a content title in the content area if no title (alpha identifier
2182 // of SET-UP MENU command) is available for the specified slot or the title is same
2183 // as the application label.
2184 return;
2185 }
2186
2187 for (int index = 0; index < mSimCount; index++) {
2188 if (index != slotId) {
2189 Menu otherMenu = getMainMenu(index);
2190 if (otherMenu != null && !TextUtils.equals(menu.title, otherMenu.title)) {
2191 // Set the title (alpha identifier of SET-UP MENU command) as the content title
2192 // to differentiate it from other main menu with different alpha identifier
2193 // (including null) is available.
2194 builder.setContentTitle(menu.title);
2195 return;
2196 }
2197 }
2198 }
2199 }
2200
fionaxu805eb572017-05-02 10:57:30 -07002201 /** Creates the notification channel and registers it with NotificationManager.
2202 * If a channel with the same ID is already registered, NotificationManager will
2203 * ignore this call.
2204 */
2205 private void createAllChannels() {
Yuta Uife965802017-11-07 20:12:37 +09002206 NotificationChannel notificationChannel = new NotificationChannel(
fionaxu805eb572017-05-02 10:57:30 -07002207 STK_NOTIFICATION_CHANNEL_ID,
2208 getResources().getString(R.string.stk_channel_name),
Yuta Uife965802017-11-07 20:12:37 +09002209 NotificationManager.IMPORTANCE_DEFAULT);
2210
2211 notificationChannel.enableVibration(true);
2212 notificationChannel.setVibrationPattern(VIBRATION_PATTERN);
2213
2214 mNotificationManager.createNotificationChannel(notificationChannel);
fionaxu805eb572017-05-02 10:57:30 -07002215 }
2216
Wink Savillee68857d2014-10-17 15:23:05 -07002217 private void launchToneDialog(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002218 Intent newIntent = new Intent(this, ToneDialog.class);
Wink Savillee68857d2014-10-17 15:23:05 -07002219 String uriString = STK_TONE_URI + slotId;
2220 Uri uriData = Uri.parse(uriString);
2221 //Set unique URI to create a new instance of activity for different slotId.
2222 CatLog.d(LOG_TAG, "launchToneDialog, slotId: " + slotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002223 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
2224 | Intent.FLAG_ACTIVITY_NO_HISTORY
2225 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
Wink Savillee68857d2014-10-17 15:23:05 -07002226 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
2227 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
2228 newIntent.putExtra("TONE", mStkContext[slotId].mCurrentCmd.getToneSettings());
2229 newIntent.putExtra(SLOT_ID, slotId);
2230 newIntent.setData(uriData);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002231 startActivity(newIntent);
2232 }
2233
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302234 private void handlePlayTone(int slotId) {
2235 TextMessage toneMsg = mStkContext[slotId].mCurrentCmd.geTextMessage();
2236
2237 boolean showUser = true;
2238 boolean displayDialog = true;
2239 Resources resource = Resources.getSystem();
2240 try {
2241 displayDialog = !resource.getBoolean(
Sooraj Sasindran2b44d5b2020-01-29 15:17:48 -08002242 R.bool.config_stkNoAlphaUsrCnf);
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302243 } catch (NotFoundException e) {
2244 displayDialog = true;
2245 }
2246
2247 // As per the spec 3GPP TS 11.14, 6.4.5. Play Tone.
2248 // If there is no alpha identifier tlv present, UE may show the
2249 // user information. 'config_stkNoAlphaUsrCnf' value will decide
2250 // whether to show it or not.
2251 // If alpha identifier tlv is present and its data is null, play only tone
2252 // without showing user any information.
2253 // Alpha Id is Present, but the text data is null.
2254 if ((toneMsg.text != null ) && (toneMsg.text.equals(""))) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002255 CatLog.d(LOG_TAG, "Alpha identifier data is null, play only tone");
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302256 showUser = false;
2257 }
2258 // Alpha Id is not present AND we need to show info to the user.
2259 if (toneMsg.text == null && displayDialog) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002260 CatLog.d(LOG_TAG, "toneMsg.text " + toneMsg.text
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302261 + " Starting ToneDialog activity with default message.");
2262 toneMsg.text = getResources().getString(R.string.default_tone_dialog_msg);
2263 showUser = true;
2264 }
2265 // Dont show user info, if config setting is true.
2266 if (toneMsg.text == null && !displayDialog) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002267 CatLog.d(LOG_TAG, "config value stkNoAlphaUsrCnf is true");
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302268 showUser = false;
2269 }
2270
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002271 CatLog.d(LOG_TAG, "toneMsg.text: " + toneMsg.text + "showUser: " +showUser +
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302272 "displayDialog: " +displayDialog);
2273 playTone(showUser, slotId);
2274 }
2275
2276 private void playTone(boolean showUserInfo, int slotId) {
2277 // Start playing tone and vibration
2278 ToneSettings settings = mStkContext[slotId].mCurrentCmd.getToneSettings();
2279 if (null == settings) {
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002280 CatLog.d(LOG_TAG, "null settings, not playing tone.");
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302281 return;
2282 }
2283
2284 mVibrator = (Vibrator)getSystemService(VIBRATOR_SERVICE);
2285 mTonePlayer = new TonePlayer();
2286 mTonePlayer.play(settings.tone);
2287 int timeout = StkApp.calculateDurationInMilis(settings.duration);
2288 if (timeout == 0) {
2289 timeout = StkApp.TONE_DEFAULT_TIMEOUT;
2290 }
2291
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +09002292 Message msg = mServiceHandler.obtainMessage(OP_STOP_TONE, 0, slotId,
2293 (showUserInfo ? PLAY_TONE_WITH_DIALOG : PLAY_TONE_ONLY));
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302294 mServiceHandler.sendMessageDelayed(msg, timeout);
2295 if (settings.vibrate) {
2296 mVibrator.vibrate(timeout);
2297 }
2298
2299 // Start Tone dialog Activity to show user the information.
2300 if (showUserInfo) {
2301 Intent newIntent = new Intent(sInstance, ToneDialog.class);
2302 String uriString = STK_TONE_URI + slotId;
2303 Uri uriData = Uri.parse(uriString);
2304 newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302305 | Intent.FLAG_ACTIVITY_SINGLE_TOP
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302306 | getFlagActivityNoUserAction(InitiatedByUserAction.unknown, slotId));
2307 newIntent.putExtra("TEXT", mStkContext[slotId].mCurrentCmd.geTextMessage());
2308 newIntent.putExtra(SLOT_ID, slotId);
2309 newIntent.setData(uriData);
2310 startActivity(newIntent);
2311 }
2312 }
2313
2314 private void finishToneDialogActivity() {
2315 Intent finishIntent = new Intent(FINISH_TONE_ACTIVITY_ACTION);
2316 sendBroadcast(finishIntent);
2317 }
2318
2319 private void handleStopTone(Message msg, int slotId) {
2320 int resId = 0;
2321
2322 // Stop the play tone in following cases:
2323 // 1.OP_STOP_TONE: play tone timer expires.
2324 // 2.STOP_TONE_USER: user pressed the back key.
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +09002325 if (msg.what == OP_STOP_TONE) {
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302326 resId = RES_ID_DONE;
2327 // Dismiss Tone dialog, after finishing off playing the tone.
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +09002328 if (PLAY_TONE_WITH_DIALOG.equals((Integer) msg.obj)) finishToneDialogActivity();
2329 } else if (msg.what == OP_STOP_TONE_USER) {
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302330 resId = RES_ID_END_SESSION;
2331 }
2332
2333 sendResponse(resId, slotId, true);
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +09002334
2335 mServiceHandler.removeMessages(OP_STOP_TONE);
2336 mServiceHandler.removeMessages(OP_STOP_TONE_USER);
2337
Takanori Nakanob82c8752019-04-01 14:47:07 +09002338 if (mTonePlayer != null) {
Srikanth Chintala89aa6602014-03-14 16:26:57 +05302339 mTonePlayer.stop();
2340 mTonePlayer.release();
2341 mTonePlayer = null;
2342 }
2343 if (mVibrator != null) {
2344 mVibrator.cancel();
2345 mVibrator = null;
2346 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002347 }
2348
Yoshiaki Nakafac708c2020-01-22 19:49:27 +09002349 boolean isNoTonePlaying() {
2350 return mTonePlayer == null ? true : false;
2351 }
2352
Takanori Nakano49b12722016-02-16 14:34:14 +09002353 private void launchOpenChannelDialog(final int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -07002354 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002355 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07002356 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002357 return;
2358 }
2359
2360 msg.title = getResources().getString(R.string.stk_dialog_title);
2361 if (msg.text == null) {
2362 msg.text = getResources().getString(R.string.default_open_channel_msg);
2363 }
2364
arunvoddu8c8f5042022-05-23 09:38:20 +00002365 mAlertDialog = new AlertDialog.Builder(mContext)
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002366 .setIconAttribute(android.R.attr.alertDialogIcon)
2367 .setTitle(msg.title)
2368 .setMessage(msg.text)
2369 .setCancelable(false)
2370 .setPositiveButton(getResources().getString(R.string.stk_dialog_accept),
2371 new DialogInterface.OnClickListener() {
2372 public void onClick(DialogInterface dialog, int which) {
2373 Bundle args = new Bundle();
2374 args.putInt(RES_ID, RES_ID_CHOICE);
2375 args.putInt(CHOICE, YES);
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +09002376 sendResponse(args, slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002377 }
2378 })
2379 .setNegativeButton(getResources().getString(R.string.stk_dialog_reject),
2380 new DialogInterface.OnClickListener() {
2381 public void onClick(DialogInterface dialog, int which) {
2382 Bundle args = new Bundle();
2383 args.putInt(RES_ID, RES_ID_CHOICE);
2384 args.putInt(CHOICE, NO);
Yoshiaki Nakab80f8ce2019-04-25 14:36:03 +09002385 sendResponse(args, slotId);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002386 }
2387 })
2388 .create();
2389
arunvoddu8c8f5042022-05-23 09:38:20 +00002390 mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002391 if (!mContext.getResources().getBoolean(
Sooraj Sasindran2b44d5b2020-01-29 15:17:48 -08002392 R.bool.config_sf_slowBlur)) {
arunvoddu8c8f5042022-05-23 09:38:20 +00002393 mAlertDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002394 }
2395
arunvoddu8c8f5042022-05-23 09:38:20 +00002396 mAlertDialog.show();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002397 }
2398
Wink Savillee68857d2014-10-17 15:23:05 -07002399 private void launchTransientEventMessage(int slotId) {
2400 TextMessage msg = mStkContext[slotId].mCurrentCmd.geTextMessage();
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002401 if (msg == null) {
Wink Savillee68857d2014-10-17 15:23:05 -07002402 CatLog.d(LOG_TAG, "msg is null, return here");
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002403 return;
2404 }
2405
2406 msg.title = getResources().getString(R.string.stk_dialog_title);
2407
2408 final AlertDialog dialog = new AlertDialog.Builder(mContext)
2409 .setIconAttribute(android.R.attr.alertDialogIcon)
2410 .setTitle(msg.title)
2411 .setMessage(msg.text)
2412 .setCancelable(false)
2413 .setPositiveButton(getResources().getString(android.R.string.ok),
2414 new DialogInterface.OnClickListener() {
2415 public void onClick(DialogInterface dialog, int which) {
2416 }
2417 })
2418 .create();
2419
2420 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
Sooraj Sasindran2b44d5b2020-01-29 15:17:48 -08002421 if (!mContext.getResources().getBoolean(R.bool.config_sf_slowBlur)) {
Kazuhiro Ondo764167c2011-10-21 16:05:05 -05002422 dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
2423 }
2424
2425 dialog.show();
2426 }
2427
Wink Savillee68857d2014-10-17 15:23:05 -07002428 private int getNotificationId(int slotId) {
2429 int notifyId = STK_NOTIFICATION_ID;
2430 if (slotId >= 0 && slotId < mSimCount) {
2431 notifyId += slotId;
2432 } else {
2433 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
2434 }
2435 CatLog.d(LOG_TAG, "getNotificationId, slotId: " + slotId + ", notifyId: " + notifyId);
2436 return notifyId;
2437 }
2438
2439 private String getItemName(int itemId, int slotId) {
2440 Menu menu = mStkContext[slotId].mCurrentCmd.getMenu();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002441 if (menu == null) {
2442 return null;
2443 }
2444 for (Item item : menu.items) {
2445 if (item.id == itemId) {
2446 return item.text;
2447 }
2448 }
2449 return null;
2450 }
2451
Wink Savillee68857d2014-10-17 15:23:05 -07002452 private boolean removeMenu(int slotId) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002453 try {
Wink Savillee68857d2014-10-17 15:23:05 -07002454 if (mStkContext[slotId].mCurrentMenu.items.size() == 1 &&
2455 mStkContext[slotId].mCurrentMenu.items.get(0) == null) {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002456 return true;
2457 }
2458 } catch (NullPointerException e) {
Wink Savillee68857d2014-10-17 15:23:05 -07002459 CatLog.d(LOG_TAG, "Unable to get Menu's items size");
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002460 return true;
2461 }
2462 return false;
2463 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05302464
Yoshiaki Naka58e07652019-04-26 17:58:52 +09002465 private boolean uninstallIfUnnecessary() {
2466 for (int slot = 0; slot < mSimCount; slot++) {
2467 if (mStkContext[slot].mMainCmd != null) {
2468 return false;
2469 }
2470 }
2471 CatLog.d(LOG_TAG, "Uninstall App");
2472 StkAppInstaller.uninstall(this);
2473 return true;
2474 }
2475
Malcolm Chen616ea282019-10-24 19:53:48 -07002476 synchronized StkContext getStkContext(int slotId) {
Wink Savillee68857d2014-10-17 15:23:05 -07002477 if (slotId >= 0 && slotId < mSimCount) {
2478 return mStkContext[slotId];
2479 } else {
2480 CatLog.d(LOG_TAG, "invalid slotId: " + slotId);
2481 return null;
2482 }
2483 }
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05302484
2485 private void handleAlphaNotify(Bundle args) {
2486 String alphaString = args.getString(AppInterface.ALPHA_STRING);
2487
Yoshiaki Naka3a980db2019-10-30 17:11:33 +09002488 CatLog.d(LOG_TAG, "Alpha string received from card: " + alphaString);
Preeti Ahuja0f4cf2f2012-08-09 11:45:08 +05302489 Toast toast = Toast.makeText(sInstance, alphaString, Toast.LENGTH_LONG);
2490 toast.setGravity(Gravity.TOP, 0, 0);
2491 toast.show();
2492 }
Srikanth Chintalaba103002015-11-30 10:49:52 -08002493
2494 private boolean isUrlAvailableToLaunchBrowser(BrowserSettings settings) {
2495 String url = SystemProperties.get(STK_BROWSER_DEFAULT_URL_SYSPROP, "");
2496 if (url == "" && settings.url == null) {
2497 return false;
2498 }
2499 return true;
2500 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -08002501}