diff options
8 files changed, 447 insertions, 224 deletions
diff --git a/core/java/android/view/FallbackEventHandler.java b/core/java/android/view/FallbackEventHandler.java new file mode 100644 index 000000000000..dd68d8966eb8 --- /dev/null +++ b/core/java/android/view/FallbackEventHandler.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2010 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 android.view; + +/** + * @hide + */ +public interface FallbackEventHandler { + public void setView(View v); + public void preDispatchKeyEvent(KeyEvent event); + public boolean dispatchKeyEvent(KeyEvent event); +} + diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index c7c207134473..5b18715de8ca 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -59,6 +59,7 @@ import android.view.accessibility.AccessibilityManager; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.widget.Scroller; +import com.android.internal.policy.PolicyManager; import com.android.internal.view.BaseSurfaceHolder; import com.android.internal.view.IInputMethodCallback; import com.android.internal.view.IInputMethodSession; @@ -160,6 +161,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn InputChannel mInputChannel; InputQueue.Callback mInputQueueCallback; InputQueue mInputQueue; + FallbackEventHandler mFallbackEventHandler; final Rect mTempRect; // used in the transaction to not thrash the heap. final Rect mVisRect; // used to retrieve visible rect of focused view. @@ -273,6 +275,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this); mViewConfiguration = ViewConfiguration.get(context); mDensity = context.getResources().getDisplayMetrics().densityDpi; + mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context); } public static void addFirstDrawHandler(Runnable callback) { @@ -325,6 +328,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn synchronized (this) { if (mView == null) { mView = view; + mFallbackEventHandler.setView(view); mWindowAttributes.copyFrom(attrs); attrs = mWindowAttributes; @@ -386,6 +390,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn mView = null; mAttachInfo.mRootView = null; mInputChannel = null; + mFallbackEventHandler.setView(null); unscheduleTraversals(); throw new RuntimeException("Adding window failed", e); } finally { @@ -404,6 +409,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn mView = null; mAttachInfo.mRootView = null; mAdded = false; + mFallbackEventHandler.setView(null); unscheduleTraversals(); switch (res) { case WindowManagerImpl.ADD_BAD_APP_TOKEN: @@ -2422,8 +2428,13 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn if (Config.LOGV) { captureKeyLog("captureDispatchKeyEvent", event); } + mFallbackEventHandler.preDispatchKeyEvent(event); boolean keyHandled = mView.dispatchKeyEvent(event); + if (!keyHandled) { + mFallbackEventHandler.dispatchKeyEvent(event); + } + if (!keyHandled && isDown) { int direction = 0; switch (event.getKeyCode()) { diff --git a/core/java/com/android/internal/policy/IPolicy.java b/core/java/com/android/internal/policy/IPolicy.java index 73db0b7ffc04..d08b3b4e9ad6 100644 --- a/core/java/com/android/internal/policy/IPolicy.java +++ b/core/java/com/android/internal/policy/IPolicy.java @@ -17,6 +17,7 @@ package com.android.internal.policy; import android.content.Context; +import android.view.FallbackEventHandler; import android.view.LayoutInflater; import android.view.Window; import android.view.WindowManagerPolicy; @@ -33,4 +34,6 @@ public interface IPolicy { public LayoutInflater makeNewLayoutInflater(Context context); public WindowManagerPolicy makeNewWindowManager(); + + public FallbackEventHandler makeNewFallbackEventHandler(Context context); } diff --git a/core/java/com/android/internal/policy/PolicyManager.java b/core/java/com/android/internal/policy/PolicyManager.java index 4ed5a1477329..5274e545a8de 100644 --- a/core/java/com/android/internal/policy/PolicyManager.java +++ b/core/java/com/android/internal/policy/PolicyManager.java @@ -17,6 +17,7 @@ package com.android.internal.policy; import android.content.Context; +import android.view.FallbackEventHandler; import android.view.LayoutInflater; import android.view.Window; import android.view.WindowManagerPolicy; @@ -65,4 +66,8 @@ public final class PolicyManager { public static WindowManagerPolicy makeNewWindowManager() { return sPolicy.makeNewWindowManager(); } + + public static FallbackEventHandler makeNewFallbackEventHandler(Context context) { + return sPolicy.makeNewFallbackEventHandler(context); + } } diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index b23dcdea5eb0..b84a2c2d08ad 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -27,10 +27,12 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; +import android.os.SystemClock; import android.os.ServiceManager; import android.provider.Settings; import android.util.Log; import android.view.KeyEvent; +import android.view.VolumePanel; import java.util.Iterator; import java.util.HashMap; @@ -45,6 +47,7 @@ public class AudioManager { private final Context mContext; private final Handler mHandler; + private long mVolumeKeyUpTime; private static String TAG = "AudioManager"; private static boolean DEBUG = false; @@ -358,6 +361,71 @@ public class AudioManager { } /** + * @hide + */ + public void preDispatchKeyEvent(int keyCode, int stream) { + /* + * If the user hits another key within the play sound delay, then + * cancel the sound + */ + if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP + && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE + && mVolumeKeyUpTime + VolumePanel.PLAY_SOUND_DELAY + > SystemClock.uptimeMillis()) { + /* + * The user has hit another key during the delay (e.g., 300ms) + * since the last volume key up, so cancel any sounds. + */ + adjustSuggestedStreamVolume(AudioManager.ADJUST_SAME, + stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE); + } + } + + /** + * @hide + */ + public void handleKeyDown(int keyCode, int stream) { + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_DOWN: + /* + * Adjust the volume in on key down since it is more + * responsive to the user. + */ + adjustSuggestedStreamVolume( + keyCode == KeyEvent.KEYCODE_VOLUME_UP + ? AudioManager.ADJUST_RAISE + : AudioManager.ADJUST_LOWER, + stream, + AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE); + break; + case KeyEvent.KEYCODE_VOLUME_MUTE: + // TODO: Actually handle MUTE. + break; + } + } + + /** + * @hide + */ + public void handleKeyUp(int keyCode, int stream) { + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_DOWN: + /* + * Play a sound. This is done on key up since we don't want the + * sound to play when a user holds down volume down to mute. + */ + adjustSuggestedStreamVolume(ADJUST_SAME, stream, FLAG_PLAY_SOUND); + mVolumeKeyUpTime = SystemClock.uptimeMillis(); + break; + case KeyEvent.KEYCODE_VOLUME_MUTE: + // TODO: Actually handle MUTE. + break; + } + } + + /** * Adjusts the volume of a particular stream by one step in a direction. * <p> * This method should only be used by applications that replace the platform-wide diff --git a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java new file mode 100644 index 000000000000..a8dd76c01677 --- /dev/null +++ b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java @@ -0,0 +1,288 @@ +/* + * 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.internal.policy.impl; + +import android.app.KeyguardManager; +import android.app.SearchManager; +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.media.AudioManager; +import android.telephony.TelephonyManager; +import android.util.EventLog; +import android.util.Slog; +import android.view.View; +import android.view.HapticFeedbackConstants; +import android.view.FallbackEventHandler; +import android.view.KeyEvent; + +public class PhoneFallbackEventHandler implements FallbackEventHandler { + static String TAG = "PhoneFallbackEventHandler"; + + Context mContext; + View mView; + + AudioManager mAudioManager; + KeyguardManager mKeyguardManager; + SearchManager mSearchManager; + TelephonyManager mTelephonyManager; + + public PhoneFallbackEventHandler(Context context) { + mContext = context; + } + + public void setView(View v) { + mView = v; + } + + public void preDispatchKeyEvent(KeyEvent event) { + getAudioManager().preDispatchKeyEvent(event.getKeyCode(), + AudioManager.USE_DEFAULT_STREAM_TYPE); + } + + public boolean dispatchKeyEvent(KeyEvent event) { + + final int action = event.getAction(); + final int keyCode = event.getKeyCode(); + + if (action == KeyEvent.ACTION_DOWN) { + return onKeyDown(keyCode, event); + } else { + return onKeyUp(keyCode, event); + } + } + + boolean onKeyDown(int keyCode, KeyEvent event) { + /* **************************************************************************** + * HOW TO DECIDE WHERE YOUR KEY HANDLING GOES. + * See the comment in PhoneWindow.onKeyDown + * ****************************************************************************/ + final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState(); + + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_DOWN: + case KeyEvent.KEYCODE_VOLUME_MUTE: { + getAudioManager().handleKeyDown(keyCode, AudioManager.USE_DEFAULT_STREAM_TYPE); + return true; + } + + + case KeyEvent.KEYCODE_MEDIA_PLAY: + case KeyEvent.KEYCODE_MEDIA_PAUSE: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + /* Suppress PLAY/PAUSE toggle when phone is ringing or in-call + * to avoid music playback */ + if (getTelephonyManager().getCallState() != TelephonyManager.CALL_STATE_IDLE) { + return true; // suppress key event + } + case KeyEvent.KEYCODE_MUTE: + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_RECORD: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { + Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + intent.putExtra(Intent.EXTRA_KEY_EVENT, event); + mContext.sendOrderedBroadcast(intent, null); + return true; + } + + case KeyEvent.KEYCODE_CALL: { + if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) { + break; + } + if (event.getRepeatCount() == 0) { + dispatcher.startTracking(event, this); + } else if (event.isLongPress() && dispatcher.isTracking(event)) { + dispatcher.performedLongPress(event); + mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + // launch the VoiceDialer + Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + sendCloseSystemWindows(); + mContext.startActivity(intent); + } catch (ActivityNotFoundException e) { + startCallActivity(); + } + } + return true; + } + + case KeyEvent.KEYCODE_CAMERA: { + if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) { + break; + } + if (event.getRepeatCount() == 0) { + dispatcher.startTracking(event, this); + } else if (event.isLongPress() && dispatcher.isTracking(event)) { + dispatcher.performedLongPress(event); + mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + sendCloseSystemWindows(); + // Broadcast an intent that the Camera button was longpressed + Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); + intent.putExtra(Intent.EXTRA_KEY_EVENT, event); + mContext.sendOrderedBroadcast(intent, null); + } + return true; + } + + case KeyEvent.KEYCODE_SEARCH: { + if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) { + break; + } + if (event.getRepeatCount() == 0) { + dispatcher.startTracking(event, this); + } else if (event.isLongPress() && dispatcher.isTracking(event)) { + Configuration config = mContext.getResources().getConfiguration(); + if (config.keyboard == Configuration.KEYBOARD_NOKEYS + || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) { + // launch the search activity + Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + sendCloseSystemWindows(); + getSearchManager().stopSearch(); + mContext.startActivity(intent); + // Only clear this if we successfully start the + // activity; otherwise we will allow the normal short + // press action to be performed. + dispatcher.performedLongPress(event); + return true; + } catch (ActivityNotFoundException e) { + // Ignore + } + } + } + break; + } + } + return false; + } + + boolean onKeyUp(int keyCode, KeyEvent event) { + Slog.d(TAG, "up " + keyCode); + final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState(); + if (dispatcher != null) { + dispatcher.handleUpEvent(event); + } + + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_DOWN: + case KeyEvent.KEYCODE_VOLUME_MUTE: { + if (!event.isCanceled()) { + AudioManager audioManager = (AudioManager)mContext.getSystemService( + Context.AUDIO_SERVICE); + if (audioManager != null) { + getAudioManager().handleKeyUp(keyCode, + AudioManager.USE_DEFAULT_STREAM_TYPE); + } + } + return true; + } + + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_MUTE: + case KeyEvent.KEYCODE_MEDIA_PLAY: + case KeyEvent.KEYCODE_MEDIA_PAUSE: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_RECORD: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { + Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + intent.putExtra(Intent.EXTRA_KEY_EVENT, event); + mContext.sendOrderedBroadcast(intent, null); + return true; + } + + case KeyEvent.KEYCODE_CAMERA: { + if (getKeyguardManager().inKeyguardRestrictedInputMode()) { + break; + } + if (event.isTracking() && !event.isCanceled()) { + // Add short press behavior here if desired + } + return true; + } + + case KeyEvent.KEYCODE_CALL: { + if (getKeyguardManager().inKeyguardRestrictedInputMode()) { + break; + } + if (event.isTracking() && !event.isCanceled()) { + startCallActivity(); + } + return true; + } + } + return false; + } + + void startCallActivity() { + sendCloseSystemWindows(); + Intent intent = new Intent(Intent.ACTION_CALL_BUTTON); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + mContext.startActivity(intent); + } catch (ActivityNotFoundException e) { + Slog.w(TAG, "No activity found for android.intent.action.CALL_BUTTON."); + } + } + + SearchManager getSearchManager() { + if (mSearchManager == null) { + mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE); + } + return mSearchManager; + } + + TelephonyManager getTelephonyManager() { + if (mTelephonyManager == null) { + mTelephonyManager = (TelephonyManager)mContext.getSystemService( + Context.TELEPHONY_SERVICE); + } + return mTelephonyManager; + } + + KeyguardManager getKeyguardManager() { + if (mKeyguardManager == null) { + mKeyguardManager = (KeyguardManager)mContext.getSystemService(Context.KEYGUARD_SERVICE); + } + return mKeyguardManager; + } + + AudioManager getAudioManager() { + if (mAudioManager == null) { + mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); + } + return mAudioManager; + } + + void sendCloseSystemWindows() { + PhoneWindowManager.sendCloseSystemWindows(mContext, null); + } +} + diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index cd888217a8cd..1bded54c053c 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -36,7 +36,6 @@ import com.android.internal.widget.ActionBarContextView; import com.android.internal.widget.ActionBarView; import android.app.KeyguardManager; -import android.app.SearchManager; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; @@ -52,7 +51,6 @@ import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; -import android.telephony.TelephonyManager; import android.util.AndroidRuntimeException; import android.util.Config; import android.util.EventLog; @@ -61,7 +59,6 @@ import android.util.SparseArray; import android.util.TypedValue; import android.view.ActionMode; import android.view.Gravity; -import android.view.HapticFeedbackConstants; import android.view.InputQueue; import android.view.KeyCharacterMap; import android.view.KeyEvent; @@ -170,12 +167,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE; private long mVolumeKeyUpTime; - private KeyguardManager mKeyguardManager = null; - - private SearchManager mSearchManager = null; + private AudioManager mAudioManager; + private KeyguardManager mKeyguardManager; - private TelephonyManager mTelephonyManager = null; - public PhoneWindow(Context context) { super(context); mLayoutInflater = LayoutInflater.from(context); @@ -1223,6 +1217,21 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * @see android.view.KeyEvent */ protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) { + /* **************************************************************************** + * HOW TO DECIDE WHERE YOUR KEY HANDLING GOES. + * + * If your key handling must happen before the app gets a crack at the event, + * it goes in PhoneWindowManager. + * + * If your key handling should happen in all windows, and does not depend on + * the state of the current application, other than that the current + * application can override the behavior by handling the event itself, it + * should go in PhoneFallbackEventHandler. + * + * Only if your handling depends on the window, and the fact that it has + * a DecorView, should it go here. + * ****************************************************************************/ + final KeyEvent.DispatcherState dispatcher = mDecor != null ? mDecor.getKeyDispatcherState() : null; //Log.i(TAG, "Key down: repeat=" + event.getRepeatCount() @@ -1232,68 +1241,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_VOLUME_MUTE: { - AudioManager audioManager = (AudioManager) getContext().getSystemService( - Context.AUDIO_SERVICE); - if (audioManager != null) { - /* - * Adjust the volume in on key down since it is more - * responsive to the user. - */ - // TODO: Actually handle MUTE. - audioManager.adjustSuggestedStreamVolume( - keyCode == KeyEvent.KEYCODE_VOLUME_UP - ? AudioManager.ADJUST_RAISE - : AudioManager.ADJUST_LOWER, - mVolumeControlStreamType, - AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE); - } - return true; - } - - - case KeyEvent.KEYCODE_MEDIA_PLAY: - case KeyEvent.KEYCODE_MEDIA_PAUSE: - case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: - /* Suppress PLAY/PAUSE toggle when phone is ringing or in-call - * to avoid music playback */ - if (mTelephonyManager == null) { - mTelephonyManager = (TelephonyManager) getContext().getSystemService( - Context.TELEPHONY_SERVICE); - } - if (mTelephonyManager != null && - mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) { - return true; // suppress key event - } - case KeyEvent.KEYCODE_MUTE: - case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_MEDIA_STOP: - case KeyEvent.KEYCODE_MEDIA_NEXT: - case KeyEvent.KEYCODE_MEDIA_PREVIOUS: - case KeyEvent.KEYCODE_MEDIA_REWIND: - case KeyEvent.KEYCODE_MEDIA_RECORD: - case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { - Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); - intent.putExtra(Intent.EXTRA_KEY_EVENT, event); - getContext().sendOrderedBroadcast(intent, null); - return true; - } - - case KeyEvent.KEYCODE_CAMERA: { - if (getKeyguardManager().inKeyguardRestrictedInputMode() - || dispatcher == null) { - break; - } - if (event.getRepeatCount() == 0) { - dispatcher.startTracking(event, this); - } else if (event.isLongPress() && dispatcher.isTracking(event)) { - dispatcher.performedLongPress(event); - mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - sendCloseSystemWindows(); - // Broadcast an intent that the Camera button was longpressed - Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); - intent.putExtra(Intent.EXTRA_KEY_EVENT, event); - getContext().sendOrderedBroadcast(intent, null); - } + // Similar code is in PhoneFallbackEventHandler in case the window + // doesn't have one of these. In this case, we execute it here and + // eat the event instead, because we have mVolumeControlStreamType + // and they don't. + getAudioManager().handleKeyDown(keyCode, mVolumeControlStreamType); return true; } @@ -1310,84 +1262,24 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return true; } - case KeyEvent.KEYCODE_CALL: { - if (getKeyguardManager().inKeyguardRestrictedInputMode() - || dispatcher == null) { - break; - } - if (event.getRepeatCount() == 0) { - dispatcher.startTracking(event, this); - } else if (event.isLongPress() && dispatcher.isTracking(event)) { - dispatcher.performedLongPress(event); - mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - // launch the VoiceDialer - Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - sendCloseSystemWindows(); - getContext().startActivity(intent); - } catch (ActivityNotFoundException e) { - startCallActivity(); - } - } - return true; - } - - case KeyEvent.KEYCODE_SEARCH: { - if (getKeyguardManager().inKeyguardRestrictedInputMode() - || dispatcher == null) { - break; - } - if (event.getRepeatCount() == 0) { - dispatcher.startTracking(event, this); - } else if (event.isLongPress() && dispatcher.isTracking(event)) { - Configuration config = getContext().getResources().getConfiguration(); - if (config.keyboard == Configuration.KEYBOARD_NOKEYS - || config.hardKeyboardHidden - == Configuration.HARDKEYBOARDHIDDEN_YES) { - // launch the search activity - Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - sendCloseSystemWindows(); - getSearchManager().stopSearch(); - getContext().startActivity(intent); - // Only clear this if we successfully start the - // activity; otherwise we will allow the normal short - // press action to be performed. - dispatcher.performedLongPress(event); - return true; - } catch (ActivityNotFoundException e) { - // Ignore - } - } - } - break; - } } return false; } - /** - * @return A handle to the keyguard manager. - */ private KeyguardManager getKeyguardManager() { if (mKeyguardManager == null) { - mKeyguardManager = (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE); + mKeyguardManager = (KeyguardManager) getContext().getSystemService( + Context.KEYGUARD_SERVICE); } return mKeyguardManager; } - - /** - * @return A handle to the search manager. - */ - private SearchManager getSearchManager() { - if (mSearchManager == null) { - mSearchManager = (SearchManager) getContext().getSystemService(Context.SEARCH_SERVICE); + + AudioManager getAudioManager() { + if (mAudioManager == null) { + mAudioManager = (AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE); } - return mSearchManager; + return mAudioManager; } /** @@ -1409,22 +1301,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_VOLUME_MUTE: { - if (!event.isCanceled()) { - AudioManager audioManager = (AudioManager) getContext().getSystemService( - Context.AUDIO_SERVICE); - if (audioManager != null) { - /* - * Play a sound. This is done on key up since we don't want the - * sound to play when a user holds down volume down to mute. - */ - // TODO: Actually handle MUTE. - audioManager.adjustSuggestedStreamVolume( - AudioManager.ADJUST_SAME, - mVolumeControlStreamType, - AudioManager.FLAG_PLAY_SOUND); - mVolumeKeyUpTime = SystemClock.uptimeMillis(); - } - } + // Similar code is in PhoneFallbackEventHandler in case the window + // doesn't have one of these. In this case, we execute it here and + // eat the event instead, because we have mVolumeControlStreamType + // and they don't. + getAudioManager().handleKeyUp(keyCode, mVolumeControlStreamType); return true; } @@ -1452,43 +1333,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { break; } - case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_MUTE: - case KeyEvent.KEYCODE_MEDIA_PLAY: - case KeyEvent.KEYCODE_MEDIA_PAUSE: - case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: - case KeyEvent.KEYCODE_MEDIA_STOP: - case KeyEvent.KEYCODE_MEDIA_NEXT: - case KeyEvent.KEYCODE_MEDIA_PREVIOUS: - case KeyEvent.KEYCODE_MEDIA_REWIND: - case KeyEvent.KEYCODE_MEDIA_RECORD: - case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { - Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); - intent.putExtra(Intent.EXTRA_KEY_EVENT, event); - getContext().sendOrderedBroadcast(intent, null); - return true; - } - - case KeyEvent.KEYCODE_CAMERA: { - if (getKeyguardManager().inKeyguardRestrictedInputMode()) { - break; - } - if (event.isTracking() && !event.isCanceled()) { - // Add short press behavior here if desired - } - return true; - } - - case KeyEvent.KEYCODE_CALL: { - if (getKeyguardManager().inKeyguardRestrictedInputMode()) { - break; - } - if (event.isTracking() && !event.isCanceled()) { - startCallActivity(); - } - return true; - } - case KeyEvent.KEYCODE_SEARCH: { /* * Do this in onKeyUp since the Search key is also used for @@ -1507,17 +1351,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return false; } - private void startCallActivity() { - sendCloseSystemWindows(); - Intent intent = new Intent(Intent.ACTION_CALL_BUTTON); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - getContext().startActivity(intent); - } catch (ActivityNotFoundException e) { - Log.w(TAG, "No activity found for android.intent.action.CALL_BUTTON."); - } - } - @Override protected void onActive() { } @@ -1719,26 +1552,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { final int action = event.getAction(); final boolean isDown = action == KeyEvent.ACTION_DOWN; - /* - * If the user hits another key within the play sound delay, then - * cancel the sound - */ - if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP - && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE - && mVolumeKeyUpTime + VolumePanel.PLAY_SOUND_DELAY - > SystemClock.uptimeMillis()) { - /* - * The user has hit another key during the delay (e.g., 300ms) - * since the last volume key up, so cancel any sounds. - */ - AudioManager audioManager = (AudioManager) getContext().getSystemService( - Context.AUDIO_SERVICE); - if (audioManager != null) { - audioManager.adjustSuggestedStreamVolume(AudioManager.ADJUST_SAME, - mVolumeControlStreamType, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE); - } - } - if (isDown && (event.getRepeatCount() == 0)) { // First handle chording of panel key: if a panel key is held // but not released, try to execute a shortcut in it. diff --git a/policy/src/com/android/internal/policy/impl/Policy.java b/policy/src/com/android/internal/policy/impl/Policy.java index 17f3e9129666..a49072986035 100644 --- a/policy/src/com/android/internal/policy/impl/Policy.java +++ b/policy/src/com/android/internal/policy/impl/Policy.java @@ -18,6 +18,10 @@ package com.android.internal.policy.impl; import android.content.Context; import android.util.Log; +import android.view.FallbackEventHandler; +import android.view.LayoutInflater; +import android.view.Window; +import android.view.WindowManagerPolicy; import com.android.internal.policy.IPolicy; import com.android.internal.policy.impl.PhoneLayoutInflater; @@ -55,15 +59,19 @@ public class Policy implements IPolicy { } } - public PhoneWindow makeNewWindow(Context context) { + public Window makeNewWindow(Context context) { return new PhoneWindow(context); } - public PhoneLayoutInflater makeNewLayoutInflater(Context context) { + public LayoutInflater makeNewLayoutInflater(Context context) { return new PhoneLayoutInflater(context); } - public PhoneWindowManager makeNewWindowManager() { + public WindowManagerPolicy makeNewWindowManager() { return new PhoneWindowManager(); } + + public FallbackEventHandler makeNewFallbackEventHandler(Context context) { + return new PhoneFallbackEventHandler(context); + } } |