Add support for power keys, improve behavior of virtual keys.

The platform now knows how to deal with a platform key, which at this
point is "just like end call, but don't end a call."

Also improve the handling of virtual keys, to allow for canceling when
sliding off into the display and providing haptic feedback.

Finally fixes a bug where the raw x and y in motion event were not
always set which caused the status bar to not work.
This commit is contained in:
Dianne Hackborn
2009-07-23 19:01:31 -07:00
parent 8e4ac7140a
commit ddca3ee3e8
9 changed files with 169 additions and 27 deletions

View File

@@ -141896,6 +141896,17 @@
visibility="public"
>
</field>
<field name="VIRTUAL_KEY"
type="int"
transient="false"
volatile="false"
value="1"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
</class>
<class name="InflateException"
extends="java.lang.RuntimeException"
@@ -142736,6 +142747,17 @@
visibility="public"
>
</method>
<method name="isCanceled"
return="boolean"
abstract="false"
native="false"
synchronized="false"
static="false"
final="true"
deprecated="not deprecated"
visibility="public"
>
</method>
<method name="isModifierKey"
return="boolean"
abstract="false"
@@ -142851,6 +142873,17 @@
visibility="public"
>
</field>
<field name="FLAG_CANCELED"
type="int"
transient="false"
volatile="false"
value="32"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="FLAG_EDITOR_ACTION"
type="int"
transient="false"
@@ -142895,6 +142928,17 @@
visibility="public"
>
</field>
<field name="FLAG_VIRTUAL_HARD_KEY"
type="int"
transient="false"
volatile="false"
value="64"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="FLAG_WOKE_HERE"
type="int"
transient="false"

View File

@@ -24,8 +24,17 @@ public class HapticFeedbackConstants {
private HapticFeedbackConstants() {}
/**
* The user has performed a long press on an object that is resulting
* in an action being performed.
*/
public static final int LONG_PRESS = 0;
/**
* The user has pressed on a virtual on-screen key.
*/
public static final int VIRTUAL_KEY = 1;
/**
* Flag for {@link View#performHapticFeedback(int, int)
* View.performHapticFeedback(int, int)}: Ignore the setting in the

View File

@@ -257,6 +257,25 @@ public class KeyEvent implements Parcelable {
*/
public static final int FLAG_EDITOR_ACTION = 0x10;
/**
* When associated with up key events, this indicates that the key press
* has been canceled. Typically this is used with virtual touch screen
* keys, where the user can slide from the virtual key area on to the
* display: in that case, the application will receive a canceled up
* event and should not perform the action normally associated with the
* key. Note that for this to work, the application can not perform an
* action for a key until it receives an up or the long press timeout has
* expired.
*/
public static final int FLAG_CANCELED = 0x20;
/**
* This key event was generated by a virtual (on-screen) hard key area.
* Typically this is an area of the touchscreen, outside of the regular
* display, dedicated to "hardware" buttons.
*/
public static final int FLAG_VIRTUAL_HARD_KEY = 0x40;
/**
* Returns the maximum keycode.
*/
@@ -693,6 +712,14 @@ public class KeyEvent implements Parcelable {
return mAction;
}
/**
* For {@link #ACTION_UP} events, indicates that the event has been
* canceled as per {@link #FLAG_CANCELED}.
*/
public final boolean isCanceled() {
return (mFlags&FLAG_CANCELED) != 0;
}
/**
* Retrieve the key code of the key event. This is the physical key that
* was pressed, <em>not</em> the Unicode character.

View File

@@ -288,9 +288,10 @@ public final class MotionEvent implements Parcelable {
ev.mEventTimeNano = eventTimeNano;
ev.mAction = action;
ev.mMetaState = metaState;
ev.mRawX = inData[SAMPLE_X];
ev.mRawY = inData[SAMPLE_Y];
ev.mXPrecision = xPrecision;
ev.mYPrecision = yPrecision;
ev.mNumPointers = pointers;
ev.mNumSamples = 1;

View File

@@ -1665,7 +1665,9 @@ public final class ViewRoot extends Handler implements ViewParent,
if(Config.LOGV) {
captureMotionLog("captureDispatchPointer", event);
}
event.offsetLocation(0, mCurScrollY);
if (mCurScrollY != 0) {
event.offsetLocation(0, mCurScrollY);
}
if (MEASURE_LATENCY) {
lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano());
}

View File

@@ -533,14 +533,15 @@ public interface WindowManagerPolicy {
* @param win The window that currently has focus. This is where the key
* event will normally go.
* @param code Key code.
* @param metaKeys TODO
* @param metaKeys bit mask of meta keys that are held.
* @param down Is this a key press (true) or release (false)?
* @param repeatCount Number of times a key down has repeated.
* @param flags event's flags.
* @return Returns true if the policy consumed the event and it should
* not be further dispatched.
*/
public boolean interceptKeyTi(WindowState win, int code,
int metaKeys, boolean down, int repeatCount);
int metaKeys, boolean down, int repeatCount, int flags);
/**
* Called when layout of the windows is about to start.
@@ -791,6 +792,13 @@ public interface WindowManagerPolicy {
*/
public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always);
/**
* A special function that is called from the very low-level input queue
* to provide feedback to the user. Currently only called for virtual
* keys.
*/
public void keyFeedbackFromInput(KeyEvent event);
/**
* Called when we have stopped keeping the screen on because a window
* requesting this is no longer visible.

View File

@@ -213,7 +213,7 @@ public class InputDevice {
// We only consider the first pointer when computing the edge
// flags, since they are global to the event.
if (action != MotionEvent.ACTION_DOWN) {
if (action == MotionEvent.ACTION_DOWN) {
if (scaled[MotionEvent.SAMPLE_X] <= 0) {
edgeFlags |= MotionEvent.EDGE_LEFT;
} else if (scaled[MotionEvent.SAMPLE_X] >= dispW) {

View File

@@ -35,7 +35,6 @@ import android.view.WindowManagerPolicy;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.BufferedReader;
import java.io.File;
@@ -55,6 +54,7 @@ public abstract class KeyInputQueue {
final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
final ArrayList<VirtualKey> mVirtualKeys = new ArrayList<VirtualKey>();
final HapticFeedbackCallback mHapticFeedbackCallback;
int mGlobalMetaState = 0;
boolean mHaveGlobalMetaState = false;
@@ -107,6 +107,10 @@ public abstract class KeyInputQueue {
int filterEvent(QueuedEvent ev);
}
public interface HapticFeedbackCallback {
void virtualKeyFeedback(KeyEvent event);
}
static class QueuedEvent {
InputDevice inputDevice;
long whenNano;
@@ -264,11 +268,13 @@ public abstract class KeyInputQueue {
}
}
KeyInputQueue(Context context) {
KeyInputQueue(Context context, HapticFeedbackCallback hapticFeedbackCallback) {
if (MEASURE_LATENCY) {
lt = new LatencyTimer(100, 1000);
}
mHapticFeedbackCallback = hapticFeedbackCallback;
readVirtualKeys();
readExcludedDevices();
@@ -539,14 +545,40 @@ public abstract class KeyInputQueue {
ms.mLastDown[0] = ms.mDown[0];
if (DEBUG_VIRTUAL_KEYS) Log.v(TAG,
"Generate key up for: " + vk.scancode);
KeyEvent event = newKeyEvent(di,
di.mKeyDownTime, curTime, false,
vk.lastKeycode,
0, vk.scancode,
KeyEvent.FLAG_VIRTUAL_HARD_KEY);
mHapticFeedbackCallback.virtualKeyFeedback(event);
addLocked(di, curTimeNano, ev.flags,
RawInputEvent.CLASS_KEYBOARD,
newKeyEvent(di, di.mKeyDownTime,
curTime, false,
vk.lastKeycode,
0, vk.scancode, 0));
event);
} else if (isInsideDisplay(di)) {
// Whoops the pointer has moved into
// the display area! Cancel the
// virtual key and start a pointer
// motion.
mPressedVirtualKey = null;
if (DEBUG_VIRTUAL_KEYS) Log.v(TAG,
"Cancel key up for: " + vk.scancode);
KeyEvent event = newKeyEvent(di,
di.mKeyDownTime, curTime, false,
vk.lastKeycode,
0, vk.scancode,
KeyEvent.FLAG_CANCELED |
KeyEvent.FLAG_VIRTUAL_HARD_KEY);
mHapticFeedbackCallback.virtualKeyFeedback(event);
addLocked(di, curTimeNano, ev.flags,
RawInputEvent.CLASS_KEYBOARD,
event);
doMotion = true;
for (int i=InputDevice.MAX_POINTERS-1; i>=0; i--) {
ms.mLastDown[i] = false;
}
}
} else if (ms.mDown[0] && !ms.mLastDown[0]) {
}
if (doMotion && ms.mDown[0] && !ms.mLastDown[0]) {
vk = findSoftButton(di);
if (vk != null) {
doMotion = false;
@@ -558,12 +590,15 @@ public abstract class KeyInputQueue {
if (DEBUG_VIRTUAL_KEYS) Log.v(TAG,
"Generate key down for: " + vk.scancode
+ " (keycode=" + vk.lastKeycode + ")");
KeyEvent event = newKeyEvent(di,
di.mKeyDownTime, curTime, true,
vk.lastKeycode, 0,
vk.scancode,
KeyEvent.FLAG_VIRTUAL_HARD_KEY);
mHapticFeedbackCallback.virtualKeyFeedback(event);
addLocked(di, curTimeNano, ev.flags,
RawInputEvent.CLASS_KEYBOARD,
newKeyEvent(di, di.mKeyDownTime,
curTime, true,
vk.lastKeycode, 0,
vk.scancode, 0));
event);
}
}
@@ -618,17 +653,12 @@ public abstract class KeyInputQueue {
}
};
private VirtualKey findSoftButton(InputDevice dev) {
final int N = mVirtualKeys.size();
if (N <= 0) {
return null;
}
private boolean isInsideDisplay(InputDevice dev) {
final InputDevice.AbsoluteInfo absx = dev.absX;
final InputDevice.AbsoluteInfo absy = dev.absY;
final InputDevice.MotionState absm = dev.mAbs;
if (absx == null || absy == null || absm == null) {
return null;
return true;
}
if (absm.mCurData[MotionEvent.SAMPLE_X] >= absx.minValue
@@ -639,9 +669,23 @@ public abstract class KeyInputQueue {
+ absm.mCurData[MotionEvent.SAMPLE_X]
+ "," + absm.mCurData[MotionEvent.SAMPLE_Y]
+ ") inside of display");
return true;
}
return false;
}
private VirtualKey findSoftButton(InputDevice dev) {
final int N = mVirtualKeys.size();
if (N <= 0) {
return null;
}
if (isInsideDisplay(dev)) {
return null;
}
final InputDevice.MotionState absm = dev.mAbs;
for (int i=0; i<N; i++) {
VirtualKey sb = mVirtualKeys.get(i);
sb.computeHitRect(dev, mDisplayWidth, mDisplayHeight);

View File

@@ -125,7 +125,8 @@ import java.util.Iterator;
import java.util.List;
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor {
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, KeyInputQueue.HapticFeedbackCallback {
static final String TAG = "WindowManager";
static final boolean DEBUG = false;
static final boolean DEBUG_FOCUS = false;
@@ -4686,7 +4687,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
callingPid, callingUid)
== PackageManager.PERMISSION_GRANTED) {
mPolicy.interceptKeyTi(null, keycode,
nextKey.getMetaState(), down, repeatCount);
nextKey.getMetaState(), down, repeatCount,
nextKey.getFlags());
}
Log.w(TAG, "Event timeout during app switch: dropping "
+ nextKey);
@@ -4709,7 +4711,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
callingPid, callingUid)
== PackageManager.PERMISSION_GRANTED) {
if (mPolicy.interceptKeyTi(focus,
keycode, nextKey.getMetaState(), down, repeatCount)) {
keycode, nextKey.getMetaState(), down, repeatCount,
nextKey.getFlags())) {
return CONSUMED_EVENT_TOKEN;
}
}
@@ -5129,7 +5132,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
PowerManager.WakeLock mHoldingScreen;
KeyQ() {
super(mContext);
super(mContext, WindowManagerService.this);
PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
mHoldingScreen = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
"KEEP_SCREEN_ON_FLAG");
@@ -9202,6 +9205,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
synchronized (mKeyWaiter) { }
}
public void virtualKeyFeedback(KeyEvent event) {
mPolicy.keyFeedbackFromInput(event);
}
/**
* DimAnimator class that controls the dim animation. This holds the surface and
* all state used for dim animation.