diff options
Diffstat (limited to 'src/com/android/phone/EmergencyDialer.java')
-rw-r--r-- | src/com/android/phone/EmergencyDialer.java | 639 |
1 files changed, 0 insertions, 639 deletions
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java deleted file mode 100644 index 69001835..00000000 --- a/src/com/android/phone/EmergencyDialer.java +++ /dev/null @@ -1,639 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.phone; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.StatusBarManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.res.Resources; -import android.media.AudioManager; -import android.media.ToneGenerator; -import android.net.Uri; -import android.os.Bundle; -import android.provider.Settings; -import android.telephony.PhoneNumberUtils; -import android.text.Editable; -import android.text.TextUtils; -import android.text.TextWatcher; -import android.text.method.DialerKeyListener; -import android.util.Log; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.view.WindowManager; -import android.view.accessibility.AccessibilityManager; -import android.widget.EditText; - -import com.android.phone.common.HapticFeedback; - - -/** - * EmergencyDialer is a special dialer that is used ONLY for dialing emergency calls. - * - * It's a simplified version of the regular dialer (i.e. the TwelveKeyDialer - * activity from apps/Contacts) that: - * 1. Allows ONLY emergency calls to be dialed - * 2. Disallows voicemail functionality - * 3. Uses the FLAG_SHOW_WHEN_LOCKED window manager flag to allow this - * activity to stay in front of the keyguard. - * - * TODO: Even though this is an ultra-simplified version of the normal - * dialer, there's still lots of code duplication between this class and - * the TwelveKeyDialer class from apps/Contacts. Could the common code be - * moved into a shared base class that would live in the framework? - * Or could we figure out some way to move *this* class into apps/Contacts - * also? - */ -public class EmergencyDialer extends Activity implements View.OnClickListener, - View.OnLongClickListener, View.OnHoverListener, View.OnKeyListener, TextWatcher { - // Keys used with onSaveInstanceState(). - private static final String LAST_NUMBER = "lastNumber"; - - // Intent action for this activity. - public static final String ACTION_DIAL = "com.android.phone.EmergencyDialer.DIAL"; - - // List of dialer button IDs. - private static final int[] DIALER_KEYS = new int[] { - R.id.one, R.id.two, R.id.three, - R.id.four, R.id.five, R.id.six, - R.id.seven, R.id.eight, R.id.nine, - R.id.star, R.id.zero, R.id.pound }; - - // Debug constants. - private static final boolean DBG = false; - private static final String LOG_TAG = "EmergencyDialer"; - - private PhoneGlobals mApp; - private StatusBarManager mStatusBarManager; - private AccessibilityManager mAccessibilityManager; - - /** The length of DTMF tones in milliseconds */ - private static final int TONE_LENGTH_MS = 150; - - /** The DTMF tone volume relative to other sounds in the stream */ - private static final int TONE_RELATIVE_VOLUME = 80; - - /** Stream type used to play the DTMF tones off call, and mapped to the volume control keys */ - private static final int DIAL_TONE_STREAM_TYPE = AudioManager.STREAM_DTMF; - - private static final int BAD_EMERGENCY_NUMBER_DIALOG = 0; - - private static final int USER_ACTIVITY_TIMEOUT_WHEN_NO_PROX_SENSOR = 15000; // millis - - EditText mDigits; - private View mDialButton; - private View mDelete; - - private ToneGenerator mToneGenerator; - private Object mToneGeneratorLock = new Object(); - - // determines if we want to playback local DTMF tones. - private boolean mDTMFToneEnabled; - - // Haptic feedback (vibration) for dialer key presses. - private HapticFeedback mHaptic = new HapticFeedback(); - - // close activity when screen turns off - private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) { - finish(); - } - } - }; - - private String mLastNumber; // last number we tried to dial. Used to restore error dialog. - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - // Do nothing - } - - @Override - public void onTextChanged(CharSequence input, int start, int before, int changeCount) { - // Do nothing - } - - @Override - public void afterTextChanged(Editable input) { - // Check for special sequences, in particular the "**04" or "**05" - // sequences that allow you to enter PIN or PUK-related codes. - // - // But note we *don't* allow most other special sequences here, - // like "secret codes" (*#*#<code>#*#*) or IMEI display ("*#06#"), - // since those shouldn't be available if the device is locked. - // - // So we call SpecialCharSequenceMgr.handleCharsForLockedDevice() - // here, not the regular handleChars() method. - if (SpecialCharSequenceMgr.handleCharsForLockedDevice(this, input.toString(), this)) { - // A special sequence was entered, clear the digits - mDigits.getText().clear(); - } - - updateDialAndDeleteButtonStateEnabledAttr(); - } - - @Override - protected void onCreate(Bundle icicle) { - super.onCreate(icicle); - - mApp = PhoneGlobals.getInstance(); - mStatusBarManager = (StatusBarManager) getSystemService(Context.STATUS_BAR_SERVICE); - mAccessibilityManager = (AccessibilityManager) getSystemService(ACCESSIBILITY_SERVICE); - - // Allow this activity to be displayed in front of the keyguard / lockscreen. - WindowManager.LayoutParams lp = getWindow().getAttributes(); - lp.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; - if (!mApp.proximitySensorModeEnabled()) { - // When no proximity sensor is available, use a shorter timeout. - lp.userActivityTimeout = USER_ACTIVITY_TIMEOUT_WHEN_NO_PROX_SENSOR; - } - getWindow().setAttributes(lp); - - setContentView(R.layout.emergency_dialer); - - mDigits = (EditText) findViewById(R.id.digits); - mDigits.setKeyListener(DialerKeyListener.getInstance()); - mDigits.setOnClickListener(this); - mDigits.setOnKeyListener(this); - mDigits.setLongClickable(false); - if (mAccessibilityManager.isEnabled()) { - // The text view must be selected to send accessibility events. - mDigits.setSelected(true); - } - maybeAddNumberFormatting(); - - // Check for the presence of the keypad - View view = findViewById(R.id.one); - if (view != null) { - setupKeypad(); - } - - mDelete = findViewById(R.id.deleteButton); - mDelete.setOnClickListener(this); - mDelete.setOnLongClickListener(this); - - mDialButton = findViewById(R.id.dialButton); - - // Check whether we should show the onscreen "Dial" button and co. - Resources res = getResources(); - if (res.getBoolean(R.bool.config_show_onscreen_dial_button)) { - mDialButton.setOnClickListener(this); - } else { - mDialButton.setVisibility(View.GONE); - } - - if (icicle != null) { - super.onRestoreInstanceState(icicle); - } - - // Extract phone number from intent - Uri data = getIntent().getData(); - if (data != null && (Constants.SCHEME_TEL.equals(data.getScheme()))) { - String number = PhoneNumberUtils.getNumberFromIntent(getIntent(), this); - if (number != null) { - mDigits.setText(number); - } - } - - // if the mToneGenerator creation fails, just continue without it. It is - // a local audio signal, and is not as important as the dtmf tone itself. - synchronized (mToneGeneratorLock) { - if (mToneGenerator == null) { - try { - mToneGenerator = new ToneGenerator(DIAL_TONE_STREAM_TYPE, TONE_RELATIVE_VOLUME); - } catch (RuntimeException e) { - Log.w(LOG_TAG, "Exception caught while creating local tone generator: " + e); - mToneGenerator = null; - } - } - } - - final IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(Intent.ACTION_SCREEN_OFF); - registerReceiver(mBroadcastReceiver, intentFilter); - - try { - mHaptic.init(this, res.getBoolean(R.bool.config_enable_dialer_key_vibration)); - } catch (Resources.NotFoundException nfe) { - Log.e(LOG_TAG, "Vibrate control bool missing.", nfe); - } - } - - @Override - protected void onDestroy() { - super.onDestroy(); - synchronized (mToneGeneratorLock) { - if (mToneGenerator != null) { - mToneGenerator.release(); - mToneGenerator = null; - } - } - unregisterReceiver(mBroadcastReceiver); - } - - @Override - protected void onRestoreInstanceState(Bundle icicle) { - mLastNumber = icicle.getString(LAST_NUMBER); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putString(LAST_NUMBER, mLastNumber); - } - - /** - * Explicitly turn off number formatting, since it gets in the way of the emergency - * number detector - */ - protected void maybeAddNumberFormatting() { - // Do nothing. - } - - @Override - protected void onPostCreate(Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - - // This can't be done in onCreate(), since the auto-restoring of the digits - // will play DTMF tones for all the old digits if it is when onRestoreSavedInstanceState() - // is called. This method will be called every time the activity is created, and - // will always happen after onRestoreSavedInstanceState(). - mDigits.addTextChangedListener(this); - } - - private void setupKeypad() { - // Setup the listeners for the buttons - for (int id : DIALER_KEYS) { - final View key = findViewById(id); - key.setOnClickListener(this); - key.setOnHoverListener(this); - } - - View view = findViewById(R.id.zero); - view.setOnLongClickListener(this); - } - - /** - * handle key events - */ - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - switch (keyCode) { - // Happen when there's a "Call" hard button. - case KeyEvent.KEYCODE_CALL: { - if (TextUtils.isEmpty(mDigits.getText().toString())) { - // if we are adding a call from the InCallScreen and the phone - // number entered is empty, we just close the dialer to expose - // the InCallScreen under it. - finish(); - } else { - // otherwise, we place the call. - placeCall(); - } - return true; - } - } - return super.onKeyDown(keyCode, event); - } - - private void keyPressed(int keyCode) { - mHaptic.vibrate(); - KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode); - mDigits.onKeyDown(keyCode, event); - } - - @Override - public boolean onKey(View view, int keyCode, KeyEvent event) { - switch (view.getId()) { - case R.id.digits: - // Happen when "Done" button of the IME is pressed. This can happen when this - // Activity is forced into landscape mode due to a desk dock. - if (keyCode == KeyEvent.KEYCODE_ENTER - && event.getAction() == KeyEvent.ACTION_UP) { - placeCall(); - return true; - } - break; - } - return false; - } - - @Override - public void onClick(View view) { - switch (view.getId()) { - case R.id.one: { - playTone(ToneGenerator.TONE_DTMF_1); - keyPressed(KeyEvent.KEYCODE_1); - return; - } - case R.id.two: { - playTone(ToneGenerator.TONE_DTMF_2); - keyPressed(KeyEvent.KEYCODE_2); - return; - } - case R.id.three: { - playTone(ToneGenerator.TONE_DTMF_3); - keyPressed(KeyEvent.KEYCODE_3); - return; - } - case R.id.four: { - playTone(ToneGenerator.TONE_DTMF_4); - keyPressed(KeyEvent.KEYCODE_4); - return; - } - case R.id.five: { - playTone(ToneGenerator.TONE_DTMF_5); - keyPressed(KeyEvent.KEYCODE_5); - return; - } - case R.id.six: { - playTone(ToneGenerator.TONE_DTMF_6); - keyPressed(KeyEvent.KEYCODE_6); - return; - } - case R.id.seven: { - playTone(ToneGenerator.TONE_DTMF_7); - keyPressed(KeyEvent.KEYCODE_7); - return; - } - case R.id.eight: { - playTone(ToneGenerator.TONE_DTMF_8); - keyPressed(KeyEvent.KEYCODE_8); - return; - } - case R.id.nine: { - playTone(ToneGenerator.TONE_DTMF_9); - keyPressed(KeyEvent.KEYCODE_9); - return; - } - case R.id.zero: { - playTone(ToneGenerator.TONE_DTMF_0); - keyPressed(KeyEvent.KEYCODE_0); - return; - } - case R.id.pound: { - playTone(ToneGenerator.TONE_DTMF_P); - keyPressed(KeyEvent.KEYCODE_POUND); - return; - } - case R.id.star: { - playTone(ToneGenerator.TONE_DTMF_S); - keyPressed(KeyEvent.KEYCODE_STAR); - return; - } - case R.id.deleteButton: { - keyPressed(KeyEvent.KEYCODE_DEL); - return; - } - case R.id.dialButton: { - mHaptic.vibrate(); // Vibrate here too, just like we do for the regular keys - placeCall(); - return; - } - case R.id.digits: { - if (mDigits.length() != 0) { - mDigits.setCursorVisible(true); - } - return; - } - } - } - - /** - * Implemented for {@link android.view.View.OnHoverListener}. Handles touch - * events for accessibility when touch exploration is enabled. - */ - @Override - public boolean onHover(View v, MotionEvent event) { - // When touch exploration is turned on, lifting a finger while inside - // the button's hover target bounds should perform a click action. - if (mAccessibilityManager.isEnabled() - && mAccessibilityManager.isTouchExplorationEnabled()) { - - switch (event.getActionMasked()) { - case MotionEvent.ACTION_HOVER_ENTER: - // Lift-to-type temporarily disables double-tap activation. - v.setClickable(false); - break; - case MotionEvent.ACTION_HOVER_EXIT: - final int left = v.getPaddingLeft(); - final int right = (v.getWidth() - v.getPaddingRight()); - final int top = v.getPaddingTop(); - final int bottom = (v.getHeight() - v.getPaddingBottom()); - final int x = (int) event.getX(); - final int y = (int) event.getY(); - if ((x > left) && (x < right) && (y > top) && (y < bottom)) { - v.performClick(); - } - v.setClickable(true); - break; - } - } - - return false; - } - - /** - * called for long touch events - */ - @Override - public boolean onLongClick(View view) { - int id = view.getId(); - switch (id) { - case R.id.deleteButton: { - mDigits.getText().clear(); - // TODO: The framework forgets to clear the pressed - // status of disabled button. Until this is fixed, - // clear manually the pressed status. b/2133127 - mDelete.setPressed(false); - return true; - } - case R.id.zero: { - keyPressed(KeyEvent.KEYCODE_PLUS); - return true; - } - } - return false; - } - - @Override - protected void onResume() { - super.onResume(); - - // retrieve the DTMF tone play back setting. - mDTMFToneEnabled = Settings.System.getInt(getContentResolver(), - Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1; - - // Retrieve the haptic feedback setting. - mHaptic.checkSystemSetting(); - - // if the mToneGenerator creation fails, just continue without it. It is - // a local audio signal, and is not as important as the dtmf tone itself. - synchronized (mToneGeneratorLock) { - if (mToneGenerator == null) { - try { - mToneGenerator = new ToneGenerator(AudioManager.STREAM_DTMF, - TONE_RELATIVE_VOLUME); - } catch (RuntimeException e) { - Log.w(LOG_TAG, "Exception caught while creating local tone generator: " + e); - mToneGenerator = null; - } - } - } - - // Disable the status bar and set the poke lock timeout to medium. - // There is no need to do anything with the wake lock. - if (DBG) Log.d(LOG_TAG, "disabling status bar, set to long timeout"); - mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND); - - updateDialAndDeleteButtonStateEnabledAttr(); - } - - @Override - public void onPause() { - // Reenable the status bar and set the poke lock timeout to default. - // There is no need to do anything with the wake lock. - if (DBG) Log.d(LOG_TAG, "reenabling status bar and closing the dialer"); - mStatusBarManager.disable(StatusBarManager.DISABLE_NONE); - - super.onPause(); - - synchronized (mToneGeneratorLock) { - if (mToneGenerator != null) { - mToneGenerator.release(); - mToneGenerator = null; - } - } - } - - /** - * place the call, but check to make sure it is a viable number. - */ - private void placeCall() { - mLastNumber = mDigits.getText().toString(); - if (PhoneNumberUtils.isLocalEmergencyNumber(mLastNumber, this)) { - if (DBG) Log.d(LOG_TAG, "placing call to " + mLastNumber); - - // place the call if it is a valid number - if (mLastNumber == null || !TextUtils.isGraphic(mLastNumber)) { - // There is no number entered. - playTone(ToneGenerator.TONE_PROP_NACK); - return; - } - Intent intent = new Intent(Intent.ACTION_CALL_EMERGENCY); - intent.setData(Uri.fromParts(Constants.SCHEME_TEL, mLastNumber, null)); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - finish(); - } else { - if (DBG) Log.d(LOG_TAG, "rejecting bad requested number " + mLastNumber); - - // erase the number and throw up an alert dialog. - mDigits.getText().delete(0, mDigits.getText().length()); - showDialog(BAD_EMERGENCY_NUMBER_DIALOG); - } - } - - /** - * Plays the specified tone for TONE_LENGTH_MS milliseconds. - * - * The tone is played locally, using the audio stream for phone calls. - * Tones are played only if the "Audible touch tones" user preference - * is checked, and are NOT played if the device is in silent mode. - * - * @param tone a tone code from {@link ToneGenerator} - */ - void playTone(int tone) { - // if local tone playback is disabled, just return. - if (!mDTMFToneEnabled) { - return; - } - - // Also do nothing if the phone is in silent mode. - // We need to re-check the ringer mode for *every* playTone() - // call, rather than keeping a local flag that's updated in - // onResume(), since it's possible to toggle silent mode without - // leaving the current activity (via the ENDCALL-longpress menu.) - AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); - int ringerMode = audioManager.getRingerMode(); - if ((ringerMode == AudioManager.RINGER_MODE_SILENT) - || (ringerMode == AudioManager.RINGER_MODE_VIBRATE)) { - return; - } - - synchronized (mToneGeneratorLock) { - if (mToneGenerator == null) { - Log.w(LOG_TAG, "playTone: mToneGenerator == null, tone: " + tone); - return; - } - - // Start the new tone (will stop any playing tone) - mToneGenerator.startTone(tone, TONE_LENGTH_MS); - } - } - - private CharSequence createErrorMessage(String number) { - if (!TextUtils.isEmpty(number)) { - return getString(R.string.dial_emergency_error, mLastNumber); - } else { - return getText(R.string.dial_emergency_empty_error).toString(); - } - } - - @Override - protected Dialog onCreateDialog(int id) { - AlertDialog dialog = null; - if (id == BAD_EMERGENCY_NUMBER_DIALOG) { - // construct dialog - dialog = new AlertDialog.Builder(this) - .setTitle(getText(R.string.emergency_enable_radio_dialog_title)) - .setMessage(createErrorMessage(mLastNumber)) - .setPositiveButton(R.string.ok, null) - .setCancelable(true).create(); - - // blur stuff behind the dialog - dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); - } - return dialog; - } - - @Override - protected void onPrepareDialog(int id, Dialog dialog) { - super.onPrepareDialog(id, dialog); - if (id == BAD_EMERGENCY_NUMBER_DIALOG) { - AlertDialog alert = (AlertDialog) dialog; - alert.setMessage(createErrorMessage(mLastNumber)); - } - } - - /** - * Update the enabledness of the "Dial" and "Backspace" buttons if applicable. - */ - private void updateDialAndDeleteButtonStateEnabledAttr() { - final boolean notEmpty = mDigits.length() != 0; - - mDialButton.setEnabled(notEmpty); - mDelete.setEnabled(notEmpty); - } -} |