1 /* 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 17 package com.android.phone; 18 19 import android.app.Activity; 20 import android.app.AlertDialog; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.net.Uri; 24 import android.provider.Telephony.Intents; 25 import com.android.internal.telephony.PhoneFactory; 26 import com.android.internal.telephony.Phone; 27 import android.telephony.PhoneNumberUtils; 28 import android.util.Log; 29 import android.view.WindowManager; 30 31 /** 32 * Helper class to listen for some magic character sequences 33 * that are handled specially by the Phone app. 34 */ 35 public class SpecialCharSequenceMgr { 36 private static final String TAG = PhoneApp.LOG_TAG; 37 private static final boolean DBG = false; 38 39 private static final String MMI_IMEI_DISPLAY = "*#06#"; 40 41 /** This class is never instantiated. */ SpecialCharSequenceMgr()42 private SpecialCharSequenceMgr() { 43 } 44 handleChars(Context context, String input)45 static boolean handleChars(Context context, String input) { 46 return handleChars(context, input, false, null); 47 } 48 49 /** 50 * Generally used for the PUK unlocking case, where we 51 * want to be able to maintain a handle to the calling 52 * activity so that we can close it or otherwise display 53 * indication if the PUK code is recognized. 54 * 55 * NOTE: The counterpart to this file in Contacts does 56 * NOT contain the special PUK handling code, since it 57 * does NOT need it. When the device gets into PUK- 58 * locked state, the keyguard comes up and the only way 59 * to unlock the device is through the Emergency dialer, 60 * which is still in the Phone App. 61 */ handleChars(Context context, String input, Activity pukInputActivity)62 static boolean handleChars(Context context, String input, Activity pukInputActivity) { 63 return handleChars(context, input, false, pukInputActivity); 64 } 65 handleChars(Context context, String input, boolean useSystemWindow)66 static boolean handleChars(Context context, String input, boolean useSystemWindow) { 67 return handleChars(context, input, useSystemWindow, null); 68 } 69 70 /** 71 * Check for special strings of digits from an input 72 * string. 73 * 74 * @param context input Context for the events we handle 75 * @param input the dial string to be examined 76 * @param useSystemWindow used for the IMEI event to 77 * determine display behaviour. 78 * @param pukInputActivity activity that originated this 79 * PUK call, tracked so that we can close it or otherwise 80 * indicate that special character sequence is 81 * successfully processed. 82 */ handleChars(Context context, String input, boolean useSystemWindow, Activity pukInputActivity)83 static boolean handleChars(Context context, 84 String input, 85 boolean useSystemWindow, 86 Activity pukInputActivity) { 87 88 //get rid of the separators so that the string gets parsed correctly 89 String dialString = PhoneNumberUtils.stripSeparators(input); 90 91 if (handleIMEIDisplay(context, dialString, useSystemWindow) 92 || handlePinEntry(context, dialString, pukInputActivity) 93 || handleAdnEntry(context, dialString) 94 || handleSecretCode(context, dialString)) { 95 return true; 96 } 97 98 return false; 99 } 100 101 /** 102 * Handles secret codes to launch arbitrary activities in the form of *#*#<code>#*#*. 103 * If a secret code is encountered an Intent is started with the android_secret_code://<code> 104 * URI. 105 * 106 * @param context the context to use 107 * @param input the text to check for a secret code in 108 * @return true if a secret code was encountered 109 */ handleSecretCode(Context context, String input)110 static boolean handleSecretCode(Context context, String input) { 111 // Secret codes are in the form *#*#<code>#*#* 112 int len = input.length(); 113 if (len > 8 && input.startsWith("*#*#") && input.endsWith("#*#*")) { 114 Intent intent = new Intent(Intents.SECRET_CODE_ACTION, 115 Uri.parse("android_secret_code://" + input.substring(4, len - 4))); 116 context.sendBroadcast(intent); 117 return true; 118 } 119 120 return false; 121 } 122 handleAdnEntry(Context context, String input)123 static boolean handleAdnEntry(Context context, String input) { 124 /* ADN entries are of the form "N(N)(N)#" */ 125 126 // if the phone is keyguard-restricted, then just ignore this 127 // input. We want to make sure that sim card contacts are NOT 128 // exposed unless the phone is unlocked, and this code can be 129 // accessed from the emergency dialer. 130 if (PhoneApp.getInstance().getKeyguardManager().inKeyguardRestrictedInputMode()) { 131 return false; 132 } 133 134 int len = input.length(); 135 if ((len > 1) && (len < 5) && (input.endsWith("#"))) { 136 try { 137 int index = Integer.parseInt(input.substring(0, len-1)); 138 Intent intent = new Intent(Intent.ACTION_PICK); 139 140 intent.setClassName("com.android.phone", 141 "com.android.phone.SimContacts"); 142 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 143 intent.putExtra("index", index); 144 PhoneApp.getInstance().startActivity(intent); 145 146 return true; 147 } catch (NumberFormatException ex) {} 148 } 149 return false; 150 } 151 handlePinEntry(Context context, String input, Activity pukInputActivity)152 static boolean handlePinEntry(Context context, String input, Activity pukInputActivity) { 153 // TODO: The string constants here should be removed in favor of some call to a 154 // static the MmiCode class that determines if a dialstring is an MMI code. 155 if ((input.startsWith("**04") || input.startsWith("**05")) 156 && input.endsWith("#")) { 157 PhoneApp app = PhoneApp.getInstance(); 158 boolean isMMIHandled = app.phone.handlePinMmi(input); 159 160 // if the PUK code is recognized then indicate to the 161 // phone app that an attempt to unPUK the device was 162 // made with this activity. The PUK code may still 163 // fail though, but we won't know until the MMI code 164 // returns a result. 165 if (isMMIHandled && input.startsWith("**05")) { 166 app.setPukEntryActivity(pukInputActivity); 167 } 168 return isMMIHandled; 169 } 170 return false; 171 } 172 handleIMEIDisplay(Context context, String input, boolean useSystemWindow)173 static boolean handleIMEIDisplay(Context context, 174 String input, boolean useSystemWindow) { 175 if (input.equals(MMI_IMEI_DISPLAY)) { 176 int phoneType = PhoneApp.getInstance().phone.getPhoneType(); 177 if (phoneType == Phone.PHONE_TYPE_CDMA) { 178 showMEIDPanel(context, useSystemWindow); 179 return true; 180 } else if (phoneType == Phone.PHONE_TYPE_GSM) { 181 showIMEIPanel(context, useSystemWindow); 182 return true; 183 } 184 } 185 186 return false; 187 } 188 showIMEIPanel(Context context, boolean useSystemWindow)189 static void showIMEIPanel(Context context, boolean useSystemWindow) { 190 if (DBG) log("showIMEIPanel"); 191 192 String imeiStr = PhoneFactory.getDefaultPhone().getDeviceId(); 193 194 AlertDialog alert = new AlertDialog.Builder(context) 195 .setTitle(R.string.imei) 196 .setMessage(imeiStr) 197 .setPositiveButton(R.string.ok, null) 198 .setCancelable(false) 199 .show(); 200 alert.getWindow().setType(WindowManager.LayoutParams.TYPE_PRIORITY_PHONE); 201 } 202 showMEIDPanel(Context context, boolean useSystemWindow)203 static void showMEIDPanel(Context context, boolean useSystemWindow) { 204 if (DBG) log("showMEIDPanel"); 205 206 String meidStr = PhoneFactory.getDefaultPhone().getDeviceId(); 207 208 AlertDialog alert = new AlertDialog.Builder(context) 209 .setTitle(R.string.meid) 210 .setMessage(meidStr) 211 .setPositiveButton(R.string.ok, null) 212 .setCancelable(false) 213 .show(); 214 alert.getWindow().setType(WindowManager.LayoutParams.TYPE_PRIORITY_PHONE); 215 } 216 log(String msg)217 private static void log(String msg) { 218 Log.d(TAG, "[SpecialCharSequenceMgr] " + msg); 219 } 220 } 221