Move the volume, media, call, camera and search key handling from
PhoneWindow to a new PhoneFallbackEventHandler class that is used
for all windows, not just ones with decors.
Bug: 3155146
Change-Id: Ib070fa3e523e3564b225bca576c08012fef4f416
diff --git a/core/java/android/view/FallbackEventHandler.java b/core/java/android/view/FallbackEventHandler.java
new file mode 100644
index 0000000..dd68d89
--- /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 c7c2071..5b18715 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -59,6 +59,7 @@
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 @@
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 @@
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 @@
synchronized (this) {
if (mView == null) {
mView = view;
+ mFallbackEventHandler.setView(view);
mWindowAttributes.copyFrom(attrs);
attrs = mWindowAttributes;
@@ -386,6 +390,7 @@
mView = null;
mAttachInfo.mRootView = null;
mInputChannel = null;
+ mFallbackEventHandler.setView(null);
unscheduleTraversals();
throw new RuntimeException("Adding window failed", e);
} finally {
@@ -404,6 +409,7 @@
mView = null;
mAttachInfo.mRootView = null;
mAdded = false;
+ mFallbackEventHandler.setView(null);
unscheduleTraversals();
switch (res) {
case WindowManagerImpl.ADD_BAD_APP_TOKEN:
@@ -2422,8 +2428,13 @@
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 73db0b7..d08b3b4 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 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 4ed5a14..5274e54 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 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 b23dcde..b84a2c2 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -27,10 +27,12 @@
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 @@
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 @@
}
/**
+ * @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 0000000..a8dd76c
--- /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 cd88821..1bded54 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.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.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.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 @@
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 @@
* @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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 17f3e91..a490729 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 @@
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 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);
+ }
}