Merge commit '7c8aa44f320f45e8417f0aba9ca67af6a67a5cf7' into gingerbread-plus-aosp * commit '7c8aa44f320f45e8417f0aba9ca67af6a67a5cf7': Native input dispatch rewrite work in progress.
This commit is contained in:
@@ -16,13 +16,11 @@
|
||||
|
||||
package android.os;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.util.AndroidRuntimeException;
|
||||
import android.util.Config;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.os.RuntimeInit;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Low-level class holding the list of messages to be dispatched by a
|
||||
@@ -34,11 +32,18 @@ import com.android.internal.os.RuntimeInit;
|
||||
*/
|
||||
public class MessageQueue {
|
||||
Message mMessages;
|
||||
private final ArrayList mIdleHandlers = new ArrayList();
|
||||
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
|
||||
private boolean mQuiting = false;
|
||||
private int mObject = 0; // used by native code
|
||||
boolean mQuitAllowed = true;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private int mPtr; // used by native code
|
||||
|
||||
private native void nativeInit();
|
||||
private native void nativeDestroy();
|
||||
private native boolean nativePollOnce(int timeoutMillis);
|
||||
private native void nativeWake();
|
||||
|
||||
/**
|
||||
* Callback interface for discovering when a thread is going to block
|
||||
* waiting for more messages.
|
||||
@@ -85,55 +90,39 @@ public class MessageQueue {
|
||||
mIdleHandlers.remove(handler);
|
||||
}
|
||||
}
|
||||
|
||||
// Add an input pipe to the set being selected over. If token is
|
||||
// negative, remove 'handler's entry from the current set and forget
|
||||
// about it.
|
||||
void setInputToken(int token, int region, Handler handler) {
|
||||
if (token >= 0) nativeRegisterInputStream(token, region, handler);
|
||||
else nativeUnregisterInputStream(token);
|
||||
}
|
||||
|
||||
|
||||
MessageQueue() {
|
||||
nativeInit();
|
||||
}
|
||||
private native void nativeInit();
|
||||
|
||||
/**
|
||||
* @param token fd of the readable end of the input stream
|
||||
* @param region fd of the ashmem region used for data transport alongside the 'token' fd
|
||||
* @param handler Handler from which to make input messages based on data read from the fd
|
||||
*/
|
||||
private native void nativeRegisterInputStream(int token, int region, Handler handler);
|
||||
private native void nativeUnregisterInputStream(int token);
|
||||
private native void nativeSignal();
|
||||
|
||||
/**
|
||||
* Wait until the designated time for new messages to arrive.
|
||||
*
|
||||
* @param when Timestamp in SystemClock.uptimeMillis() base of the next message in the queue.
|
||||
* If 'when' is zero, the method will check for incoming messages without blocking. If
|
||||
* 'when' is negative, the method will block forever waiting for the next message.
|
||||
* @return
|
||||
*/
|
||||
private native int nativeWaitForNext(long when);
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
nativeDestroy();
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
final Message next() {
|
||||
boolean tryIdle = true;
|
||||
// when we start out, we'll just touch the input pipes and then go from there
|
||||
long timeToNextEventMillis = 0;
|
||||
int timeToNextEventMillis = 0;
|
||||
|
||||
while (true) {
|
||||
long now;
|
||||
Object[] idlers = null;
|
||||
|
||||
nativeWaitForNext(timeToNextEventMillis);
|
||||
boolean dispatched = nativePollOnce(timeToNextEventMillis);
|
||||
|
||||
// Try to retrieve the next message, returning if found.
|
||||
synchronized (this) {
|
||||
now = SystemClock.uptimeMillis();
|
||||
Message msg = pullNextLocked(now);
|
||||
if (msg != null) return msg;
|
||||
if (msg != null) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
if (tryIdle && mIdleHandlers.size() > 0) {
|
||||
idlers = mIdleHandlers.toArray();
|
||||
}
|
||||
@@ -170,9 +159,14 @@ public class MessageQueue {
|
||||
synchronized (this) {
|
||||
// No messages, nobody to tell about it... time to wait!
|
||||
if (mMessages != null) {
|
||||
if (mMessages.when - now > 0) {
|
||||
long longTimeToNextEventMillis = mMessages.when - now;
|
||||
|
||||
if (longTimeToNextEventMillis > 0) {
|
||||
Binder.flushPendingCommands();
|
||||
timeToNextEventMillis = mMessages.when - now;
|
||||
timeToNextEventMillis = (int) Math.min(longTimeToNextEventMillis,
|
||||
Integer.MAX_VALUE);
|
||||
} else {
|
||||
timeToNextEventMillis = 0;
|
||||
}
|
||||
} else {
|
||||
Binder.flushPendingCommands();
|
||||
@@ -230,7 +224,7 @@ public class MessageQueue {
|
||||
msg.next = prev.next;
|
||||
prev.next = msg;
|
||||
}
|
||||
nativeSignal();
|
||||
nativeWake();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -351,7 +345,7 @@ public class MessageQueue {
|
||||
void poke()
|
||||
{
|
||||
synchronized (this) {
|
||||
nativeSignal();
|
||||
nativeWake();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.service.wallpaper;
|
||||
|
||||
import com.android.internal.os.HandlerCaller;
|
||||
import com.android.internal.view.BaseIWindow;
|
||||
import com.android.internal.view.BaseInputHandler;
|
||||
import com.android.internal.view.BaseSurfaceHolder;
|
||||
|
||||
import android.annotation.SdkConstant;
|
||||
@@ -39,6 +40,10 @@ import android.util.Log;
|
||||
import android.util.LogPrinter;
|
||||
import android.view.Gravity;
|
||||
import android.view.IWindowSession;
|
||||
import android.view.InputChannel;
|
||||
import android.view.InputHandler;
|
||||
import android.view.InputQueue;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.View;
|
||||
@@ -46,6 +51,7 @@ import android.view.ViewGroup;
|
||||
import android.view.ViewRoot;
|
||||
import android.view.WindowManager;
|
||||
import android.view.WindowManagerImpl;
|
||||
import android.view.WindowManagerPolicy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -146,6 +152,7 @@ public abstract class WallpaperService extends Service {
|
||||
final WindowManager.LayoutParams mLayout
|
||||
= new WindowManager.LayoutParams();
|
||||
IWindowSession mSession;
|
||||
InputChannel mInputChannel;
|
||||
|
||||
final Object mLock = new Object();
|
||||
boolean mOffsetMessageEnqueued;
|
||||
@@ -205,6 +212,30 @@ public abstract class WallpaperService extends Service {
|
||||
|
||||
};
|
||||
|
||||
final InputHandler mInputHandler = new BaseInputHandler() {
|
||||
@Override
|
||||
public void handleTouch(MotionEvent event, Runnable finishedCallback) {
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
if (event.getAction() == MotionEvent.ACTION_MOVE) {
|
||||
if (mPendingMove != null) {
|
||||
mCaller.removeMessages(MSG_TOUCH_EVENT, mPendingMove);
|
||||
mPendingMove.recycle();
|
||||
}
|
||||
mPendingMove = event;
|
||||
} else {
|
||||
mPendingMove = null;
|
||||
}
|
||||
Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT,
|
||||
event);
|
||||
mCaller.sendMessage(msg);
|
||||
}
|
||||
} finally {
|
||||
finishedCallback.run();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final BaseIWindow mWindow = new BaseIWindow() {
|
||||
@Override
|
||||
public boolean onDispatchPointer(MotionEvent event, long eventTime,
|
||||
@@ -487,8 +518,15 @@ public abstract class WallpaperService extends Service {
|
||||
mLayout.setTitle(WallpaperService.this.getClass().getName());
|
||||
mLayout.windowAnimations =
|
||||
com.android.internal.R.style.Animation_Wallpaper;
|
||||
mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets);
|
||||
mInputChannel = new InputChannel();
|
||||
mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets,
|
||||
mInputChannel);
|
||||
mCreated = true;
|
||||
|
||||
if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
|
||||
InputQueue.registerInputChannel(mInputChannel, mInputHandler,
|
||||
Looper.myQueue());
|
||||
}
|
||||
}
|
||||
|
||||
mSurfaceHolder.mSurfaceLock.lock();
|
||||
@@ -587,6 +625,7 @@ public abstract class WallpaperService extends Service {
|
||||
mSurfaceHolder.setSizeFromLayout();
|
||||
mInitializing = true;
|
||||
mSession = ViewRoot.getWindowSession(getMainLooper());
|
||||
|
||||
mWindow.setSession(mSession);
|
||||
|
||||
IntentFilter filter = new IntentFilter();
|
||||
@@ -730,6 +769,15 @@ public abstract class WallpaperService extends Service {
|
||||
try {
|
||||
if (DEBUG) Log.v(TAG, "Removing window and destroying surface "
|
||||
+ mSurfaceHolder.getSurface() + " of: " + this);
|
||||
|
||||
if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
|
||||
if (mInputChannel != null) {
|
||||
InputQueue.unregisterInputChannel(mInputChannel);
|
||||
mInputChannel.dispose();
|
||||
mInputChannel = null;
|
||||
}
|
||||
}
|
||||
|
||||
mSession.remove(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
import android.os.Bundle;
|
||||
import android.view.InputChannel;
|
||||
import android.view.IWindow;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.WindowManager;
|
||||
@@ -33,6 +34,9 @@ import android.view.Surface;
|
||||
*/
|
||||
interface IWindowSession {
|
||||
int add(IWindow window, in WindowManager.LayoutParams attrs,
|
||||
in int viewVisibility, out Rect outContentInsets,
|
||||
out InputChannel outInputChannel);
|
||||
int addWithoutInputChannel(IWindow window, in WindowManager.LayoutParams attrs,
|
||||
in int viewVisibility, out Rect outContentInsets);
|
||||
void remove(IWindow window);
|
||||
|
||||
|
||||
20
core/java/android/view/InputChannel.aidl
Normal file
20
core/java/android/view/InputChannel.aidl
Normal file
@@ -0,0 +1,20 @@
|
||||
/* //device/java/android/android/view/InputChannel.aidl
|
||||
**
|
||||
** Copyright 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;
|
||||
|
||||
parcelable InputChannel;
|
||||
152
core/java/android/view/InputChannel.java
Normal file
152
core/java/android/view/InputChannel.java
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Slog;
|
||||
|
||||
/**
|
||||
* An input channel specifies the file descriptors used to send input events to
|
||||
* a window in another process. It is Parcelable so that it can be transmitted
|
||||
* to the ViewRoot through a Binder transaction as part of registering the Window.
|
||||
* @hide
|
||||
*/
|
||||
public class InputChannel implements Parcelable {
|
||||
private static final String TAG = "InputChannel";
|
||||
|
||||
public static final Parcelable.Creator<InputChannel> CREATOR
|
||||
= new Parcelable.Creator<InputChannel>() {
|
||||
public InputChannel createFromParcel(Parcel source) {
|
||||
InputChannel result = new InputChannel();
|
||||
result.readFromParcel(source);
|
||||
return result;
|
||||
}
|
||||
|
||||
public InputChannel[] newArray(int size) {
|
||||
return new InputChannel[size];
|
||||
}
|
||||
};
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private int mPtr; // used by native code
|
||||
|
||||
private boolean mDisposeAfterWriteToParcel;
|
||||
|
||||
private static native InputChannel[] nativeOpenInputChannelPair(String name);
|
||||
|
||||
private native void nativeDispose(boolean finalized);
|
||||
private native void nativeTransferTo(InputChannel other);
|
||||
private native void nativeReadFromParcel(Parcel parcel);
|
||||
private native void nativeWriteToParcel(Parcel parcel);
|
||||
|
||||
private native String nativeGetName();
|
||||
|
||||
/**
|
||||
* Creates an uninitialized input channel.
|
||||
* It can be initialized by reading from a Parcel or by transferring the state of
|
||||
* another input channel into this one.
|
||||
*/
|
||||
public InputChannel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
nativeDispose(true);
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new input channel pair. One channel should be provided to the input
|
||||
* dispatcher and the other to the application's input queue.
|
||||
* @param name The descriptive (non-unique) name of the channel pair.
|
||||
* @return A pair of input channels. They are symmetric and indistinguishable.
|
||||
*/
|
||||
public static InputChannel[] openInputChannelPair(String name) {
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException("name must not be null");
|
||||
}
|
||||
|
||||
Slog.d(TAG, "Opening input channel pair '" + name + "'");
|
||||
return nativeOpenInputChannelPair(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the input channel.
|
||||
* @return The input channel name.
|
||||
*/
|
||||
public String getName() {
|
||||
String name = nativeGetName();
|
||||
return name != null ? name : "uninitialized";
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes the input channel.
|
||||
* Explicitly releases the reference this object is holding on the input channel.
|
||||
* When all references are released, the input channel will be closed.
|
||||
*/
|
||||
public void dispose() {
|
||||
nativeDispose(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfers ownership of the internal state of the input channel to another
|
||||
* instance and invalidates this instance. This is used to pass an input channel
|
||||
* as an out parameter in a binder call.
|
||||
* @param other The other input channel instance.
|
||||
*/
|
||||
public void transferToBinderOutParameter(InputChannel outParameter) {
|
||||
if (outParameter == null) {
|
||||
throw new IllegalArgumentException("outParameter must not be null");
|
||||
}
|
||||
|
||||
nativeTransferTo(outParameter);
|
||||
outParameter.mDisposeAfterWriteToParcel = true;
|
||||
}
|
||||
|
||||
public int describeContents() {
|
||||
return Parcelable.CONTENTS_FILE_DESCRIPTOR;
|
||||
}
|
||||
|
||||
public void readFromParcel(Parcel in) {
|
||||
if (in == null) {
|
||||
throw new IllegalArgumentException("in must not be null");
|
||||
}
|
||||
|
||||
nativeReadFromParcel(in);
|
||||
}
|
||||
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
if (out == null) {
|
||||
throw new IllegalArgumentException("out must not be null");
|
||||
}
|
||||
|
||||
nativeWriteToParcel(out);
|
||||
|
||||
if (mDisposeAfterWriteToParcel) {
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
53
core/java/android/view/InputHandler.java
Normal file
53
core/java/android/view/InputHandler.java
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Handles input messages that arrive on an input channel.
|
||||
* @hide
|
||||
*/
|
||||
public interface InputHandler {
|
||||
/**
|
||||
* Handle a key event.
|
||||
* It is the responsibility of the callee to ensure that the finished callback is
|
||||
* eventually invoked when the event processing is finished and the input system
|
||||
* can send the next event.
|
||||
* @param event The key event data.
|
||||
* @param finishedCallback The callback to invoke when event processing is finished.
|
||||
*/
|
||||
public void handleKey(KeyEvent event, Runnable finishedCallback);
|
||||
|
||||
/**
|
||||
* Handle a touch event.
|
||||
* It is the responsibility of the callee to ensure that the finished callback is
|
||||
* eventually invoked when the event processing is finished and the input system
|
||||
* can send the next event.
|
||||
* @param event The motion event data.
|
||||
* @param finishedCallback The callback to invoke when event processing is finished.
|
||||
*/
|
||||
public void handleTouch(MotionEvent event, Runnable finishedCallback);
|
||||
|
||||
/**
|
||||
* Handle a trackball event.
|
||||
* It is the responsibility of the callee to ensure that the finished callback is
|
||||
* eventually invoked when the event processing is finished and the input system
|
||||
* can send the next event.
|
||||
* @param event The motion event data.
|
||||
* @param finishedCallback The callback to invoke when event processing is finished.
|
||||
*/
|
||||
public void handleTrackball(MotionEvent event, Runnable finishedCallback);
|
||||
}
|
||||
126
core/java/android/view/InputQueue.java
Normal file
126
core/java/android/view/InputQueue.java
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import android.os.MessageQueue;
|
||||
import android.util.Slog;
|
||||
|
||||
/**
|
||||
* An input queue provides a mechanism for an application to receive incoming
|
||||
* input events sent over an input channel. Signalling is implemented by MessageQueue.
|
||||
* @hide
|
||||
*/
|
||||
public final class InputQueue {
|
||||
private static final String TAG = "InputQueue";
|
||||
|
||||
// Describes the interpretation of an event.
|
||||
// XXX This concept is tentative. See comments in android/input.h.
|
||||
public static final int INPUT_EVENT_NATURE_KEY = 1;
|
||||
public static final int INPUT_EVENT_NATURE_TOUCH = 2;
|
||||
public static final int INPUT_EVENT_NATURE_TRACKBALL = 3;
|
||||
|
||||
private static Object sLock = new Object();
|
||||
|
||||
private static native void nativeRegisterInputChannel(InputChannel inputChannel,
|
||||
InputHandler inputHandler, MessageQueue messageQueue);
|
||||
private static native void nativeUnregisterInputChannel(InputChannel inputChannel);
|
||||
private static native void nativeFinished(long finishedToken);
|
||||
|
||||
private InputQueue() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an input channel and handler.
|
||||
* @param inputChannel The input channel to register.
|
||||
* @param inputHandler The input handler to input events send to the target.
|
||||
* @param messageQueue The message queue on whose thread the handler should be invoked.
|
||||
*/
|
||||
public static void registerInputChannel(InputChannel inputChannel, InputHandler inputHandler,
|
||||
MessageQueue messageQueue) {
|
||||
if (inputChannel == null) {
|
||||
throw new IllegalArgumentException("inputChannel must not be null");
|
||||
}
|
||||
if (inputHandler == null) {
|
||||
throw new IllegalArgumentException("inputHandler must not be null");
|
||||
}
|
||||
if (messageQueue == null) {
|
||||
throw new IllegalArgumentException("messageQueue must not be null");
|
||||
}
|
||||
|
||||
synchronized (sLock) {
|
||||
Slog.d(TAG, "Registering input channel '" + inputChannel + "'");
|
||||
nativeRegisterInputChannel(inputChannel, inputHandler, messageQueue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters an input channel.
|
||||
* Does nothing if the channel is not currently registered.
|
||||
* @param inputChannel The input channel to unregister.
|
||||
*/
|
||||
public static void unregisterInputChannel(InputChannel inputChannel) {
|
||||
if (inputChannel == null) {
|
||||
throw new IllegalArgumentException("inputChannel must not be null");
|
||||
}
|
||||
|
||||
synchronized (sLock) {
|
||||
Slog.d(TAG, "Unregistering input channel '" + inputChannel + "'");
|
||||
nativeUnregisterInputChannel(inputChannel);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static void dispatchKeyEvent(InputHandler inputHandler,
|
||||
KeyEvent event, int nature, long finishedToken) {
|
||||
Runnable finishedCallback = new FinishedCallback(finishedToken);
|
||||
|
||||
if (nature == INPUT_EVENT_NATURE_KEY) {
|
||||
inputHandler.handleKey(event, finishedCallback);
|
||||
} else {
|
||||
Slog.d(TAG, "Unsupported nature for key event: " + nature);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static void dispatchMotionEvent(InputHandler inputHandler,
|
||||
MotionEvent event, int nature, long finishedToken) {
|
||||
Runnable finishedCallback = new FinishedCallback(finishedToken);
|
||||
|
||||
if (nature == INPUT_EVENT_NATURE_TOUCH) {
|
||||
inputHandler.handleTouch(event, finishedCallback);
|
||||
} else if (nature == INPUT_EVENT_NATURE_TRACKBALL) {
|
||||
inputHandler.handleTrackball(event, finishedCallback);
|
||||
} else {
|
||||
Slog.d(TAG, "Unsupported nature for motion event: " + nature);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO consider recycling finished callbacks when done
|
||||
private static class FinishedCallback implements Runnable {
|
||||
private long mFinishedToken;
|
||||
|
||||
public FinishedCallback(long finishedToken) {
|
||||
mFinishedToken = finishedToken;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
synchronized (sLock) {
|
||||
nativeFinished(mFinishedToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
57
core/java/android/view/InputTarget.java
Normal file
57
core/java/android/view/InputTarget.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* An input target specifies how an input event is to be dispatched to a particular window
|
||||
* including the window's input channel, control flags, a timeout, and an X / Y offset to
|
||||
* be added to input event coordinates to compensate for the absolute position of the
|
||||
* window area.
|
||||
*
|
||||
* These parameters are used by the native input dispatching code.
|
||||
* @hide
|
||||
*/
|
||||
public class InputTarget {
|
||||
public InputChannel mInputChannel;
|
||||
public int mFlags;
|
||||
public long mTimeoutNanos;
|
||||
public float mXOffset;
|
||||
public float mYOffset;
|
||||
|
||||
/**
|
||||
* This flag indicates that subsequent event delivery should be held until the
|
||||
* current event is delivered to this target or a timeout occurs.
|
||||
*/
|
||||
public static int FLAG_SYNC = 0x01;
|
||||
|
||||
/**
|
||||
* This flag indicates that a MotionEvent with ACTION_DOWN falls outside of the area of
|
||||
* this target and so should instead be delivered as an ACTION_OUTSIDE to this target.
|
||||
*/
|
||||
public static int FLAG_OUTSIDE = 0x02;
|
||||
|
||||
/*
|
||||
* This flag indicates that a KeyEvent or MotionEvent is being canceled.
|
||||
* In the case of a key event, it should be delivered with KeyEvent.FLAG_CANCELED set.
|
||||
* In the case of a motion event, it should be delivered as MotionEvent.ACTION_CANCEL.
|
||||
*/
|
||||
public static int FLAG_CANCEL = 0x04;
|
||||
|
||||
public void recycle() {
|
||||
mInputChannel = null;
|
||||
}
|
||||
}
|
||||
@@ -127,6 +127,7 @@ public class KeyEvent implements Parcelable {
|
||||
|
||||
// NOTE: If you add a new keycode here you must also add it to:
|
||||
// isSystem()
|
||||
// native/include/android/keycodes.h
|
||||
// frameworks/base/include/ui/KeycodeLabels.h
|
||||
// tools/puppet_master/PuppetMaster/nav_keys.py
|
||||
// frameworks/base/core/res/res/values/attrs.xml
|
||||
@@ -162,7 +163,7 @@ public class KeyEvent implements Parcelable {
|
||||
* key code is not {#link {@link #KEYCODE_UNKNOWN} then the
|
||||
* {#link {@link #getRepeatCount()} method returns the number of times
|
||||
* the given key code should be executed.
|
||||
* Otherwise, if the key code {@link #KEYCODE_UNKNOWN}, then
|
||||
* Otherwise, if the key code is {@link #KEYCODE_UNKNOWN}, then
|
||||
* this is a sequence of characters as returned by {@link #getCharacters}.
|
||||
*/
|
||||
public static final int ACTION_MULTIPLE = 2;
|
||||
@@ -330,7 +331,7 @@ public class KeyEvent implements Parcelable {
|
||||
private int mMetaState;
|
||||
private int mAction;
|
||||
private int mKeyCode;
|
||||
private int mScancode;
|
||||
private int mScanCode;
|
||||
private int mRepeatCount;
|
||||
private int mDeviceId;
|
||||
private int mFlags;
|
||||
@@ -480,7 +481,7 @@ public class KeyEvent implements Parcelable {
|
||||
mRepeatCount = repeat;
|
||||
mMetaState = metaState;
|
||||
mDeviceId = device;
|
||||
mScancode = scancode;
|
||||
mScanCode = scancode;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -510,7 +511,7 @@ public class KeyEvent implements Parcelable {
|
||||
mRepeatCount = repeat;
|
||||
mMetaState = metaState;
|
||||
mDeviceId = device;
|
||||
mScancode = scancode;
|
||||
mScanCode = scancode;
|
||||
mFlags = flags;
|
||||
}
|
||||
|
||||
@@ -547,7 +548,7 @@ public class KeyEvent implements Parcelable {
|
||||
mRepeatCount = origEvent.mRepeatCount;
|
||||
mMetaState = origEvent.mMetaState;
|
||||
mDeviceId = origEvent.mDeviceId;
|
||||
mScancode = origEvent.mScancode;
|
||||
mScanCode = origEvent.mScanCode;
|
||||
mFlags = origEvent.mFlags;
|
||||
mCharacters = origEvent.mCharacters;
|
||||
}
|
||||
@@ -572,7 +573,7 @@ public class KeyEvent implements Parcelable {
|
||||
mRepeatCount = newRepeat;
|
||||
mMetaState = origEvent.mMetaState;
|
||||
mDeviceId = origEvent.mDeviceId;
|
||||
mScancode = origEvent.mScancode;
|
||||
mScanCode = origEvent.mScanCode;
|
||||
mFlags = origEvent.mFlags;
|
||||
mCharacters = origEvent.mCharacters;
|
||||
}
|
||||
@@ -625,7 +626,7 @@ public class KeyEvent implements Parcelable {
|
||||
mRepeatCount = origEvent.mRepeatCount;
|
||||
mMetaState = origEvent.mMetaState;
|
||||
mDeviceId = origEvent.mDeviceId;
|
||||
mScancode = origEvent.mScancode;
|
||||
mScanCode = origEvent.mScanCode;
|
||||
mFlags = origEvent.mFlags;
|
||||
// Don't copy mCharacters, since one way or the other we'll lose it
|
||||
// when changing the action.
|
||||
@@ -859,7 +860,7 @@ public class KeyEvent implements Parcelable {
|
||||
* Mostly this is here for debugging purposes.
|
||||
*/
|
||||
public final int getScanCode() {
|
||||
return mScancode;
|
||||
return mScanCode;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1183,7 +1184,7 @@ public class KeyEvent implements Parcelable {
|
||||
public String toString() {
|
||||
return "KeyEvent{action=" + mAction + " code=" + mKeyCode
|
||||
+ " repeat=" + mRepeatCount
|
||||
+ " meta=" + mMetaState + " scancode=" + mScancode
|
||||
+ " meta=" + mMetaState + " scancode=" + mScanCode
|
||||
+ " mFlags=" + mFlags + "}";
|
||||
}
|
||||
|
||||
@@ -1208,7 +1209,7 @@ public class KeyEvent implements Parcelable {
|
||||
out.writeInt(mRepeatCount);
|
||||
out.writeInt(mMetaState);
|
||||
out.writeInt(mDeviceId);
|
||||
out.writeInt(mScancode);
|
||||
out.writeInt(mScanCode);
|
||||
out.writeInt(mFlags);
|
||||
out.writeLong(mDownTime);
|
||||
out.writeLong(mEventTime);
|
||||
@@ -1220,7 +1221,7 @@ public class KeyEvent implements Parcelable {
|
||||
mRepeatCount = in.readInt();
|
||||
mMetaState = in.readInt();
|
||||
mDeviceId = in.readInt();
|
||||
mScancode = in.readInt();
|
||||
mScanCode = in.readInt();
|
||||
mFlags = in.readInt();
|
||||
mDownTime = in.readLong();
|
||||
mEventTime = in.readLong();
|
||||
|
||||
@@ -248,17 +248,17 @@ public final class MotionEvent implements Parcelable {
|
||||
private RuntimeException mRecycledLocation;
|
||||
private boolean mRecycled;
|
||||
|
||||
private MotionEvent() {
|
||||
mPointerIdentifiers = new int[BASE_AVAIL_POINTERS];
|
||||
mDataSamples = new float[BASE_AVAIL_POINTERS*BASE_AVAIL_SAMPLES*NUM_SAMPLE_DATA];
|
||||
mTimeSamples = new long[BASE_AVAIL_SAMPLES];
|
||||
private MotionEvent(int pointerCount, int sampleCount) {
|
||||
mPointerIdentifiers = new int[pointerCount];
|
||||
mDataSamples = new float[pointerCount * sampleCount * NUM_SAMPLE_DATA];
|
||||
mTimeSamples = new long[sampleCount];
|
||||
}
|
||||
|
||||
static private MotionEvent obtain() {
|
||||
final MotionEvent ev;
|
||||
synchronized (gRecyclerLock) {
|
||||
if (gRecyclerTop == null) {
|
||||
return new MotionEvent();
|
||||
return new MotionEvent(BASE_AVAIL_POINTERS, BASE_AVAIL_SAMPLES);
|
||||
}
|
||||
ev = gRecyclerTop;
|
||||
gRecyclerTop = ev.mNext;
|
||||
@@ -269,6 +269,45 @@ public final class MotionEvent implements Parcelable {
|
||||
ev.mNext = null;
|
||||
return ev;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused") // used by native code
|
||||
static private MotionEvent obtain(int pointerCount, int sampleCount) {
|
||||
final MotionEvent ev;
|
||||
synchronized (gRecyclerLock) {
|
||||
if (gRecyclerTop == null) {
|
||||
if (pointerCount < BASE_AVAIL_POINTERS) {
|
||||
pointerCount = BASE_AVAIL_POINTERS;
|
||||
}
|
||||
if (sampleCount < BASE_AVAIL_SAMPLES) {
|
||||
sampleCount = BASE_AVAIL_SAMPLES;
|
||||
}
|
||||
return new MotionEvent(pointerCount, sampleCount);
|
||||
}
|
||||
ev = gRecyclerTop;
|
||||
gRecyclerTop = ev.mNext;
|
||||
gRecyclerUsed--;
|
||||
}
|
||||
ev.mRecycledLocation = null;
|
||||
ev.mRecycled = false;
|
||||
ev.mNext = null;
|
||||
|
||||
if (ev.mPointerIdentifiers.length < pointerCount) {
|
||||
ev.mPointerIdentifiers = new int[pointerCount];
|
||||
}
|
||||
|
||||
final int timeSamplesLength = ev.mTimeSamples.length;
|
||||
if (timeSamplesLength < sampleCount) {
|
||||
ev.mTimeSamples = new long[sampleCount];
|
||||
}
|
||||
|
||||
final int dataSamplesLength = ev.mDataSamples.length;
|
||||
final int neededDataSamplesLength = pointerCount * sampleCount * NUM_SAMPLE_DATA;
|
||||
if (dataSamplesLength < neededDataSamplesLength) {
|
||||
ev.mDataSamples = new float[neededDataSamplesLength];
|
||||
}
|
||||
|
||||
return ev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new MotionEvent, filling in all of the basic values that
|
||||
@@ -1022,7 +1061,7 @@ public final class MotionEvent implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a bitfield indicating which edges, if any, where touched by this
|
||||
* Returns a bitfield indicating which edges, if any, were touched by this
|
||||
* MotionEvent. For touch events, clients can use this to determine if the
|
||||
* user's finger was touching the edge of the display.
|
||||
*
|
||||
|
||||
@@ -471,7 +471,7 @@ public class SurfaceView extends View {
|
||||
mWindow = new MyWindow(this);
|
||||
mLayout.type = mWindowType;
|
||||
mLayout.gravity = Gravity.LEFT|Gravity.TOP;
|
||||
mSession.add(mWindow, mLayout,
|
||||
mSession.addWithoutInputChannel(mWindow, mLayout,
|
||||
mVisible ? VISIBLE : GONE, mContentInsets);
|
||||
}
|
||||
|
||||
|
||||
@@ -153,6 +153,7 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
CompatibilityInfo.Translator mTranslator;
|
||||
|
||||
final View.AttachInfo mAttachInfo;
|
||||
InputChannel mInputChannel;
|
||||
|
||||
final Rect mTempRect; // used in the transaction to not thrash the heap.
|
||||
final Rect mVisRect; // used to retrieve visible rect of focused view.
|
||||
@@ -219,7 +220,7 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
AudioManager mAudioManager;
|
||||
|
||||
private final int mDensity;
|
||||
|
||||
|
||||
public static IWindowSession getWindowSession(Looper mainLooper) {
|
||||
synchronized (mStaticInit) {
|
||||
if (!mInitialized) {
|
||||
@@ -434,9 +435,6 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
}
|
||||
}
|
||||
|
||||
// fd [0] is the receiver, [1] is the sender
|
||||
private native int[] makeInputChannel();
|
||||
|
||||
/**
|
||||
* We have one child
|
||||
*/
|
||||
@@ -488,25 +486,20 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
mAdded = true;
|
||||
int res; /* = WindowManagerImpl.ADD_OKAY; */
|
||||
|
||||
// Set up the input event channel
|
||||
if (false) {
|
||||
int[] fds = makeInputChannel();
|
||||
if (DEBUG_INPUT) {
|
||||
Log.v(TAG, "makeInputChannel() returned " + fds);
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule the first layout -before- adding to the window
|
||||
// manager, to make sure we do the relayout before receiving
|
||||
// any other events from the system.
|
||||
requestLayout();
|
||||
mInputChannel = new InputChannel();
|
||||
try {
|
||||
res = sWindowSession.add(mWindow, mWindowAttributes,
|
||||
getHostVisibility(), mAttachInfo.mContentInsets);
|
||||
getHostVisibility(), mAttachInfo.mContentInsets,
|
||||
mInputChannel);
|
||||
} catch (RemoteException e) {
|
||||
mAdded = false;
|
||||
mView = null;
|
||||
mAttachInfo.mRootView = null;
|
||||
mInputChannel = null;
|
||||
unscheduleTraversals();
|
||||
throw new RuntimeException("Adding window failed", e);
|
||||
} finally {
|
||||
@@ -514,7 +507,7 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
attrs.restore();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (mTranslator != null) {
|
||||
mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
|
||||
}
|
||||
@@ -560,6 +553,12 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
throw new RuntimeException(
|
||||
"Unable to add window -- unknown error code " + res);
|
||||
}
|
||||
|
||||
if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
|
||||
InputQueue.registerInputChannel(mInputChannel, mInputHandler,
|
||||
Looper.myQueue());
|
||||
}
|
||||
|
||||
view.assignParent(this);
|
||||
mAddedTouchMode = (res&WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE) != 0;
|
||||
mAppVisible = (res&WindowManagerImpl.ADD_FLAG_APP_VISIBLE) != 0;
|
||||
@@ -1735,6 +1734,14 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
}
|
||||
mSurface.release();
|
||||
|
||||
if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
|
||||
if (mInputChannel != null) {
|
||||
InputQueue.unregisterInputChannel(mInputChannel);
|
||||
mInputChannel.dispose();
|
||||
mInputChannel = null;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
sWindowSession.remove(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
@@ -1841,19 +1848,16 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
boolean callWhenDone = msg.arg1 != 0;
|
||||
|
||||
if (event == null) {
|
||||
try {
|
||||
long timeBeforeGettingEvents;
|
||||
if (MEASURE_LATENCY) {
|
||||
timeBeforeGettingEvents = System.nanoTime();
|
||||
}
|
||||
long timeBeforeGettingEvents;
|
||||
if (MEASURE_LATENCY) {
|
||||
timeBeforeGettingEvents = System.nanoTime();
|
||||
}
|
||||
|
||||
event = sWindowSession.getPendingPointerMove(mWindow);
|
||||
event = getPendingPointerMotionEvent();
|
||||
|
||||
if (MEASURE_LATENCY && event != null) {
|
||||
lt.sample("9 Client got events ", System.nanoTime() - event.getEventTimeNano());
|
||||
lt.sample("8 Client getting events ", timeBeforeGettingEvents - event.getEventTimeNano());
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
if (MEASURE_LATENCY && event != null) {
|
||||
lt.sample("9 Client got events ", System.nanoTime() - event.getEventTimeNano());
|
||||
lt.sample("8 Client getting events ", timeBeforeGettingEvents - event.getEventTimeNano());
|
||||
}
|
||||
callWhenDone = false;
|
||||
}
|
||||
@@ -1928,14 +1932,9 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
}
|
||||
} finally {
|
||||
if (callWhenDone) {
|
||||
try {
|
||||
sWindowSession.finishKey(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
if (event != null) {
|
||||
event.recycle();
|
||||
finishMotionEvent();
|
||||
}
|
||||
recycleMotionEvent(event);
|
||||
if (LOCAL_LOGV || WATCH_POINTER) Log.i(TAG, "Done dispatching!");
|
||||
// Let the exception fall through -- the looper will catch
|
||||
// it and take care of the bad app for us.
|
||||
@@ -2075,7 +2074,63 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
private void finishKeyEvent(KeyEvent event) {
|
||||
if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
|
||||
if (mFinishedCallback != null) {
|
||||
mFinishedCallback.run();
|
||||
mFinishedCallback = null;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
sWindowSession.finishKey(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void finishMotionEvent() {
|
||||
if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
|
||||
throw new IllegalStateException("Should not be reachable with native input dispatch.");
|
||||
}
|
||||
|
||||
try {
|
||||
sWindowSession.finishKey(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
private void recycleMotionEvent(MotionEvent event) {
|
||||
if (event != null) {
|
||||
event.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
private MotionEvent getPendingPointerMotionEvent() {
|
||||
if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
|
||||
throw new IllegalStateException("Should not be reachable with native input dispatch.");
|
||||
}
|
||||
|
||||
try {
|
||||
return sWindowSession.getPendingPointerMove(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private MotionEvent getPendingTrackballMotionEvent() {
|
||||
if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
|
||||
throw new IllegalStateException("Should not be reachable with native input dispatch.");
|
||||
}
|
||||
|
||||
try {
|
||||
return sWindowSession.getPendingTrackballMove(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Something in the current window tells us we need to change the touch mode. For
|
||||
* example, we are not in touch mode, and the user touches the screen.
|
||||
@@ -2200,10 +2255,7 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
|
||||
private void deliverTrackballEvent(MotionEvent event, boolean callWhenDone) {
|
||||
if (event == null) {
|
||||
try {
|
||||
event = sWindowSession.getPendingTrackballMove(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
event = getPendingTrackballMotionEvent();
|
||||
callWhenDone = false;
|
||||
}
|
||||
|
||||
@@ -2223,14 +2275,9 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
} finally {
|
||||
if (handled) {
|
||||
if (callWhenDone) {
|
||||
try {
|
||||
sWindowSession.finishKey(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
if (event != null) {
|
||||
event.recycle();
|
||||
finishMotionEvent();
|
||||
}
|
||||
recycleMotionEvent(event);
|
||||
// If we reach this, we delivered a trackball event to mView and
|
||||
// mView consumed it. Because we will not translate the trackball
|
||||
// event into a key event, touch mode will not exit, so we exit
|
||||
@@ -2339,13 +2386,8 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
}
|
||||
} finally {
|
||||
if (callWhenDone) {
|
||||
try {
|
||||
sWindowSession.finishKey(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
if (event != null) {
|
||||
event.recycle();
|
||||
}
|
||||
finishMotionEvent();
|
||||
recycleMotionEvent(event);
|
||||
}
|
||||
// Let the exception fall through -- the looper will catch
|
||||
// it and take care of the bad app for us.
|
||||
@@ -2503,10 +2545,7 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
if (sendDone) {
|
||||
if (LOCAL_LOGV) Log.v(
|
||||
"ViewRoot", "Telling window manager key is finished");
|
||||
try {
|
||||
sWindowSession.finishKey(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
finishKeyEvent(event);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -2539,10 +2578,7 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
} else if (sendDone) {
|
||||
if (LOCAL_LOGV) Log.v(
|
||||
"ViewRoot", "Telling window manager key is finished");
|
||||
try {
|
||||
sWindowSession.finishKey(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
finishKeyEvent(event);
|
||||
} else {
|
||||
Log.w("ViewRoot", "handleFinishedEvent(seq=" + seq
|
||||
+ " handled=" + handled + " ev=" + event
|
||||
@@ -2617,10 +2653,7 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
if (sendDone) {
|
||||
if (LOCAL_LOGV) Log.v(
|
||||
"ViewRoot", "Telling window manager key is finished");
|
||||
try {
|
||||
sWindowSession.finishKey(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
finishKeyEvent(event);
|
||||
}
|
||||
// Let the exception fall through -- the looper will catch
|
||||
// it and take care of the bad app for us.
|
||||
@@ -2798,6 +2831,53 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
msg.obj = ri;
|
||||
sendMessage(msg);
|
||||
}
|
||||
|
||||
private Runnable mFinishedCallback;
|
||||
|
||||
private final InputHandler mInputHandler = new InputHandler() {
|
||||
public void handleKey(KeyEvent event, Runnable finishedCallback) {
|
||||
mFinishedCallback = finishedCallback;
|
||||
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
//noinspection ConstantConditions
|
||||
if (false && event.getKeyCode() == KeyEvent.KEYCODE_CAMERA) {
|
||||
if (Config.LOGD) Log.d("keydisp",
|
||||
"===================================================");
|
||||
if (Config.LOGD) Log.d("keydisp", "Focused view Hierarchy is:");
|
||||
debug();
|
||||
|
||||
if (Config.LOGD) Log.d("keydisp",
|
||||
"===================================================");
|
||||
}
|
||||
}
|
||||
|
||||
Message msg = obtainMessage(DISPATCH_KEY);
|
||||
msg.obj = event;
|
||||
|
||||
if (LOCAL_LOGV) Log.v(
|
||||
"ViewRoot", "sending key " + event + " to " + mView);
|
||||
|
||||
sendMessageAtTime(msg, event.getEventTime());
|
||||
}
|
||||
|
||||
public void handleTouch(MotionEvent event, Runnable finishedCallback) {
|
||||
finishedCallback.run();
|
||||
|
||||
Message msg = obtainMessage(DISPATCH_POINTER);
|
||||
msg.obj = event;
|
||||
msg.arg1 = 0;
|
||||
sendMessageAtTime(msg, event.getEventTime());
|
||||
}
|
||||
|
||||
public void handleTrackball(MotionEvent event, Runnable finishedCallback) {
|
||||
finishedCallback.run();
|
||||
|
||||
Message msg = obtainMessage(DISPATCH_TRACKBALL);
|
||||
msg.obj = event;
|
||||
msg.arg1 = 0;
|
||||
sendMessageAtTime(msg, event.getEventTime());
|
||||
}
|
||||
};
|
||||
|
||||
public void dispatchKey(KeyEvent event) {
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
@@ -2968,7 +3048,7 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
}
|
||||
}
|
||||
|
||||
static class EventCompletion extends Handler {
|
||||
class EventCompletion extends Handler {
|
||||
final IWindow mWindow;
|
||||
final KeyEvent mKeyEvent;
|
||||
final boolean mIsPointer;
|
||||
@@ -2987,40 +3067,25 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
if (mKeyEvent != null) {
|
||||
try {
|
||||
sWindowSession.finishKey(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
finishKeyEvent(mKeyEvent);
|
||||
} else if (mIsPointer) {
|
||||
boolean didFinish;
|
||||
MotionEvent event = mMotionEvent;
|
||||
if (event == null) {
|
||||
try {
|
||||
event = sWindowSession.getPendingPointerMove(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
event = getPendingPointerMotionEvent();
|
||||
didFinish = true;
|
||||
} else {
|
||||
didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE;
|
||||
}
|
||||
if (!didFinish) {
|
||||
try {
|
||||
sWindowSession.finishKey(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
finishMotionEvent();
|
||||
}
|
||||
} else {
|
||||
MotionEvent event = mMotionEvent;
|
||||
if (event == null) {
|
||||
try {
|
||||
event = sWindowSession.getPendingTrackballMove(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
event = getPendingTrackballMotionEvent();
|
||||
} else {
|
||||
try {
|
||||
sWindowSession.finishKey(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
finishMotionEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3050,7 +3115,7 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
viewRoot.dispatchKey(event);
|
||||
} else {
|
||||
Log.w("ViewRoot.W", "Key event " + event + " but no ViewRoot available!");
|
||||
new EventCompletion(mMainLooper, this, event, false, null);
|
||||
viewRoot.new EventCompletion(mMainLooper, this, event, false, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3064,7 +3129,7 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
}
|
||||
viewRoot.dispatchPointer(event, eventTime, callWhenDone);
|
||||
} else {
|
||||
new EventCompletion(mMainLooper, this, null, true, event);
|
||||
viewRoot.new EventCompletion(mMainLooper, this, null, true, event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3074,7 +3139,7 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
if (viewRoot != null) {
|
||||
viewRoot.dispatchTrackball(event, eventTime, callWhenDone);
|
||||
} else {
|
||||
new EventCompletion(mMainLooper, this, null, false, event);
|
||||
viewRoot.new EventCompletion(mMainLooper, this, null, false, event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -78,6 +78,12 @@ public interface WindowManagerPolicy {
|
||||
public final static int FLAG_BRIGHT_HERE = 0x20000000;
|
||||
|
||||
public final static boolean WATCH_POINTER = false;
|
||||
|
||||
/**
|
||||
* Temporary flag added during the transition to the new native input dispatcher.
|
||||
* This will be removed when the old input dispatch code is deleted.
|
||||
*/
|
||||
public final static boolean ENABLE_NATIVE_INPUT_DISPATCH = false;
|
||||
|
||||
// flags for interceptKeyTq
|
||||
/**
|
||||
@@ -708,6 +714,8 @@ public interface WindowManagerPolicy {
|
||||
*/
|
||||
public boolean preprocessInputEventTq(RawInputEvent event);
|
||||
|
||||
public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
|
||||
|
||||
/**
|
||||
* Determine whether a given key code is used to cause an app switch
|
||||
* to occur (most often the HOME key, also often ENDCALL). If you return
|
||||
|
||||
39
core/java/com/android/internal/view/BaseInputHandler.java
Normal file
39
core/java/com/android/internal/view/BaseInputHandler.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 com.android.internal.view;
|
||||
|
||||
import android.view.InputHandler;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
/**
|
||||
* Base do-nothing implementation of an input handler.
|
||||
* @hide
|
||||
*/
|
||||
public abstract class BaseInputHandler implements InputHandler {
|
||||
public void handleKey(KeyEvent event, Runnable finishedCallback) {
|
||||
finishedCallback.run();
|
||||
}
|
||||
|
||||
public void handleTouch(MotionEvent event, Runnable finishedCallback) {
|
||||
finishedCallback.run();
|
||||
}
|
||||
|
||||
public void handleTrackball(MotionEvent event, Runnable finishedCallback) {
|
||||
finishedCallback.run();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user