blob: 49dd501f44aeb43930fed400e5932c85d907f24b [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
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080019import android.app.Activity;
w302348bf95af2015-01-09 10:54:41 -080020import android.app.AlarmManager;
Sanket Padawe7b70fb42017-04-05 15:35:34 -070021import android.app.AlertDialog;
w302348bf95af2015-01-09 10:54:41 -080022import android.content.Context;
Sanket Padawe7b70fb42017-04-05 15:35:34 -070023import android.content.DialogInterface;
Yoshiaki Naka711656a2018-05-30 17:48:31 +090024import android.content.Intent;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080025import android.os.Bundle;
w302348bf95af2015-01-09 10:54:41 -080026import android.os.SystemClock;
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +090027import android.telephony.SubscriptionManager;
Takanori Nakano9ecdba72017-07-21 15:27:49 +090028import android.text.TextUtils;
29import android.view.LayoutInflater;
30import android.view.View;
31import android.widget.ImageView;
32import android.widget.TextView;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080033
Yoshiaki Naka711656a2018-05-30 17:48:31 +090034import com.android.internal.telephony.cat.CatLog;
35import com.android.internal.telephony.cat.TextMessage;
Jayachandran C1416ac52019-10-23 18:12:48 -070036import com.android.internal.telephony.util.TelephonyUtils;
Yoshiaki Naka711656a2018-05-30 17:48:31 +090037
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080038/**
w302348bf95af2015-01-09 10:54:41 -080039 * AlertDialog used for DISPLAY TEXT commands.
Wink Saville79085fc2009-06-09 10:27:23 -070040 *
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080041 */
Sanket Padawe7b70fb42017-04-05 15:35:34 -070042public class StkDialogActivity extends Activity {
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080043 // members
Yoshiaki Naka3a980db2019-10-30 17:11:33 +090044 private static final String LOG_TAG =
45 new Object(){}.getClass().getEnclosingClass().getSimpleName();
Wink Savillee68857d2014-10-17 15:23:05 -070046 TextMessage mTextMsg = null;
47 private int mSlotId = -1;
48 private StkAppService appService = StkAppService.getInstance();
w302348bf95af2015-01-09 10:54:41 -080049 // Determines whether Terminal Response (TR) has been sent
Johannes Carlssonef243a22011-10-25 10:37:24 +020050 private boolean mIsResponseSent = false;
w302348bf95af2015-01-09 10:54:41 -080051 // Utilize AlarmManager for real-time countdown
Yoshiaki Naka711656a2018-05-30 17:48:31 +090052 private static final String DIALOG_ALARM_TAG = LOG_TAG;
53 private static final long NO_DIALOG_ALARM = -1;
54 private long mAlarmTime = NO_DIALOG_ALARM;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080055
Takanori Nakano1d3f3c12016-08-30 10:34:24 +090056 // Keys for saving the state of the dialog in the bundle
57 private static final String TEXT_KEY = "text";
Yoshiaki Naka711656a2018-05-30 17:48:31 +090058 private static final String ALARM_TIME_KEY = "alarm_time";
59 private static final String RESPONSE_SENT_KEY = "response_sent";
Takanori Nakano1d3f3c12016-08-30 10:34:24 +090060 private static final String SLOT_ID_KEY = "slotid";
Yoshiaki Nakaa1cea462018-08-09 20:33:36 +090061
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080062
Takanori Nakanocbe32d32017-07-20 17:10:46 +090063 private AlertDialog mAlertDialog;
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080064
65 @Override
Takanori Nakano1d3f3c12016-08-30 10:34:24 +090066 protected void onCreate(Bundle savedInstanceState) {
67 super.onCreate(savedInstanceState);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080068
w302348bf95af2015-01-09 10:54:41 -080069 CatLog.d(LOG_TAG, "onCreate, sim id: " + mSlotId);
Ryuto Sawadaba9b86b2016-10-03 14:03:16 +090070
71 // appService can be null if this activity is automatically recreated by the system
72 // with the saved instance state right after the phone process is killed.
73 if (appService == null) {
74 CatLog.d(LOG_TAG, "onCreate - appService is null");
75 finish();
76 return;
77 }
78
w302348bf95af2015-01-09 10:54:41 -080079 // New Dialog is created - set to no response sent
80 mIsResponseSent = false;
81
Takanori Nakanocbe32d32017-07-20 17:10:46 +090082 AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080083
Sanket Padawe7b70fb42017-04-05 15:35:34 -070084 alertDialogBuilder.setPositiveButton(R.string.button_ok, new
85 DialogInterface.OnClickListener() {
86 @Override
87 public void onClick(DialogInterface dialog, int id) {
88 CatLog.d(LOG_TAG, "OK Clicked!, mSlotId: " + mSlotId);
Sanket Padawe7b70fb42017-04-05 15:35:34 -070089 sendResponse(StkAppService.RES_ID_CONFIRM, true);
Sanket Padawe7b70fb42017-04-05 15:35:34 -070090 }
91 });
The Android Open Source Project9d9730a2009-03-03 19:32:37 -080092
Sanket Padawe7b70fb42017-04-05 15:35:34 -070093 alertDialogBuilder.setNegativeButton(R.string.button_cancel, new
94 DialogInterface.OnClickListener() {
95 @Override
96 public void onClick(DialogInterface dialog,int id) {
97 CatLog.d(LOG_TAG, "Cancel Clicked!, mSlotId: " + mSlotId);
Sanket Padawe7b70fb42017-04-05 15:35:34 -070098 sendResponse(StkAppService.RES_ID_CONFIRM, false);
Sanket Padawe7b70fb42017-04-05 15:35:34 -070099 }
100 });
Takuro Nishief00cb12017-07-04 11:46:28 +0900101
102 alertDialogBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() {
103 @Override
104 public void onCancel(DialogInterface dialog) {
105 CatLog.d(LOG_TAG, "Moving backward!, mSlotId: " + mSlotId);
Takuro Nishief00cb12017-07-04 11:46:28 +0900106 sendResponse(StkAppService.RES_ID_BACKWARD);
Takuro Nishief00cb12017-07-04 11:46:28 +0900107 }
108 });
109
Sanket Padawe7b70fb42017-04-05 15:35:34 -0700110 alertDialogBuilder.create();
w302348bf95af2015-01-09 10:54:41 -0800111
Takanori Nakanocbe32d32017-07-20 17:10:46 +0900112 initFromIntent(getIntent());
113 if (mTextMsg == null) {
114 finish();
115 return;
116 }
117
118 if (!mTextMsg.responseNeeded) {
119 alertDialogBuilder.setNegativeButton(null, null);
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +0900120 // Register the instance of this activity because the dialog displayed for DISPLAY TEXT
121 // command with an immediate response object should disappear when the terminal receives
122 // a subsequent proactive command containing display data.
123 appService.getStkContext(mSlotId).setImmediateDialogInstance(this);
Anna Suzuki35309b02019-02-15 16:24:59 +0900124 } else {
125 appService.getStkContext(mSlotId).setPendingDialogInstance(this);
Takanori Nakanocbe32d32017-07-20 17:10:46 +0900126 }
127
128 alertDialogBuilder.setTitle(mTextMsg.title);
129
Takanori Nakano9ecdba72017-07-21 15:27:49 +0900130 LayoutInflater inflater = this.getLayoutInflater();
131 View dialogView = inflater.inflate(R.layout.stk_msg_dialog, null);
132 alertDialogBuilder.setView(dialogView);
133 TextView tv = (TextView) dialogView.findViewById(R.id.message);
134 ImageView iv = (ImageView) dialogView.findViewById(R.id.icon);
135
136 if (mTextMsg.icon != null) {
137 iv.setImageBitmap(mTextMsg.icon);
138 } else {
139 iv.setVisibility(View.GONE);
140 }
141
142 // Per spec, only set text if the icon is not provided or not self-explanatory
143 if ((mTextMsg.icon == null || !mTextMsg.iconSelfExplanatory)
144 && !TextUtils.isEmpty(mTextMsg.text)) {
145 tv.setText(mTextMsg.text);
146 } else {
147 tv.setVisibility(View.GONE);
Takanori Nakanocbe32d32017-07-20 17:10:46 +0900148 }
149
150 mAlertDialog = alertDialogBuilder.create();
151 mAlertDialog.setCanceledOnTouchOutside(false);
152 mAlertDialog.show();
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800153 }
154
155 @Override
156 public void onResume() {
157 super.onResume();
Wink Savillee68857d2014-10-17 15:23:05 -0700158 CatLog.d(LOG_TAG, "onResume - mIsResponseSent[" + mIsResponseSent +
159 "], sim id: " + mSlotId);
Christopher Posselwhitecfe4d7f2013-09-04 09:01:50 +0200160 /*
Preeti Ahuja414bc412013-06-25 19:31:49 -0700161 * If the userClear flag is set and dialogduration is set to 0, the display Text
162 * should be displayed to user forever until some high priority event occurs
163 * (incoming call, MMI code execution etc as mentioned under section
164 * ETSI 102.223, 6.4.1)
Christopher Posselwhitecfe4d7f2013-09-04 09:01:50 +0200165 */
Preeti Ahuja414bc412013-06-25 19:31:49 -0700166 if (StkApp.calculateDurationInMilis(mTextMsg.duration) == 0 &&
Sanket Padawe7b70fb42017-04-05 15:35:34 -0700167 !mTextMsg.responseNeeded && mTextMsg.userClear) {
w302348bf95af2015-01-09 10:54:41 -0800168 CatLog.d(LOG_TAG, "User should clear text..showing message forever");
Christopher Posselwhitecfe4d7f2013-09-04 09:01:50 +0200169 return;
170 }
171
Preeti Ahuja95919342013-10-01 18:18:55 -0700172 appService.setDisplayTextDlgVisibility(true, mSlotId);
w302348bf95af2015-01-09 10:54:41 -0800173
174 /*
175 * When another activity takes the foreground, we do not want the Terminal
176 * Response timer to be restarted when our activity resumes. Hence we will
177 * check if there is an existing timer, and resume it. In this way we will
Sanket Padawe7b70fb42017-04-05 15:35:34 -0700178 * inform the SIM in correct time when there is no response from the User
w302348bf95af2015-01-09 10:54:41 -0800179 * to a dialog.
180 */
Yoshiaki Naka711656a2018-05-30 17:48:31 +0900181 if (mAlarmTime == NO_DIALOG_ALARM) {
182 startTimeOut();
w302348bf95af2015-01-09 10:54:41 -0800183 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800184 }
185
186 @Override
187 public void onPause() {
188 super.onPause();
Wink Savillee68857d2014-10-17 15:23:05 -0700189 CatLog.d(LOG_TAG, "onPause, sim id: " + mSlotId);
Preeti Ahuja95919342013-10-01 18:18:55 -0700190 appService.setDisplayTextDlgVisibility(false, mSlotId);
Preeti Ahuja03be6672012-08-30 19:21:25 +0530191
192 /*
193 * do not cancel the timer here cancelTimeOut(). If any higher/lower
194 * priority events such as incoming call, new sms, screen off intent,
195 * notification alerts, user actions such as 'User moving to another activtiy'
196 * etc.. occur during Display Text ongoing session,
197 * this activity would receive 'onPause()' event resulting in
198 * cancellation of the timer. As a result no terminal response is
199 * sent to the card.
200 */
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800201 }
202
203 @Override
Johannes Carlssonef243a22011-10-25 10:37:24 +0200204 protected void onStart() {
w302348bf95af2015-01-09 10:54:41 -0800205 CatLog.d(LOG_TAG, "onStart, sim id: " + mSlotId);
Johannes Carlssonef243a22011-10-25 10:37:24 +0200206 super.onStart();
Johannes Carlssonef243a22011-10-25 10:37:24 +0200207 }
208
209 @Override
210 public void onStop() {
211 super.onStop();
Wink Savillee68857d2014-10-17 15:23:05 -0700212 CatLog.d(LOG_TAG, "onStop - before Send CONFIRM false mIsResponseSent[" +
213 mIsResponseSent + "], sim id: " + mSlotId);
Johannes Carlssonef243a22011-10-25 10:37:24 +0200214 }
215
216 @Override
Wink Savillee68857d2014-10-17 15:23:05 -0700217 public void onDestroy() {
218 super.onDestroy();
219 CatLog.d(LOG_TAG, "onDestroy - mIsResponseSent[" + mIsResponseSent +
220 "], sim id: " + mSlotId);
Takanori Nakanocbe32d32017-07-20 17:10:46 +0900221
222 if (mAlertDialog != null && mAlertDialog.isShowing()) {
223 mAlertDialog.dismiss();
224 mAlertDialog = null;
225 }
226
Ryuto Sawadaba9b86b2016-10-03 14:03:16 +0900227 if (appService == null) {
228 return;
229 }
Wink Savillee68857d2014-10-17 15:23:05 -0700230 // if dialog activity is finished by stkappservice
231 // when receiving OP_LAUNCH_APP from the other SIM, we can not send TR here
232 // , since the dialog cmd is waiting user to process.
Takanori Nakano1d3f3c12016-08-30 10:34:24 +0900233 if (!isChangingConfigurations()) {
234 if (!mIsResponseSent && appService != null && !appService.isDialogPending(mSlotId)) {
235 sendResponse(StkAppService.RES_ID_CONFIRM, false);
236 }
Wink Savillee68857d2014-10-17 15:23:05 -0700237 }
Yoshiaki Naka711656a2018-05-30 17:48:31 +0900238 cancelTimeOut();
Wink Savillee68857d2014-10-17 15:23:05 -0700239 }
240
241 @Override
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800242 public void onSaveInstanceState(Bundle outState) {
243 super.onSaveInstanceState(outState);
244
Yoshiaki Naka711656a2018-05-30 17:48:31 +0900245 CatLog.d(LOG_TAG, "onSaveInstanceState");
246
Takanori Nakano1d3f3c12016-08-30 10:34:24 +0900247 outState.putParcelable(TEXT_KEY, mTextMsg);
Yoshiaki Naka711656a2018-05-30 17:48:31 +0900248 outState.putBoolean(RESPONSE_SENT_KEY, mIsResponseSent);
249 outState.putLong(ALARM_TIME_KEY, mAlarmTime);
Takanori Nakano1d3f3c12016-08-30 10:34:24 +0900250 outState.putInt(SLOT_ID_KEY, mSlotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800251 }
252
253 @Override
254 public void onRestoreInstanceState(Bundle savedInstanceState) {
255 super.onRestoreInstanceState(savedInstanceState);
Wink Saville79085fc2009-06-09 10:27:23 -0700256
Yoshiaki Naka711656a2018-05-30 17:48:31 +0900257 CatLog.d(LOG_TAG, "onRestoreInstanceState");
258
Takanori Nakano1d3f3c12016-08-30 10:34:24 +0900259 mTextMsg = savedInstanceState.getParcelable(TEXT_KEY);
Yoshiaki Naka711656a2018-05-30 17:48:31 +0900260 mIsResponseSent = savedInstanceState.getBoolean(RESPONSE_SENT_KEY);
261 mAlarmTime = savedInstanceState.getLong(ALARM_TIME_KEY, NO_DIALOG_ALARM);
Takanori Nakano1d3f3c12016-08-30 10:34:24 +0900262 mSlotId = savedInstanceState.getInt(SLOT_ID_KEY);
Yoshiaki Nakaa1cea462018-08-09 20:33:36 +0900263
Yoshiaki Naka711656a2018-05-30 17:48:31 +0900264 if (mAlarmTime != NO_DIALOG_ALARM) {
265 startTimeOut();
266 }
267
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800268 }
269
Preeti Ahuja414bc412013-06-25 19:31:49 -0700270 @Override
271 protected void onNewIntent(Intent intent) {
w302348bf95af2015-01-09 10:54:41 -0800272 CatLog.d(LOG_TAG, "onNewIntent - updating the same Dialog box");
Preeti Ahuja414bc412013-06-25 19:31:49 -0700273 setIntent(intent);
274 }
275
Yoshiaki Naka4c7fb2b2017-08-31 19:25:33 +0900276 @Override
277 public void finish() {
278 super.finish();
279 // Unregister the instance for DISPLAY TEXT command with an immediate response object
280 // as it is unnecessary to ask the service to finish this anymore.
281 if ((appService != null) && (mTextMsg != null) && !mTextMsg.responseNeeded) {
282 if (SubscriptionManager.isValidSlotIndex(mSlotId)) {
283 appService.getStkContext(mSlotId).setImmediateDialogInstance(null);
284 }
285 }
286 }
287
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800288 private void sendResponse(int resId, boolean confirmed) {
Yoshiaki Nakaa1cea462018-08-09 20:33:36 +0900289 cancelTimeOut();
290
Wink Savillee68857d2014-10-17 15:23:05 -0700291 if (mSlotId == -1) {
292 CatLog.d(LOG_TAG, "sim id is invalid");
293 return;
294 }
295
296 if (StkAppService.getInstance() == null) {
297 CatLog.d(LOG_TAG, "Ignore response: id is " + resId);
298 return;
299 }
300
301 CatLog.d(LOG_TAG, "sendResponse resID[" + resId + "] confirmed[" + confirmed + "]");
302
Preeti Ahuja414bc412013-06-25 19:31:49 -0700303 if (mTextMsg.responseNeeded) {
304 Bundle args = new Bundle();
305 args.putInt(StkAppService.OPCODE, StkAppService.OP_RESPONSE);
306 args.putInt(StkAppService.SLOT_ID, mSlotId);
307 args.putInt(StkAppService.RES_ID, resId);
308 args.putBoolean(StkAppService.CONFIRMATION, confirmed);
309 startService(new Intent(this, StkAppService.class).putExtras(args));
310 mIsResponseSent = true;
311 }
Yoshiaki Nakaa1cea462018-08-09 20:33:36 +0900312 if (!isFinishing()) {
313 finish();
314 }
315
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800316 }
317
318 private void sendResponse(int resId) {
319 sendResponse(resId, true);
320 }
321
322 private void initFromIntent(Intent intent) {
323
324 if (intent != null) {
325 mTextMsg = intent.getParcelableExtra("TEXT");
Wink Savillee68857d2014-10-17 15:23:05 -0700326 mSlotId = intent.getIntExtra(StkAppService.SLOT_ID, -1);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800327 } else {
328 finish();
329 }
Wink Savillee68857d2014-10-17 15:23:05 -0700330
Jayachandran C1416ac52019-10-23 18:12:48 -0700331 CatLog.d(LOG_TAG, "initFromIntent - [" + (TelephonyUtils.IS_DEBUGGABLE ? mTextMsg : "********")
Yoshiaki Naka25273c92017-10-31 20:00:33 +0900332 + "], slot id: " + mSlotId);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800333 }
334
335 private void cancelTimeOut() {
Yoshiaki Naka711656a2018-05-30 17:48:31 +0900336 if (mAlarmTime != NO_DIALOG_ALARM) {
337 CatLog.d(LOG_TAG, "cancelTimeOut - slot id: " + mSlotId);
338 AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
339 am.cancel(mAlarmListener);
340 mAlarmTime = NO_DIALOG_ALARM;
w302348bf95af2015-01-09 10:54:41 -0800341 }
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800342 }
343
Yoshiaki Naka711656a2018-05-30 17:48:31 +0900344 private void startTimeOut() {
345 // No need to set alarm if device sent TERMINAL RESPONSE already
346 // and it is required to wait for user to clear the message.
347 if (mIsResponseSent || (mTextMsg.userClear && !mTextMsg.responseNeeded)) {
Wink Savillee68857d2014-10-17 15:23:05 -0700348 return;
Yoshiaki Naka711656a2018-05-30 17:48:31 +0900349 }
350
351 if (mAlarmTime == NO_DIALOG_ALARM) {
352 int duration = StkApp.calculateDurationInMilis(mTextMsg.duration);
353 // If no duration is specified, the timeout set by the terminal manufacturer is applied.
354 if (duration == 0) {
355 if (mTextMsg.userClear) {
356 duration = StkApp.DISP_TEXT_WAIT_FOR_USER_TIMEOUT;
Wink Savillee68857d2014-10-17 15:23:05 -0700357 } else {
Yoshiaki Naka711656a2018-05-30 17:48:31 +0900358 duration = StkApp.DISP_TEXT_CLEAR_AFTER_DELAY_TIMEOUT;
Wink Savillee68857d2014-10-17 15:23:05 -0700359 }
Christopher.Posselwhite1772c042012-11-22 12:15:54 +0100360 }
Yoshiaki Naka711656a2018-05-30 17:48:31 +0900361 mAlarmTime = SystemClock.elapsedRealtime() + duration;
Wink Savillee68857d2014-10-17 15:23:05 -0700362 }
Yoshiaki Naka711656a2018-05-30 17:48:31 +0900363
364 CatLog.d(LOG_TAG, "startTimeOut: " + mAlarmTime + "ms, slot id: " + mSlotId);
365 AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
366 am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, mAlarmTime, DIALOG_ALARM_TAG,
367 mAlarmListener, null);
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800368 }
w302348bf95af2015-01-09 10:54:41 -0800369
Yoshiaki Naka711656a2018-05-30 17:48:31 +0900370 private final AlarmManager.OnAlarmListener mAlarmListener =
371 new AlarmManager.OnAlarmListener() {
372 @Override
373 public void onAlarm() {
374 CatLog.d(LOG_TAG, "The alarm time is reached");
375 mAlarmTime = NO_DIALOG_ALARM;
376 sendResponse(StkAppService.RES_ID_TIMEOUT);
Yoshiaki Naka711656a2018-05-30 17:48:31 +0900377 }
378 };
The Android Open Source Project9d9730a2009-03-03 19:32:37 -0800379}