Merge "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."
This commit is contained in:
27
core/java/android/view/FallbackEventHandler.java
Normal file
27
core/java/android/view/FallbackEventHandler.java
Normal file
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -357,6 +360,71 @@ public class AudioManager {
|
||||
return sService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user