PhoneFallbackEventHandler.java revision 86f6786032b1a0380cf089aeeceef7e9d8982ef8
1a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o/* 2a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * Copyright (C) 2008 The Android Open Source Project 3a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * 4a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * Licensed under the Apache License, Version 2.0 (the "License"); 5a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * you may not use this file except in compliance with the License. 6a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * You may obtain a copy of the License at 7a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * 8a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * http://www.apache.org/licenses/LICENSE-2.0 9a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * 10a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * Unless required by applicable law or agreed to in writing, software 11a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * distributed under the License is distributed on an "AS IS" BASIS, 12a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o * See the License for the specific language governing permissions and 14a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * limitations under the License. 154cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o */ 16a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 17a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'opackage com.android.internal.policy.impl; 18a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 19a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.app.KeyguardManager; 20a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.app.SearchManager; 21a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.content.ActivityNotFoundException; 22a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.content.Context; 23a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.content.Intent; 24a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.content.res.Configuration; 25a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.media.AudioManager; 26a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.telephony.TelephonyManager; 27a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.util.EventLog; 28a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.util.Slog; 29a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.view.View; 30a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.view.HapticFeedbackConstants; 31a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.view.FallbackEventHandler; 32a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.view.KeyEvent; 33a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 34a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'opublic class PhoneFallbackEventHandler implements FallbackEventHandler { 35a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o static String TAG = "PhoneFallbackEventHandler"; 36a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 37a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o Context mContext; 38a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o View mView; 39a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 40a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o AudioManager mAudioManager; 41a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o KeyguardManager mKeyguardManager; 42a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o SearchManager mSearchManager; 43a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o TelephonyManager mTelephonyManager; 44a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 45a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o public PhoneFallbackEventHandler(Context context) { 46a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o mContext = context; 47a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o } 48a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 49a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o public void setView(View v) { 50a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o mView = v; 51a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o } 52a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 53a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o public void preDispatchKeyEvent(KeyEvent event) { 54a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o getAudioManager().preDispatchKeyEvent(event.getKeyCode(), 55a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o AudioManager.USE_DEFAULT_STREAM_TYPE); 56a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o } 57a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 58a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o public boolean dispatchKeyEvent(KeyEvent event) { 59a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 60a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o final int action = event.getAction(); 61a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o final int keyCode = event.getKeyCode(); 62a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 63a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o if (action == KeyEvent.ACTION_DOWN) { 64a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o return onKeyDown(keyCode, event); 65a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o } else { 66a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o return onKeyUp(keyCode, event); 67a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o } 68a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o } 69a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 70a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o boolean onKeyDown(int keyCode, KeyEvent event) { 71a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o /* **************************************************************************** 72a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * HOW TO DECIDE WHERE YOUR KEY HANDLING GOES. 73a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * See the comment in PhoneWindow.onKeyDown 74a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * ****************************************************************************/ 75a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState(); 76a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 77a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o switch (keyCode) { 78a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o case KeyEvent.KEYCODE_VOLUME_UP: 79a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o case KeyEvent.KEYCODE_VOLUME_DOWN: 80a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o case KeyEvent.KEYCODE_VOLUME_MUTE: { 81a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o getAudioManager().handleKeyDown(keyCode, AudioManager.USE_DEFAULT_STREAM_TYPE); 82a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o return true; 83a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o } 84a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 85a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 86a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o case KeyEvent.KEYCODE_MEDIA_PLAY: 87a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o case KeyEvent.KEYCODE_MEDIA_PAUSE: 88a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 89a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o /* Suppress PLAY/PAUSE toggle when phone is ringing or in-call 90a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * to avoid music playback */ 91a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o if (getTelephonyManager().getCallState() != TelephonyManager.CALL_STATE_IDLE) { 92a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o return true; // suppress key event 93a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o } 94a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o case KeyEvent.KEYCODE_MUTE: 95a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o case KeyEvent.KEYCODE_HEADSETHOOK: 96 case KeyEvent.KEYCODE_MEDIA_STOP: 97 case KeyEvent.KEYCODE_MEDIA_NEXT: 98 case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 99 case KeyEvent.KEYCODE_MEDIA_REWIND: 100 case KeyEvent.KEYCODE_MEDIA_RECORD: 101 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { 102 Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); 103 intent.putExtra(Intent.EXTRA_KEY_EVENT, event); 104 mContext.sendOrderedBroadcast(intent, null); 105 return true; 106 } 107 108 case KeyEvent.KEYCODE_CALL: { 109 if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) { 110 break; 111 } 112 if (event.getRepeatCount() == 0) { 113 dispatcher.startTracking(event, this); 114 } else if (event.isLongPress() && dispatcher.isTracking(event)) { 115 dispatcher.performedLongPress(event); 116 mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 117 // launch the VoiceDialer 118 Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND); 119 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 120 try { 121 sendCloseSystemWindows(); 122 mContext.startActivity(intent); 123 } catch (ActivityNotFoundException e) { 124 startCallActivity(); 125 } 126 } 127 return true; 128 } 129 130 case KeyEvent.KEYCODE_CAMERA: { 131 if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) { 132 break; 133 } 134 if (event.getRepeatCount() == 0) { 135 dispatcher.startTracking(event, this); 136 } else if (event.isLongPress() && dispatcher.isTracking(event)) { 137 dispatcher.performedLongPress(event); 138 mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 139 sendCloseSystemWindows(); 140 // Broadcast an intent that the Camera button was longpressed 141 Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); 142 intent.putExtra(Intent.EXTRA_KEY_EVENT, event); 143 mContext.sendOrderedBroadcast(intent, null); 144 } 145 return true; 146 } 147 148 case KeyEvent.KEYCODE_SEARCH: { 149 if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) { 150 break; 151 } 152 if (event.getRepeatCount() == 0) { 153 dispatcher.startTracking(event, this); 154 } else if (event.isLongPress() && dispatcher.isTracking(event)) { 155 Configuration config = mContext.getResources().getConfiguration(); 156 if (config.keyboard == Configuration.KEYBOARD_NOKEYS 157 || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) { 158 // launch the search activity 159 Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS); 160 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 161 try { 162 mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 163 sendCloseSystemWindows(); 164 getSearchManager().stopSearch(); 165 mContext.startActivity(intent); 166 // Only clear this if we successfully start the 167 // activity; otherwise we will allow the normal short 168 // press action to be performed. 169 dispatcher.performedLongPress(event); 170 return true; 171 } catch (ActivityNotFoundException e) { 172 // Ignore 173 } 174 } 175 } 176 break; 177 } 178 } 179 return false; 180 } 181 182 boolean onKeyUp(int keyCode, KeyEvent event) { 183 Slog.d(TAG, "up " + keyCode); 184 final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState(); 185 if (dispatcher != null) { 186 dispatcher.handleUpEvent(event); 187 } 188 189 switch (keyCode) { 190 case KeyEvent.KEYCODE_VOLUME_UP: 191 case KeyEvent.KEYCODE_VOLUME_DOWN: 192 case KeyEvent.KEYCODE_VOLUME_MUTE: { 193 if (!event.isCanceled()) { 194 AudioManager audioManager = (AudioManager)mContext.getSystemService( 195 Context.AUDIO_SERVICE); 196 if (audioManager != null) { 197 getAudioManager().handleKeyUp(keyCode, 198 AudioManager.USE_DEFAULT_STREAM_TYPE); 199 } 200 } 201 return true; 202 } 203 204 case KeyEvent.KEYCODE_HEADSETHOOK: 205 case KeyEvent.KEYCODE_MUTE: 206 case KeyEvent.KEYCODE_MEDIA_PLAY: 207 case KeyEvent.KEYCODE_MEDIA_PAUSE: 208 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 209 case KeyEvent.KEYCODE_MEDIA_STOP: 210 case KeyEvent.KEYCODE_MEDIA_NEXT: 211 case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 212 case KeyEvent.KEYCODE_MEDIA_REWIND: 213 case KeyEvent.KEYCODE_MEDIA_RECORD: 214 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { 215 Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); 216 intent.putExtra(Intent.EXTRA_KEY_EVENT, event); 217 mContext.sendOrderedBroadcast(intent, null); 218 return true; 219 } 220 221 case KeyEvent.KEYCODE_CAMERA: { 222 if (getKeyguardManager().inKeyguardRestrictedInputMode()) { 223 break; 224 } 225 if (event.isTracking() && !event.isCanceled()) { 226 // Add short press behavior here if desired 227 } 228 return true; 229 } 230 231 case KeyEvent.KEYCODE_CALL: { 232 if (getKeyguardManager().inKeyguardRestrictedInputMode()) { 233 break; 234 } 235 if (event.isTracking() && !event.isCanceled()) { 236 startCallActivity(); 237 } 238 return true; 239 } 240 } 241 return false; 242 } 243 244 void startCallActivity() { 245 sendCloseSystemWindows(); 246 Intent intent = new Intent(Intent.ACTION_CALL_BUTTON); 247 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 248 try { 249 mContext.startActivity(intent); 250 } catch (ActivityNotFoundException e) { 251 Slog.w(TAG, "No activity found for android.intent.action.CALL_BUTTON."); 252 } 253 } 254 255 SearchManager getSearchManager() { 256 if (mSearchManager == null) { 257 mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE); 258 } 259 return mSearchManager; 260 } 261 262 TelephonyManager getTelephonyManager() { 263 if (mTelephonyManager == null) { 264 mTelephonyManager = (TelephonyManager)mContext.getSystemService( 265 Context.TELEPHONY_SERVICE); 266 } 267 return mTelephonyManager; 268 } 269 270 KeyguardManager getKeyguardManager() { 271 if (mKeyguardManager == null) { 272 mKeyguardManager = (KeyguardManager)mContext.getSystemService(Context.KEYGUARD_SERVICE); 273 } 274 return mKeyguardManager; 275 } 276 277 AudioManager getAudioManager() { 278 if (mAudioManager == null) { 279 mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); 280 } 281 return mAudioManager; 282 } 283 284 void sendCloseSystemWindows() { 285 PhoneWindowManager.sendCloseSystemWindows(mContext, null); 286 } 287} 288 289