1/* 2 * Copyright (C) 2008 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.internal.policy.impl; 18 19import android.app.KeyguardManager; 20import android.app.SearchManager; 21import android.content.ActivityNotFoundException; 22import android.content.Context; 23import android.content.Intent; 24import android.content.res.Configuration; 25import android.media.AudioManager; 26import android.media.IAudioService; 27import android.media.session.MediaSessionLegacyHelper; 28import android.os.RemoteException; 29import android.os.ServiceManager; 30import android.os.UserHandle; 31import android.provider.Settings; 32import android.telephony.TelephonyManager; 33import android.util.Log; 34import android.view.View; 35import android.view.HapticFeedbackConstants; 36import android.view.FallbackEventHandler; 37import android.view.KeyEvent; 38 39public class PhoneFallbackEventHandler implements FallbackEventHandler { 40 private static String TAG = "PhoneFallbackEventHandler"; 41 private static final boolean DEBUG = false; 42 43 Context mContext; 44 View mView; 45 46 AudioManager mAudioManager; 47 KeyguardManager mKeyguardManager; 48 SearchManager mSearchManager; 49 TelephonyManager mTelephonyManager; 50 51 public PhoneFallbackEventHandler(Context context) { 52 mContext = context; 53 } 54 55 public void setView(View v) { 56 mView = v; 57 } 58 59 public void preDispatchKeyEvent(KeyEvent event) { 60 getAudioManager().preDispatchKeyEvent(event, AudioManager.USE_DEFAULT_STREAM_TYPE); 61 } 62 63 public boolean dispatchKeyEvent(KeyEvent event) { 64 65 final int action = event.getAction(); 66 final int keyCode = event.getKeyCode(); 67 68 if (action == KeyEvent.ACTION_DOWN) { 69 return onKeyDown(keyCode, event); 70 } else { 71 return onKeyUp(keyCode, event); 72 } 73 } 74 75 boolean onKeyDown(int keyCode, KeyEvent event) { 76 /* **************************************************************************** 77 * HOW TO DECIDE WHERE YOUR KEY HANDLING GOES. 78 * See the comment in PhoneWindow.onKeyDown 79 * ****************************************************************************/ 80 final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState(); 81 82 switch (keyCode) { 83 case KeyEvent.KEYCODE_VOLUME_UP: 84 case KeyEvent.KEYCODE_VOLUME_DOWN: 85 case KeyEvent.KEYCODE_VOLUME_MUTE: { 86 MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false); 87 return true; 88 } 89 90 91 case KeyEvent.KEYCODE_MEDIA_PLAY: 92 case KeyEvent.KEYCODE_MEDIA_PAUSE: 93 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 94 /* Suppress PLAY/PAUSE toggle when phone is ringing or in-call 95 * to avoid music playback */ 96 if (getTelephonyManager().getCallState() != TelephonyManager.CALL_STATE_IDLE) { 97 return true; // suppress key event 98 } 99 case KeyEvent.KEYCODE_MUTE: 100 case KeyEvent.KEYCODE_HEADSETHOOK: 101 case KeyEvent.KEYCODE_MEDIA_STOP: 102 case KeyEvent.KEYCODE_MEDIA_NEXT: 103 case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 104 case KeyEvent.KEYCODE_MEDIA_REWIND: 105 case KeyEvent.KEYCODE_MEDIA_RECORD: 106 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: 107 case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: { 108 handleMediaKeyEvent(event); 109 return true; 110 } 111 112 case KeyEvent.KEYCODE_CALL: { 113 if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) { 114 break; 115 } 116 if (event.getRepeatCount() == 0) { 117 dispatcher.startTracking(event, this); 118 } else if (event.isLongPress() && dispatcher.isTracking(event)) { 119 dispatcher.performedLongPress(event); 120 if (isUserSetupComplete()) { 121 mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 122 // launch the VoiceDialer 123 Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND); 124 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 125 try { 126 sendCloseSystemWindows(); 127 mContext.startActivity(intent); 128 } catch (ActivityNotFoundException e) { 129 startCallActivity(); 130 } 131 } else { 132 Log.i(TAG, "Not starting call activity because user " 133 + "setup is in progress."); 134 } 135 } 136 return true; 137 } 138 139 case KeyEvent.KEYCODE_CAMERA: { 140 if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) { 141 break; 142 } 143 if (event.getRepeatCount() == 0) { 144 dispatcher.startTracking(event, this); 145 } else if (event.isLongPress() && dispatcher.isTracking(event)) { 146 dispatcher.performedLongPress(event); 147 if (isUserSetupComplete()) { 148 mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 149 sendCloseSystemWindows(); 150 // Broadcast an intent that the Camera button was longpressed 151 Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); 152 intent.putExtra(Intent.EXTRA_KEY_EVENT, event); 153 mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF, 154 null, null, null, 0, null, null); 155 } else { 156 Log.i(TAG, "Not dispatching CAMERA long press because user " 157 + "setup is in progress."); 158 } 159 } 160 return true; 161 } 162 163 case KeyEvent.KEYCODE_SEARCH: { 164 if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) { 165 break; 166 } 167 if (event.getRepeatCount() == 0) { 168 dispatcher.startTracking(event, this); 169 } else if (event.isLongPress() && dispatcher.isTracking(event)) { 170 Configuration config = mContext.getResources().getConfiguration(); 171 if (config.keyboard == Configuration.KEYBOARD_NOKEYS 172 || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) { 173 if (isUserSetupComplete()) { 174 // launch the search activity 175 Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS); 176 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 177 try { 178 mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 179 sendCloseSystemWindows(); 180 getSearchManager().stopSearch(); 181 mContext.startActivity(intent); 182 // Only clear this if we successfully start the 183 // activity; otherwise we will allow the normal short 184 // press action to be performed. 185 dispatcher.performedLongPress(event); 186 return true; 187 } catch (ActivityNotFoundException e) { 188 // Ignore 189 } 190 } else { 191 Log.i(TAG, "Not dispatching SEARCH long press because user " 192 + "setup is in progress."); 193 } 194 } 195 } 196 break; 197 } 198 } 199 return false; 200 } 201 202 boolean onKeyUp(int keyCode, KeyEvent event) { 203 if (DEBUG) { 204 Log.d(TAG, "up " + keyCode); 205 } 206 final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState(); 207 if (dispatcher != null) { 208 dispatcher.handleUpEvent(event); 209 } 210 211 switch (keyCode) { 212 case KeyEvent.KEYCODE_VOLUME_UP: 213 case KeyEvent.KEYCODE_VOLUME_DOWN: 214 case KeyEvent.KEYCODE_VOLUME_MUTE: { 215 if (!event.isCanceled()) { 216 MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false); 217 } 218 return true; 219 } 220 221 case KeyEvent.KEYCODE_HEADSETHOOK: 222 case KeyEvent.KEYCODE_MUTE: 223 case KeyEvent.KEYCODE_MEDIA_PLAY: 224 case KeyEvent.KEYCODE_MEDIA_PAUSE: 225 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 226 case KeyEvent.KEYCODE_MEDIA_STOP: 227 case KeyEvent.KEYCODE_MEDIA_NEXT: 228 case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 229 case KeyEvent.KEYCODE_MEDIA_REWIND: 230 case KeyEvent.KEYCODE_MEDIA_RECORD: 231 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: 232 case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: { 233 handleMediaKeyEvent(event); 234 return true; 235 } 236 237 case KeyEvent.KEYCODE_CAMERA: { 238 if (getKeyguardManager().inKeyguardRestrictedInputMode()) { 239 break; 240 } 241 if (event.isTracking() && !event.isCanceled()) { 242 // Add short press behavior here if desired 243 } 244 return true; 245 } 246 247 case KeyEvent.KEYCODE_CALL: { 248 if (getKeyguardManager().inKeyguardRestrictedInputMode()) { 249 break; 250 } 251 if (event.isTracking() && !event.isCanceled()) { 252 if (isUserSetupComplete()) { 253 startCallActivity(); 254 } else { 255 Log.i(TAG, "Not starting call activity because user " 256 + "setup is in progress."); 257 } 258 } 259 return true; 260 } 261 } 262 return false; 263 } 264 265 void startCallActivity() { 266 sendCloseSystemWindows(); 267 Intent intent = new Intent(Intent.ACTION_CALL_BUTTON); 268 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 269 try { 270 mContext.startActivity(intent); 271 } catch (ActivityNotFoundException e) { 272 Log.w(TAG, "No activity found for android.intent.action.CALL_BUTTON."); 273 } 274 } 275 276 SearchManager getSearchManager() { 277 if (mSearchManager == null) { 278 mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE); 279 } 280 return mSearchManager; 281 } 282 283 TelephonyManager getTelephonyManager() { 284 if (mTelephonyManager == null) { 285 mTelephonyManager = (TelephonyManager)mContext.getSystemService( 286 Context.TELEPHONY_SERVICE); 287 } 288 return mTelephonyManager; 289 } 290 291 KeyguardManager getKeyguardManager() { 292 if (mKeyguardManager == null) { 293 mKeyguardManager = (KeyguardManager)mContext.getSystemService(Context.KEYGUARD_SERVICE); 294 } 295 return mKeyguardManager; 296 } 297 298 AudioManager getAudioManager() { 299 if (mAudioManager == null) { 300 mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); 301 } 302 return mAudioManager; 303 } 304 305 void sendCloseSystemWindows() { 306 PhoneWindowManager.sendCloseSystemWindows(mContext, null); 307 } 308 309 private void handleMediaKeyEvent(KeyEvent keyEvent) { 310 MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false); 311 } 312 313 private boolean isUserSetupComplete() { 314 return Settings.Secure.getInt(mContext.getContentResolver(), 315 Settings.Secure.USER_SETUP_COMPLETE, 0) != 0; 316 } 317} 318 319