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