blob: 5a5d48876bf0a98789f52fcd834fc6f319af4d0f [file] [log] [blame]
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001/*
2 * Copyright (C) 2006 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.phone;
18
19import android.app.Activity;
20import android.app.AlertDialog;
21import android.content.ActivityNotFoundException;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070022import android.content.Context;
23import android.content.Intent;
Jeff Sharkey236e67c2014-04-16 17:21:29 -070024import android.provider.Settings;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070025import android.telephony.PhoneNumberUtils;
26import android.util.Log;
27import android.view.WindowManager;
28
Aravind Sreekumarafc08c52018-04-10 15:34:32 -070029import com.android.internal.telephony.Phone;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070030import com.android.internal.telephony.TelephonyCapabilities;
31
32/**
33 * Helper class to listen for some magic dialpad character sequences
34 * that are handled specially by the Phone app.
35 *
36 * Note the Contacts app also handles these sequences too, so there's a
37 * separate version of this class under apps/Contacts.
38 *
39 * In fact, the most common use case for these special sequences is typing
40 * them from the regular "Dialer" used for outgoing calls, which is part
41 * of the contacts app; see DialtactsActivity and DialpadFragment.
42 * *This* version of SpecialCharSequenceMgr is used for only a few
43 * relatively obscure places in the UI:
44 * - The "SIM network unlock" PIN entry screen (see
45 * IccNetworkDepersonalizationPanel.java)
46 * - The emergency dialer (see EmergencyDialer.java).
47 *
48 * TODO: there's lots of duplicated code between this class and the
49 * corresponding class under apps/Contacts. Let's figure out a way to
50 * unify these two classes (in the framework? in a common shared library?)
51 */
52public class SpecialCharSequenceMgr {
53 private static final String TAG = PhoneGlobals.LOG_TAG;
54 private static final boolean DBG = false;
55
56 private static final String MMI_IMEI_DISPLAY = "*#06#";
57 private static final String MMI_REGULATORY_INFO_DISPLAY = "*#07#";
58
59 /** This class is never instantiated. */
60 private SpecialCharSequenceMgr() {
61 }
62
63 /**
64 * Check for special strings of digits from an input
65 * string.
66 * @param context input Context for the events we handle.
67 * @param input the dial string to be examined.
68 */
69 static boolean handleChars(Context context, String input) {
70 return handleChars(context, input, null);
71 }
72
73 /**
74 * Generally used for the Personal Unblocking Key (PUK) unlocking
75 * case, where we want to be able to maintain a handle to the
76 * calling activity so that we can close it or otherwise display
77 * indication if the PUK code is recognized.
78 *
79 * NOTE: The counterpart to this file in Contacts does
80 * NOT contain the special PUK handling code, since it
81 * does NOT need it. When the device gets into PUK-
82 * locked state, the keyguard comes up and the only way
83 * to unlock the device is through the Emergency dialer,
84 * which is still in the Phone App.
85 *
86 * @param context input Context for the events we handle.
87 * @param input the dial string to be examined.
88 * @param pukInputActivity activity that originated this
89 * PUK call, tracked so that we can close it or otherwise
90 * indicate that special character sequence is
91 * successfully processed. Can be null.
92 * @return true if the input was a special string which has been
93 * handled.
94 */
95 static boolean handleChars(Context context,
96 String input,
97 Activity pukInputActivity) {
98
99 //get rid of the separators so that the string gets parsed correctly
100 String dialString = PhoneNumberUtils.stripSeparators(input);
101
102 if (handleIMEIDisplay(context, dialString)
103 || handleRegulatoryInfoDisplay(context, dialString)
104 || handlePinEntry(context, dialString, pukInputActivity)
105 || handleAdnEntry(context, dialString)
fionaxue559f972017-01-24 22:31:12 -0800106 || handleSecretCode(dialString)) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700107 return true;
108 }
109
110 return false;
111 }
112
113 /**
114 * Variant of handleChars() that looks for the subset of "special
115 * sequences" that are available even if the device is locked.
116 *
117 * (Specifically, these are the sequences that you're allowed to type
118 * in the Emergency Dialer, which is accessible *without* unlocking
119 * the device.)
120 */
121 static boolean handleCharsForLockedDevice(Context context,
122 String input,
123 Activity pukInputActivity) {
124 // Get rid of the separators so that the string gets parsed correctly
125 String dialString = PhoneNumberUtils.stripSeparators(input);
126
127 // The only sequences available on a locked device are the "**04"
128 // or "**05" sequences that allow you to enter PIN or PUK-related
129 // codes. (e.g. for the case where you're currently locked out of
130 // your phone, and need to change the PIN! The only way to do
131 // that is via the Emergency Dialer.)
132
133 if (handlePinEntry(context, dialString, pukInputActivity)) {
134 return true;
135 }
136
137 return false;
138 }
139
140 /**
fionaxue559f972017-01-24 22:31:12 -0800141 * Handles secret codes to launch arbitrary receivers in the form of *#*#<code>#*#*.
142 * If a secret code is encountered, an broadcast intent is sent with the
143 * android_secret_code://<code> URI.
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700144 *
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700145 * @param input the text to check for a secret code in
fionaxue559f972017-01-24 22:31:12 -0800146 * @return true if a secret code was encountered and intent is sent out
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700147 */
fionaxue559f972017-01-24 22:31:12 -0800148 static private boolean handleSecretCode(String input) {
fionaxu235cc5e2017-03-06 22:25:57 -0800149 // Secret codes are in the form *#*#<code>#*#*
150 int len = input.length();
151 if (len > 8 && input.startsWith("*#*#") && input.endsWith("#*#*")) {
152 final Phone phone = PhoneGlobals.getPhone();
153 phone.sendDialerSpecialCode(input.substring(4, len - 4));
154 return true;
155 }
156 return false;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700157 }
158
159 static private boolean handleAdnEntry(Context context, String input) {
160 /* ADN entries are of the form "N(N)(N)#" */
161
162 // if the phone is keyguard-restricted, then just ignore this
163 // input. We want to make sure that sim card contacts are NOT
164 // exposed unless the phone is unlocked, and this code can be
165 // accessed from the emergency dialer.
166 if (PhoneGlobals.getInstance().getKeyguardManager().inKeyguardRestrictedInputMode()) {
167 return false;
168 }
169
170 int len = input.length();
171 if ((len > 1) && (len < 5) && (input.endsWith("#"))) {
172 try {
173 int index = Integer.parseInt(input.substring(0, len-1));
174 Intent intent = new Intent(Intent.ACTION_PICK);
175
176 intent.setClassName("com.android.phone",
177 "com.android.phone.SimContacts");
178 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
179 intent.putExtra("index", index);
180 PhoneGlobals.getInstance().startActivity(intent);
181
182 return true;
183 } catch (NumberFormatException ex) {}
184 }
185 return false;
186 }
187
188 static private boolean handlePinEntry(Context context, String input,
189 Activity pukInputActivity) {
190 // TODO: The string constants here should be removed in favor
191 // of some call to a static the MmiCode class that determines
192 // if a dialstring is an MMI code.
193 if ((input.startsWith("**04") || input.startsWith("**05"))
194 && input.endsWith("#")) {
195 PhoneGlobals app = PhoneGlobals.getInstance();
Stuart Scottdcf40a92014-12-09 10:45:01 -0800196 Phone phone = PhoneGlobals.getPhone();
197 boolean isMMIHandled = phone.handlePinMmi(input);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700198
199 // if the PUK code is recognized then indicate to the
200 // phone app that an attempt to unPUK the device was
201 // made with this activity. The PUK code may still
202 // fail though, but we won't know until the MMI code
203 // returns a result.
204 if (isMMIHandled && input.startsWith("**05")) {
205 app.setPukEntryActivity(pukInputActivity);
206 }
207 return isMMIHandled;
208 }
209 return false;
210 }
211
212 static private boolean handleIMEIDisplay(Context context,
213 String input) {
214 if (input.equals(MMI_IMEI_DISPLAY)) {
215 showDeviceIdPanel(context);
216 return true;
217 }
218
219 return false;
220 }
221
222 static private void showDeviceIdPanel(Context context) {
223 if (DBG) log("showDeviceIdPanel()...");
224
225 Phone phone = PhoneGlobals.getPhone();
226 int labelId = TelephonyCapabilities.getDeviceIdLabel(phone);
227 String deviceId = phone.getDeviceId();
228
229 AlertDialog alert = new AlertDialog.Builder(context)
230 .setTitle(labelId)
231 .setMessage(deviceId)
232 .setPositiveButton(R.string.ok, null)
233 .setCancelable(false)
234 .create();
235 alert.getWindow().setType(WindowManager.LayoutParams.TYPE_PRIORITY_PHONE);
236 alert.show();
237 }
238
239 private static boolean handleRegulatoryInfoDisplay(Context context, String input) {
240 if (input.equals(MMI_REGULATORY_INFO_DISPLAY)) {
241 log("handleRegulatoryInfoDisplay() sending intent to settings app");
Jeff Sharkey236e67c2014-04-16 17:21:29 -0700242 Intent showRegInfoIntent = new Intent(Settings.ACTION_SHOW_REGULATORY_INFO);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700243 try {
244 context.startActivity(showRegInfoIntent);
245 } catch (ActivityNotFoundException e) {
246 Log.e(TAG, "startActivity() failed: " + e);
247 }
248 return true;
249 }
250 return false;
251 }
252
253 private static void log(String msg) {
254 Log.d(TAG, "[SpecialCharSequenceMgr] " + msg);
255 }
256}