diff options
25 files changed, 1426 insertions, 658 deletions
diff --git a/services/input/Android.mk b/services/input/Android.mk index 37804ff66d31..d7b61fc9592e 100644 --- a/services/input/Android.mk +++ b/services/input/Android.mk @@ -21,6 +21,7 @@ LOCAL_SRC_FILES:= \ InputDispatcher.cpp \ InputManager.cpp \ InputReader.cpp \ + InputWindow.cpp \ PointerController.cpp LOCAL_SHARED_LIBRARIES := \ diff --git a/services/input/InputApplication.h b/services/input/InputApplication.h new file mode 100644 index 000000000000..cc8006217c11 --- /dev/null +++ b/services/input/InputApplication.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef _UI_INPUT_APPLICATION_H +#define _UI_INPUT_APPLICATION_H + +#include <ui/Input.h> + +#include <utils/RefBase.h> +#include <utils/Timers.h> +#include <utils/String8.h> + +namespace android { + +/* + * A handle to an application that can receive input. + * Used by the native input dispatcher to indirectly refer to the window manager objects + * that describe an application. + */ +class InputApplicationHandle : public RefBase { +protected: + InputApplicationHandle() { } + virtual ~InputApplicationHandle() { } +}; + + +/* + * An input application describes properties of an application that can receive input. + */ +struct InputApplication { + sp<InputApplicationHandle> inputApplicationHandle; + String8 name; + nsecs_t dispatchingTimeout; +}; + +} // namespace android + +#endif // _UI_INPUT_APPLICATION_H diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index 89a7751a35fd..b5a4bd2da0c7 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -72,6 +72,10 @@ const nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5 sec // when an application takes too long to respond and the user has pressed an app switch key. const nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec +// Amount of time to allow for an event to be dispatched (measured since its eventTime) +// before considering it stale and dropping it. +const nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL; // 10sec + static inline nsecs_t now() { return systemTime(SYSTEM_TIME_MONOTONIC); @@ -151,34 +155,12 @@ static bool validateMotionEvent(int32_t action, size_t pointerCount, } -// --- InputWindow --- - -bool InputWindow::touchableAreaContainsPoint(int32_t x, int32_t y) const { - return x >= touchableAreaLeft && x <= touchableAreaRight - && y >= touchableAreaTop && y <= touchableAreaBottom; -} - -bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const { - return x >= frameLeft && x <= frameRight - && y >= frameTop && y <= frameBottom; -} - -bool InputWindow::isTrustedOverlay() const { - return layoutParamsType == TYPE_INPUT_METHOD - || layoutParamsType == TYPE_INPUT_METHOD_DIALOG - || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY; -} - -bool InputWindow::supportsSplitTouch() const { - return layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH; -} - - // --- InputDispatcher --- InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) : mPolicy(policy), - mPendingEvent(NULL), mAppSwitchDueTime(LONG_LONG_MAX), + mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), + mNextUnblockedEvent(NULL), mDispatchEnabled(true), mDispatchFrozen(false), mFocusedWindow(NULL), mFocusedApplication(NULL), @@ -368,6 +350,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, } // Now we have an event to dispatch. + // All events are eventually dequeued and processed this way, even if we intend to drop them. assert(mPendingEvent != NULL); bool done = false; DropReason dropReason = DROP_REASON_NOT_DROPPED; @@ -376,6 +359,11 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, } else if (!mDispatchEnabled) { dropReason = DROP_REASON_DISABLED; } + + if (mNextUnblockedEvent == mPendingEvent) { + mNextUnblockedEvent = NULL; + } + switch (mPendingEvent->type) { case EventEntry::TYPE_CONFIGURATION_CHANGED: { ConfigurationChangedEntry* typedEntry = @@ -395,6 +383,13 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, dropReason = DROP_REASON_APP_SWITCH; } } + if (dropReason == DROP_REASON_NOT_DROPPED + && isStaleEventLocked(currentTime, typedEntry)) { + dropReason = DROP_REASON_STALE; + } + if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { + dropReason = DROP_REASON_BLOCKED; + } done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout, &dropReason, nextWakeupTime); break; @@ -405,6 +400,13 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { dropReason = DROP_REASON_APP_SWITCH; } + if (dropReason == DROP_REASON_NOT_DROPPED + && isStaleEventLocked(currentTime, typedEntry)) { + dropReason = DROP_REASON_STALE; + } + if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { + dropReason = DROP_REASON_BLOCKED; + } done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); break; @@ -431,6 +433,9 @@ bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { switch (entry->type) { case EventEntry::TYPE_KEY: { + // Optimize app switch latency. + // If the application takes too long to catch up then we drop all events preceding + // the app switch key. KeyEntry* keyEntry = static_cast<KeyEntry*>(entry); if (isAppSwitchKeyEventLocked(keyEntry)) { if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) { @@ -448,11 +453,63 @@ bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { } break; } + + case EventEntry::TYPE_MOTION: { + // Optimize case where the current application is unresponsive and the user + // decides to touch a window in a different application. + // If the application takes too long to catch up then we drop all events preceding + // the touch into the other window. + MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); + if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN + && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) + && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY + && mInputTargetWaitApplication != NULL) { + int32_t x = int32_t(motionEntry->firstSample.pointerCoords[0].x); + int32_t y = int32_t(motionEntry->firstSample.pointerCoords[0].y); + const InputWindow* touchedWindow = findTouchedWindowAtLocked(x, y); + if (touchedWindow + && touchedWindow->inputWindowHandle != NULL + && touchedWindow->inputWindowHandle->getInputApplicationHandle() + != mInputTargetWaitApplication) { + // User touched a different application than the one we are waiting on. + // Flag the event, and start pruning the input queue. + mNextUnblockedEvent = motionEntry; + needWake = true; + } + } + break; + } } return needWake; } +const InputWindow* InputDispatcher::findTouchedWindowAtLocked(int32_t x, int32_t y) { + // Traverse windows from front to back to find touched window. + size_t numWindows = mWindows.size(); + for (size_t i = 0; i < numWindows; i++) { + const InputWindow* window = & mWindows.editItemAt(i); + int32_t flags = window->layoutParamsFlags; + + if (window->visible) { + if (!(flags & InputWindow::FLAG_NOT_TOUCHABLE)) { + bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE + | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0; + if (isTouchModal || window->touchableAreaContainsPoint(x, y)) { + // Found window. + return window; + } + } + } + + if (flags & InputWindow::FLAG_SYSTEM_ERROR) { + // Error window is on top but not visible, so touch is dropped. + return NULL; + } + } + return NULL; +} + void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) { const char* reason; switch (dropReason) { @@ -470,6 +527,16 @@ void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropR LOGI("Dropped event because of pending overdue app switch."); reason = "inbound event was dropped because of pending overdue app switch"; break; + case DROP_REASON_BLOCKED: + LOGI("Dropped event because the current application is not responding and the user " + "has started interating with a different application."); + reason = "inbound event was dropped because the current application is not responding " + "and the user has started interating with a different application"; + break; + case DROP_REASON_STALE: + LOGI("Dropped event because it is stale."); + reason = "inbound event was dropped because it is stale"; + break; default: assert(false); return; @@ -521,6 +588,10 @@ void InputDispatcher::resetPendingAppSwitchLocked(bool handled) { #endif } +bool InputDispatcher::isStaleEventLocked(nsecs_t currentTime, EventEntry* entry) { + return currentTime - entry->eventTime >= STALE_EVENT_TIMEOUT; +} + bool InputDispatcher::runCommandsLockedInterruptible() { if (mCommandQueue.isEmpty()) { return false; @@ -670,7 +741,7 @@ bool InputDispatcher::dispatchKeyLocked( CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); if (mFocusedWindow) { - commandEntry->inputChannel = mFocusedWindow->inputChannel; + commandEntry->inputWindowHandle = mFocusedWindow->inputWindowHandle; } commandEntry->keyEntry = entry; entry->refCount += 1; @@ -848,6 +919,7 @@ void InputDispatcher::resetTargetsLocked() { mCurrentInputTargetsValid = false; mCurrentInputTargets.clear(); mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE; + mInputTargetWaitApplication.clear(); } void InputDispatcher::commitTargetsLocked() { @@ -866,6 +938,7 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, mInputTargetWaitStartTime = currentTime; mInputTargetWaitTimeoutTime = LONG_LONG_MAX; mInputTargetWaitTimeoutExpired = false; + mInputTargetWaitApplication.clear(); } } else { if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { @@ -880,6 +953,15 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, mInputTargetWaitStartTime = currentTime; mInputTargetWaitTimeoutTime = currentTime + timeout; mInputTargetWaitTimeoutExpired = false; + mInputTargetWaitApplication.clear(); + + if (window && window->inputWindowHandle != NULL) { + mInputTargetWaitApplication = + window->inputWindowHandle->getInputApplicationHandle(); + } + if (mInputTargetWaitApplication == NULL && application) { + mInputTargetWaitApplication = application->inputApplicationHandle; + } } } @@ -2624,7 +2706,7 @@ void InputDispatcher::setFocusedApplication(const InputApplication* inputApplica void InputDispatcher::releaseFocusedApplicationLocked() { if (mFocusedApplication) { mFocusedApplication = NULL; - mFocusedApplicationStorage.handle.clear(); + mFocusedApplicationStorage.inputApplicationHandle.clear(); } } @@ -2860,7 +2942,8 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) { } } -status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor) { +status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, + const sp<InputWindowHandle>& inputWindowHandle, bool monitor) { #if DEBUG_REGISTRATION LOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().string(), toString(monitor)); @@ -2875,7 +2958,7 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan return BAD_VALUE; } - sp<Connection> connection = new Connection(inputChannel); + sp<Connection> connection = new Connection(inputChannel, inputWindowHandle); status_t status = connection->initialize(); if (status) { LOGE("Failed to initialize input publisher for input channel '%s', status=%d", @@ -3002,9 +3085,10 @@ void InputDispatcher::onANRLocked( CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doNotifyANRLockedInterruptible); if (application) { - commandEntry->inputApplicationHandle = application->handle; + commandEntry->inputApplicationHandle = application->inputApplicationHandle; } if (window) { + commandEntry->inputWindowHandle = window->inputWindowHandle; commandEntry->inputChannel = window->inputChannel; } } @@ -3025,7 +3109,7 @@ void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible( if (connection->status != Connection::STATUS_ZOMBIE) { mLock.unlock(); - mPolicy->notifyInputChannelBroken(connection->inputChannel); + mPolicy->notifyInputChannelBroken(connection->inputWindowHandle); mLock.lock(); } @@ -3036,7 +3120,7 @@ void InputDispatcher::doNotifyANRLockedInterruptible( mLock.unlock(); nsecs_t newTimeout = mPolicy->notifyANR( - commandEntry->inputApplicationHandle, commandEntry->inputChannel); + commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle); mLock.lock(); @@ -3052,7 +3136,7 @@ void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( mLock.unlock(); - bool consumed = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputChannel, + bool consumed = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle, &event, entry->policyFlags); mLock.lock(); @@ -3095,7 +3179,7 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( mLock.unlock(); - bool fallback = mPolicy->dispatchUnhandledKey(connection->inputChannel, + bool fallback = mPolicy->dispatchUnhandledKey(connection->inputWindowHandle, &event, keyEntry->policyFlags, &event); mLock.lock(); @@ -3604,8 +3688,10 @@ bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& mement // --- InputDispatcher::Connection --- -InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel) : - status(STATUS_NORMAL), inputChannel(inputChannel), inputPublisher(inputChannel), +InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel, + const sp<InputWindowHandle>& inputWindowHandle) : + status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle), + inputPublisher(inputChannel), lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX) { } diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h index c8beab2aabae..11e511732061 100644 --- a/services/input/InputDispatcher.h +++ b/services/input/InputDispatcher.h @@ -33,6 +33,9 @@ #include <unistd.h> #include <limits.h> +#include "InputWindow.h" +#include "InputApplication.h" + namespace android { @@ -116,137 +119,6 @@ struct InputTarget { /* - * An input window describes the bounds of a window that can receive input. - */ -struct InputWindow { - // Window flags from WindowManager.LayoutParams - enum { - FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, - FLAG_DIM_BEHIND = 0x00000002, - FLAG_BLUR_BEHIND = 0x00000004, - FLAG_NOT_FOCUSABLE = 0x00000008, - FLAG_NOT_TOUCHABLE = 0x00000010, - FLAG_NOT_TOUCH_MODAL = 0x00000020, - FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040, - FLAG_KEEP_SCREEN_ON = 0x00000080, - FLAG_LAYOUT_IN_SCREEN = 0x00000100, - FLAG_LAYOUT_NO_LIMITS = 0x00000200, - FLAG_FULLSCREEN = 0x00000400, - FLAG_FORCE_NOT_FULLSCREEN = 0x00000800, - FLAG_DITHER = 0x00001000, - FLAG_SECURE = 0x00002000, - FLAG_SCALED = 0x00004000, - FLAG_IGNORE_CHEEK_PRESSES = 0x00008000, - FLAG_LAYOUT_INSET_DECOR = 0x00010000, - FLAG_ALT_FOCUSABLE_IM = 0x00020000, - FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000, - FLAG_SHOW_WHEN_LOCKED = 0x00080000, - FLAG_SHOW_WALLPAPER = 0x00100000, - FLAG_TURN_SCREEN_ON = 0x00200000, - FLAG_DISMISS_KEYGUARD = 0x00400000, - FLAG_SPLIT_TOUCH = 0x00800000, - FLAG_KEEP_SURFACE_WHILE_ANIMATING = 0x10000000, - FLAG_COMPATIBLE_WINDOW = 0x20000000, - FLAG_SYSTEM_ERROR = 0x40000000, - }; - - // Window types from WindowManager.LayoutParams - enum { - FIRST_APPLICATION_WINDOW = 1, - TYPE_BASE_APPLICATION = 1, - TYPE_APPLICATION = 2, - TYPE_APPLICATION_STARTING = 3, - LAST_APPLICATION_WINDOW = 99, - FIRST_SUB_WINDOW = 1000, - TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW, - TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1, - TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2, - TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3, - TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW+4, - LAST_SUB_WINDOW = 1999, - FIRST_SYSTEM_WINDOW = 2000, - TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW, - TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1, - TYPE_PHONE = FIRST_SYSTEM_WINDOW+2, - TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3, - TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4, - TYPE_TOAST = FIRST_SYSTEM_WINDOW+5, - TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6, - TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7, - TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8, - TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9, - TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10, - TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11, - TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12, - TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13, - TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+14, - TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15, - TYPE_DRAG = FIRST_SYSTEM_WINDOW+16, - TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+17, - LAST_SYSTEM_WINDOW = 2999, - }; - - sp<InputChannel> inputChannel; - String8 name; - int32_t layoutParamsFlags; - int32_t layoutParamsType; - nsecs_t dispatchingTimeout; - int32_t frameLeft; - int32_t frameTop; - int32_t frameRight; - int32_t frameBottom; - int32_t visibleFrameLeft; - int32_t visibleFrameTop; - int32_t visibleFrameRight; - int32_t visibleFrameBottom; - int32_t touchableAreaLeft; - int32_t touchableAreaTop; - int32_t touchableAreaRight; - int32_t touchableAreaBottom; - bool visible; - bool canReceiveKeys; - bool hasFocus; - bool hasWallpaper; - bool paused; - int32_t layer; - int32_t ownerPid; - int32_t ownerUid; - - bool touchableAreaContainsPoint(int32_t x, int32_t y) const; - bool frameContainsPoint(int32_t x, int32_t y) const; - - /* Returns true if the window is of a trusted type that is allowed to silently - * overlay other windows for the purpose of implementing the secure views feature. - * Trusted overlays, such as IME windows, can partly obscure other windows without causing - * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. - */ - bool isTrustedOverlay() const; - - bool supportsSplitTouch() const; -}; - - -/* - * A private handle type used by the input manager to track the window. - */ -class InputApplicationHandle : public RefBase { -protected: - InputApplicationHandle() { } - virtual ~InputApplicationHandle() { } -}; - - -/* - * An input application describes properties of an application that can receive input. - */ -struct InputApplication { - String8 name; - nsecs_t dispatchingTimeout; - sp<InputApplicationHandle> handle; -}; - - -/* * Input dispatcher policy interface. * * The input reader policy is used by the input reader to interact with the Window Manager @@ -267,10 +139,10 @@ public: /* Notifies the system that an application is not responding. * Returns a new timeout to continue waiting, or 0 to abort dispatch. */ virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, - const sp<InputChannel>& inputChannel) = 0; + const sp<InputWindowHandle>& inputWindowHandle) = 0; /* Notifies the system that an input channel is unrecoverably broken. */ - virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel) = 0; + virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) = 0; /* Gets the key repeat initial timeout or -1 if automatic key repeating is disabled. */ virtual nsecs_t getKeyRepeatTimeout() = 0; @@ -303,12 +175,12 @@ public: virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) = 0; /* Allows the policy a chance to intercept a key before dispatching. */ - virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel, + virtual bool interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags) = 0; /* Allows the policy a chance to perform default processing for an unhandled key. * Returns an alternate keycode to redispatch as a fallback, or 0 to give up. */ - virtual bool dispatchUnhandledKey(const sp<InputChannel>& inputChannel, + virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) = 0; /* Notifies the policy about switch events. @@ -407,7 +279,8 @@ public: * * These methods may be called on any thread (usually by the input manager). */ - virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor) = 0; + virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, + const sp<InputWindowHandle>& inputWindowHandle, bool monitor) = 0; virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0; }; @@ -461,7 +334,8 @@ public: virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel, const sp<InputChannel>& toChannel); - virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor); + virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, + const sp<InputWindowHandle>& inputWindowHandle, bool monitor); virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel); private: @@ -615,6 +489,7 @@ private: KeyEntry* keyEntry; sp<InputChannel> inputChannel; sp<InputApplicationHandle> inputApplicationHandle; + sp<InputWindowHandle> inputWindowHandle; int32_t userActivityEventType; bool handled; }; @@ -815,7 +690,8 @@ private: }; Status status; - sp<InputChannel> inputChannel; + sp<InputChannel> inputChannel; // never null + sp<InputWindowHandle> inputWindowHandle; // may be null InputPublisher inputPublisher; InputState inputState; Queue<DispatchEntry> outboundQueue; @@ -823,7 +699,8 @@ private: nsecs_t lastEventTime; // the time when the event was originally captured nsecs_t lastDispatchTime; // the time when the last event was dispatched - explicit Connection(const sp<InputChannel>& inputChannel); + explicit Connection(const sp<InputChannel>& inputChannel, + const sp<InputWindowHandle>& inputWindowHandle); inline const char* getInputChannelName() const { return inputChannel->getName().string(); } @@ -851,6 +728,8 @@ private: DROP_REASON_POLICY = 1, DROP_REASON_APP_SWITCH = 2, DROP_REASON_DISABLED = 3, + DROP_REASON_BLOCKED = 4, + DROP_REASON_STALE = 5, }; sp<InputDispatcherPolicyInterface> mPolicy; @@ -884,6 +763,15 @@ private: bool isAppSwitchPendingLocked(); void resetPendingAppSwitchLocked(bool handled); + // Stale event latency optimization. + static bool isStaleEventLocked(nsecs_t currentTime, EventEntry* entry); + + // Blocked event latency optimization. Drops old events when the user intends + // to transfer focus to a new application. + EventEntry* mNextUnblockedEvent; + + const InputWindow* findTouchedWindowAtLocked(int32_t x, int32_t y); + // All registered connections mapped by receive pipe file descriptor. KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd; @@ -1006,6 +894,7 @@ private: nsecs_t mInputTargetWaitStartTime; nsecs_t mInputTargetWaitTimeoutTime; bool mInputTargetWaitTimeoutExpired; + sp<InputApplicationHandle> mInputTargetWaitApplication; // Finding targets for input events. void resetTargetsLocked(); diff --git a/services/input/InputWindow.cpp b/services/input/InputWindow.cpp new file mode 100644 index 000000000000..9ce45f50513c --- /dev/null +++ b/services/input/InputWindow.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011 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. + */ + +#define LOG_TAG "InputWindow" + +#include "InputWindow.h" + +#include <cutils/log.h> + +namespace android { + +// --- InputWindow --- + +bool InputWindow::touchableAreaContainsPoint(int32_t x, int32_t y) const { + return x >= touchableAreaLeft && x <= touchableAreaRight + && y >= touchableAreaTop && y <= touchableAreaBottom; +} + +bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const { + return x >= frameLeft && x <= frameRight + && y >= frameTop && y <= frameBottom; +} + +bool InputWindow::isTrustedOverlay() const { + return layoutParamsType == TYPE_INPUT_METHOD + || layoutParamsType == TYPE_INPUT_METHOD_DIALOG + || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY; +} + +bool InputWindow::supportsSplitTouch() const { + return layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH; +} + +} // namespace android diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h new file mode 100644 index 000000000000..b3d5a651ba75 --- /dev/null +++ b/services/input/InputWindow.h @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef _UI_INPUT_WINDOW_H +#define _UI_INPUT_WINDOW_H + +#include <ui/Input.h> +#include <ui/InputTransport.h> +#include <utils/RefBase.h> +#include <utils/Timers.h> +#include <utils/String8.h> + +#include "InputApplication.h" + +namespace android { + +/* + * A handle to a window that can receive input. + * Used by the native input dispatcher to indirectly refer to the window manager objects + * that describe a window. + */ +class InputWindowHandle : public RefBase { +protected: + InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) : + mInputApplicationHandle(inputApplicationHandle) { } + virtual ~InputWindowHandle() { } + +public: + inline sp<InputApplicationHandle> getInputApplicationHandle() { + return mInputApplicationHandle; + } + +private: + sp<InputApplicationHandle> mInputApplicationHandle; +}; + + +/* + * An input window describes the bounds of a window that can receive input. + */ +struct InputWindow { + // Window flags from WindowManager.LayoutParams + enum { + FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, + FLAG_DIM_BEHIND = 0x00000002, + FLAG_BLUR_BEHIND = 0x00000004, + FLAG_NOT_FOCUSABLE = 0x00000008, + FLAG_NOT_TOUCHABLE = 0x00000010, + FLAG_NOT_TOUCH_MODAL = 0x00000020, + FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040, + FLAG_KEEP_SCREEN_ON = 0x00000080, + FLAG_LAYOUT_IN_SCREEN = 0x00000100, + FLAG_LAYOUT_NO_LIMITS = 0x00000200, + FLAG_FULLSCREEN = 0x00000400, + FLAG_FORCE_NOT_FULLSCREEN = 0x00000800, + FLAG_DITHER = 0x00001000, + FLAG_SECURE = 0x00002000, + FLAG_SCALED = 0x00004000, + FLAG_IGNORE_CHEEK_PRESSES = 0x00008000, + FLAG_LAYOUT_INSET_DECOR = 0x00010000, + FLAG_ALT_FOCUSABLE_IM = 0x00020000, + FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000, + FLAG_SHOW_WHEN_LOCKED = 0x00080000, + FLAG_SHOW_WALLPAPER = 0x00100000, + FLAG_TURN_SCREEN_ON = 0x00200000, + FLAG_DISMISS_KEYGUARD = 0x00400000, + FLAG_SPLIT_TOUCH = 0x00800000, + FLAG_KEEP_SURFACE_WHILE_ANIMATING = 0x10000000, + FLAG_COMPATIBLE_WINDOW = 0x20000000, + FLAG_SYSTEM_ERROR = 0x40000000, + }; + + // Window types from WindowManager.LayoutParams + enum { + FIRST_APPLICATION_WINDOW = 1, + TYPE_BASE_APPLICATION = 1, + TYPE_APPLICATION = 2, + TYPE_APPLICATION_STARTING = 3, + LAST_APPLICATION_WINDOW = 99, + FIRST_SUB_WINDOW = 1000, + TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW, + TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1, + TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2, + TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3, + TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW+4, + LAST_SUB_WINDOW = 1999, + FIRST_SYSTEM_WINDOW = 2000, + TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW, + TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1, + TYPE_PHONE = FIRST_SYSTEM_WINDOW+2, + TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3, + TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4, + TYPE_TOAST = FIRST_SYSTEM_WINDOW+5, + TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6, + TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7, + TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8, + TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9, + TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10, + TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11, + TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12, + TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13, + TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+14, + TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15, + TYPE_DRAG = FIRST_SYSTEM_WINDOW+16, + TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+17, + LAST_SYSTEM_WINDOW = 2999, + }; + + sp<InputWindowHandle> inputWindowHandle; + sp<InputChannel> inputChannel; + String8 name; + int32_t layoutParamsFlags; + int32_t layoutParamsType; + nsecs_t dispatchingTimeout; + int32_t frameLeft; + int32_t frameTop; + int32_t frameRight; + int32_t frameBottom; + int32_t visibleFrameLeft; + int32_t visibleFrameTop; + int32_t visibleFrameRight; + int32_t visibleFrameBottom; + int32_t touchableAreaLeft; + int32_t touchableAreaTop; + int32_t touchableAreaRight; + int32_t touchableAreaBottom; + bool visible; + bool canReceiveKeys; + bool hasFocus; + bool hasWallpaper; + bool paused; + int32_t layer; + int32_t ownerPid; + int32_t ownerUid; + + bool touchableAreaContainsPoint(int32_t x, int32_t y) const; + bool frameContainsPoint(int32_t x, int32_t y) const; + + /* Returns true if the window is of a trusted type that is allowed to silently + * overlay other windows for the purpose of implementing the secure views feature. + * Trusted overlays, such as IME windows, can partly obscure other windows without causing + * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. + */ + bool isTrustedOverlay() const; + + bool supportsSplitTouch() const; +}; + +} // namespace android + +#endif // _UI_INPUT_WINDOW_H diff --git a/services/input/tests/InputDispatcher_test.cpp b/services/input/tests/InputDispatcher_test.cpp index b79633ad5afe..5ba18671441e 100644 --- a/services/input/tests/InputDispatcher_test.cpp +++ b/services/input/tests/InputDispatcher_test.cpp @@ -36,11 +36,11 @@ private: } virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, - const sp<InputChannel>& inputChannel) { + const sp<InputWindowHandle>& inputWindowHandle) { return 0; } - virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel) { + virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) { } virtual nsecs_t getKeyRepeatTimeout() { @@ -61,12 +61,12 @@ private: virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) { } - virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel, + virtual bool interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags) { return false; } - virtual bool dispatchUnhandledKey(const sp<InputChannel>& inputChannel, + virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) { return false; } diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index 9d2c52f07809..8ec6f534274d 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -368,7 +368,8 @@ private: return 0; } - virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor) { + virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, + const sp<InputWindowHandle>& inputWindowHandle, bool monitor) { ADD_FAILURE() << "Should never be called by input reader."; return 0; } diff --git a/services/java/com/android/server/InputApplication.java b/services/java/com/android/server/InputApplication.java index 38420d4f899f..ae0948441757 100644 --- a/services/java/com/android/server/InputApplication.java +++ b/services/java/com/android/server/InputApplication.java @@ -18,16 +18,19 @@ package com.android.server; /** * Describes input-related application properties for use by the input dispatcher. - * * @hide */ public final class InputApplication { + // Application handle. + public InputApplicationHandle inputApplicationHandle; + // Application name. public String name; - + // Dispatching timeout. public long dispatchingTimeoutNanos; - - // The application window token. - public Object token; + + public void recycle() { + inputApplicationHandle = null; + } } diff --git a/services/java/com/android/server/InputApplicationHandle.java b/services/java/com/android/server/InputApplicationHandle.java new file mode 100644 index 000000000000..d396d11caa41 --- /dev/null +++ b/services/java/com/android/server/InputApplicationHandle.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011 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.server; + +/** + * Functions as a handle for an application that can receive input. + * Enables the native input dispatcher to refer indirectly to the window manager's + * application window token. + * @hide + */ +public final class InputApplicationHandle { + // Pointer to the native input application handle. + // This field is lazily initialized via JNI. + @SuppressWarnings("unused") + private int ptr; + + // The window manager's application window token. + public final WindowManagerService.AppWindowToken appWindowToken; + + private native void nativeDispose(); + + public InputApplicationHandle(WindowManagerService.AppWindowToken appWindowToken) { + this.appWindowToken = appWindowToken; + } + + @Override + protected void finalize() throws Throwable { + nativeDispose(); + super.finalize(); + } +} diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java index 410b8c259b00..5c2048bd81f4 100644 --- a/services/java/com/android/server/InputManager.java +++ b/services/java/com/android/server/InputManager.java @@ -77,7 +77,7 @@ public class InputManager { private static native boolean nativeHasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists); private static native void nativeRegisterInputChannel(InputChannel inputChannel, - boolean monitor); + InputWindowHandle inputWindowHandle, boolean monitor); private static native void nativeUnregisterInputChannel(InputChannel inputChannel); private static native int nativeInjectInputEvent(InputEvent event, int injectorPid, int injectorUid, int syncMode, int timeoutMillis); @@ -240,7 +240,7 @@ public class InputManager { } InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName); - nativeRegisterInputChannel(inputChannels[0], true); + nativeRegisterInputChannel(inputChannels[0], null, true); inputChannels[0].dispose(); // don't need to retain the Java object reference return inputChannels[1]; } @@ -248,13 +248,16 @@ public class InputManager { /** * Registers an input channel so that it can be used as an input event target. * @param inputChannel The input channel to register. + * @param inputWindowHandle The handle of the input window associated with the + * input channel, or null if none. */ - public void registerInputChannel(InputChannel inputChannel) { + public void registerInputChannel(InputChannel inputChannel, + InputWindowHandle inputWindowHandle) { if (inputChannel == null) { throw new IllegalArgumentException("inputChannel must not be null."); } - nativeRegisterInputChannel(inputChannel, false); + nativeRegisterInputChannel(inputChannel, inputWindowHandle, false); } /** @@ -429,13 +432,15 @@ public class InputManager { } @SuppressWarnings("unused") - public void notifyInputChannelBroken(InputChannel inputChannel) { - mWindowManagerService.mInputMonitor.notifyInputChannelBroken(inputChannel); + public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) { + mWindowManagerService.mInputMonitor.notifyInputChannelBroken(inputWindowHandle); } @SuppressWarnings("unused") - public long notifyANR(Object token, InputChannel inputChannel) { - return mWindowManagerService.mInputMonitor.notifyANR(token, inputChannel); + public long notifyANR(InputApplicationHandle inputApplicationHandle, + InputWindowHandle inputWindowHandle) { + return mWindowManagerService.mInputMonitor.notifyANR( + inputApplicationHandle, inputWindowHandle); } @SuppressWarnings("unused") @@ -445,14 +450,14 @@ public class InputManager { } @SuppressWarnings("unused") - public boolean interceptKeyBeforeDispatching(InputChannel focus, + public boolean interceptKeyBeforeDispatching(InputWindowHandle focus, KeyEvent event, int policyFlags) { return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching( focus, event, policyFlags); } @SuppressWarnings("unused") - public KeyEvent dispatchUnhandledKey(InputChannel focus, + public KeyEvent dispatchUnhandledKey(InputWindowHandle focus, KeyEvent event, int policyFlags) { return mWindowManagerService.mInputMonitor.dispatchUnhandledKey( focus, event, policyFlags); diff --git a/services/java/com/android/server/InputWindow.java b/services/java/com/android/server/InputWindow.java index befc770b4136..1515290145d8 100644 --- a/services/java/com/android/server/InputWindow.java +++ b/services/java/com/android/server/InputWindow.java @@ -20,64 +20,67 @@ import android.view.InputChannel; /** * Describes input-related window properties for use by the input dispatcher. - * * @hide */ public final class InputWindow { + // The window handle. + public InputWindowHandle inputWindowHandle; + // The input channel associated with the window. public InputChannel inputChannel; - + // The window name. public String name; - + // Window layout params attributes. (WindowManager.LayoutParams) public int layoutParamsFlags; public int layoutParamsType; - + // Dispatching timeout. public long dispatchingTimeoutNanos; - + // Window frame area. public int frameLeft; public int frameTop; public int frameRight; public int frameBottom; - + // Window visible frame area. public int visibleFrameLeft; public int visibleFrameTop; public int visibleFrameRight; public int visibleFrameBottom; - + // Window touchable area. public int touchableAreaLeft; public int touchableAreaTop; public int touchableAreaRight; public int touchableAreaBottom; - + // Window is visible. public boolean visible; - + // Window can receive keys. public boolean canReceiveKeys; - + // Window has focus. public boolean hasFocus; - + // Window has wallpaper. (window is the current wallpaper target) public boolean hasWallpaper; - + // Input event dispatching is paused. public boolean paused; - + // Window layer. public int layer; - + // Id of process and user that owns the window. public int ownerPid; public int ownerUid; - + public void recycle() { + inputWindowHandle = null; inputChannel = null; } } diff --git a/services/java/com/android/server/InputWindowHandle.java b/services/java/com/android/server/InputWindowHandle.java new file mode 100644 index 000000000000..4b9293918031 --- /dev/null +++ b/services/java/com/android/server/InputWindowHandle.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2011 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.server; + +import android.view.WindowManagerPolicy; + +/** + * Functions as a handle for a window that can receive input. + * Enables the native input dispatcher to refer indirectly to the window manager's window state. + * @hide + */ +public final class InputWindowHandle { + // Pointer to the native input window handle. + // This field is lazily initialized via JNI. + @SuppressWarnings("unused") + private int ptr; + + // The input application handle. + public final InputApplicationHandle inputApplicationHandle; + + // The window manager's window state. + public final WindowManagerPolicy.WindowState windowState; + + private native void nativeDispose(); + + public InputWindowHandle(InputApplicationHandle inputApplicationHandle, + WindowManagerPolicy.WindowState windowState) { + this.inputApplicationHandle = inputApplicationHandle; + this.windowState = windowState; + } + + @Override + protected void finalize() throws Throwable { + nativeDispose(); + super.finalize(); + } +} diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index c33d19d706a7..5c823bae8aa4 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -536,7 +536,7 @@ public class WindowManagerService extends IWindowManager.Stub InputChannel[] channels = InputChannel.openInputChannelPair("drag"); mServerChannel = channels[0]; mClientChannel = channels[1]; - mInputManager.registerInputChannel(mServerChannel); + mInputManager.registerInputChannel(mServerChannel, null); InputQueue.registerInputChannel(mClientChannel, mDragInputHandler, mH.getLooper().getQueue()); } @@ -2311,7 +2311,7 @@ public class WindowManagerService extends IWindowManager.Stub win.mInputChannel = inputChannels[0]; inputChannels[1].transferToBinderOutParameter(outInputChannel); - mInputManager.registerInputChannel(win.mInputChannel); + mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle); } // From now on, no exceptions or errors allowed! @@ -5711,13 +5711,13 @@ public class WindowManagerService extends IWindowManager.Stub * * Called by the InputManager. */ - public void notifyInputChannelBroken(InputChannel inputChannel) { + public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) { + if (inputWindowHandle == null) { + return; + } + synchronized (mWindowMap) { - WindowState windowState = getWindowStateForInputChannelLocked(inputChannel); - if (windowState == null) { - return; // irrelevant - } - + WindowState windowState = (WindowState) inputWindowHandle.windowState; Slog.i(TAG, "WINDOW DIED " + windowState); removeWindowLocked(windowState.mSession, windowState); } @@ -5728,11 +5728,12 @@ public class WindowManagerService extends IWindowManager.Stub * * Called by the InputManager. */ - public long notifyANR(Object token, InputChannel inputChannel) { + public long notifyANR(InputApplicationHandle inputApplicationHandle, + InputWindowHandle inputWindowHandle) { AppWindowToken appWindowToken = null; - if (inputChannel != null) { + if (inputWindowHandle != null) { synchronized (mWindowMap) { - WindowState windowState = getWindowStateForInputChannelLocked(inputChannel); + WindowState windowState = (WindowState) inputWindowHandle.windowState; if (windowState != null) { Slog.i(TAG, "Input event dispatching timed out sending to " + windowState.mAttrs.getTitle()); @@ -5741,8 +5742,8 @@ public class WindowManagerService extends IWindowManager.Stub } } - if (appWindowToken == null && token != null) { - appWindowToken = (AppWindowToken) token; + if (appWindowToken == null && inputApplicationHandle != null) { + appWindowToken = inputApplicationHandle.appWindowToken; Slog.i(TAG, "Input event dispatching timed out sending to application " + appWindowToken.stringName); } @@ -5762,24 +5763,6 @@ public class WindowManagerService extends IWindowManager.Stub } return 0; // abort dispatching } - - private WindowState getWindowStateForInputChannel(InputChannel inputChannel) { - synchronized (mWindowMap) { - return getWindowStateForInputChannelLocked(inputChannel); - } - } - - private WindowState getWindowStateForInputChannelLocked(InputChannel inputChannel) { - int windowCount = mWindows.size(); - for (int i = 0; i < windowCount; i++) { - WindowState windowState = mWindows.get(i); - if (windowState.mInputChannel == inputChannel) { - return windowState; - } - } - - return null; - } private void addDragInputWindowLw(InputWindowList windowList) { final InputWindow inputWindow = windowList.add(); @@ -5856,6 +5839,7 @@ public class WindowManagerService extends IWindowManager.Stub // Add a window to our list of input windows. final InputWindow inputWindow = mTempInputWindows.add(); + inputWindow.inputWindowHandle = child.mInputWindowHandle; inputWindow.inputChannel = child.mInputChannel; inputWindow.name = child.toString(); inputWindow.layoutParamsFlags = flags; @@ -5934,16 +5918,16 @@ public class WindowManagerService extends IWindowManager.Stub /* Provides an opportunity for the window manager policy to process a key before * ordinary dispatch. */ public boolean interceptKeyBeforeDispatching( - InputChannel focus, KeyEvent event, int policyFlags) { - WindowState windowState = getWindowStateForInputChannel(focus); + InputWindowHandle focus, KeyEvent event, int policyFlags) { + WindowState windowState = (WindowState) focus.windowState; return mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags); } /* Provides an opportunity for the window manager policy to process a key that * the application did not handle. */ public KeyEvent dispatchUnhandledKey( - InputChannel focus, KeyEvent event, int policyFlags) { - WindowState windowState = getWindowStateForInputChannel(focus); + InputWindowHandle focus, KeyEvent event, int policyFlags) { + WindowState windowState = (WindowState) focus.windowState; return mPolicy.dispatchUnhandledKey(windowState, event, policyFlags); } @@ -5973,12 +5957,14 @@ public class WindowManagerService extends IWindowManager.Stub if (newApp == null) { mInputManager.setFocusedApplication(null); } else { + mTempInputApplication.inputApplicationHandle = newApp.mInputApplicationHandle; mTempInputApplication.name = newApp.toString(); mTempInputApplication.dispatchingTimeoutNanos = newApp.inputDispatchingTimeoutNanos; - mTempInputApplication.token = newApp; - + mInputManager.setFocusedApplication(mTempInputApplication); + + mTempInputApplication.recycle(); } } @@ -6823,7 +6809,8 @@ public class WindowManagerService extends IWindowManager.Stub int mSurfaceLayer; float mSurfaceAlpha; - // Input channel + // Input channel and input window handle used by the input dispatcher. + InputWindowHandle mInputWindowHandle; InputChannel mInputChannel; // Used to improve performance of toString() @@ -6915,6 +6902,8 @@ public class WindowManagerService extends IWindowManager.Stub mLayer = 0; mAnimLayer = 0; mLastLayer = 0; + mInputWindowHandle = new InputWindowHandle( + mAppToken != null ? mAppToken.mInputApplicationHandle : null, this); } void attach() { @@ -8304,11 +8293,15 @@ public class WindowManagerService extends IWindowManager.Stub boolean startingMoved; boolean firstWindowDrawn; + // Input application handle used by the input dispatcher. + InputApplicationHandle mInputApplicationHandle; + AppWindowToken(IApplicationToken _token) { super(_token.asBinder(), WindowManager.LayoutParams.TYPE_APPLICATION, true); appWindowToken = this; appToken = _token; + mInputApplicationHandle = new InputApplicationHandle(this); } public void setAnimation(Animation anim) { diff --git a/services/jni/Android.mk b/services/jni/Android.mk index ec85e54b52c2..f5a5b4da5e80 100644 --- a/services/jni/Android.mk +++ b/services/jni/Android.mk @@ -4,7 +4,11 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ com_android_server_AlarmManagerService.cpp \ com_android_server_BatteryService.cpp \ + com_android_server_InputApplication.cpp \ + com_android_server_InputApplicationHandle.cpp \ com_android_server_InputManager.cpp \ + com_android_server_InputWindow.cpp \ + com_android_server_InputWindowHandle.cpp \ com_android_server_LightsService.cpp \ com_android_server_PowerManagerService.cpp \ com_android_server_SystemServer.cpp \ diff --git a/services/jni/com_android_server_InputApplication.cpp b/services/jni/com_android_server_InputApplication.cpp new file mode 100644 index 000000000000..a46a162071e8 --- /dev/null +++ b/services/jni/com_android_server_InputApplication.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2011 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. + */ + +#define LOG_TAG "InputApplication" + +#include "JNIHelp.h" +#include "jni.h" +#include <android_runtime/AndroidRuntime.h> + +#include "com_android_server_InputApplication.h" +#include "com_android_server_InputApplicationHandle.h" + +namespace android { + +static struct { + jclass clazz; + + jfieldID inputApplicationHandle; + jfieldID name; + jfieldID dispatchingTimeoutNanos; +} gInputApplicationClassInfo; + + +// --- Global functions --- + +void android_server_InputApplication_toNative( + JNIEnv* env, jobject inputApplicationObj, InputApplication* outInputApplication) { + jobject inputApplicationHandleObj = env->GetObjectField(inputApplicationObj, + gInputApplicationClassInfo.inputApplicationHandle); + if (inputApplicationHandleObj) { + outInputApplication->inputApplicationHandle = + android_server_InputApplicationHandle_getHandle(env, inputApplicationHandleObj); + env->DeleteLocalRef(inputApplicationHandleObj); + } else { + outInputApplication->inputApplicationHandle = NULL; + } + + jstring nameObj = jstring(env->GetObjectField(inputApplicationObj, + gInputApplicationClassInfo.name)); + if (nameObj) { + const char* nameStr = env->GetStringUTFChars(nameObj, NULL); + outInputApplication->name.setTo(nameStr); + env->ReleaseStringUTFChars(nameObj, nameStr); + env->DeleteLocalRef(nameObj); + } else { + LOGE("InputApplication.name should not be null."); + outInputApplication->name.setTo("unknown"); + } + + outInputApplication->dispatchingTimeout = env->GetLongField(inputApplicationObj, + gInputApplicationClassInfo.dispatchingTimeoutNanos); +} + + +// --- JNI --- + +#define FIND_CLASS(var, className) \ + var = env->FindClass(className); \ + LOG_FATAL_IF(! var, "Unable to find class " className); \ + var = jclass(env->NewGlobalRef(var)); + +#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ + var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find field " fieldName); + +int register_android_server_InputApplication(JNIEnv* env) { + FIND_CLASS(gInputApplicationClassInfo.clazz, "com/android/server/InputApplication"); + + GET_FIELD_ID(gInputApplicationClassInfo.inputApplicationHandle, + gInputApplicationClassInfo.clazz, + "inputApplicationHandle", "Lcom/android/server/InputApplicationHandle;"); + + GET_FIELD_ID(gInputApplicationClassInfo.name, gInputApplicationClassInfo.clazz, + "name", "Ljava/lang/String;"); + + GET_FIELD_ID(gInputApplicationClassInfo.dispatchingTimeoutNanos, + gInputApplicationClassInfo.clazz, + "dispatchingTimeoutNanos", "J"); + return 0; +} + +} /* namespace android */ diff --git a/services/jni/com_android_server_InputApplication.h b/services/jni/com_android_server_InputApplication.h new file mode 100644 index 000000000000..85fb891cfd2b --- /dev/null +++ b/services/jni/com_android_server_InputApplication.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef _ANDROID_SERVER_INPUT_APPLICATION_H +#define _ANDROID_SERVER_INPUT_APPLICATION_H + +#include <input/InputApplication.h> + +#include "JNIHelp.h" +#include "jni.h" + +namespace android { + +extern void android_server_InputApplication_toNative( + JNIEnv* env, jobject inputApplicationObj, InputApplication* outInputApplication); + +} // namespace android + +#endif // _ANDROID_SERVER_INPUT_APPLICATION_H diff --git a/services/jni/com_android_server_InputApplicationHandle.cpp b/services/jni/com_android_server_InputApplicationHandle.cpp new file mode 100644 index 000000000000..ab82635595d8 --- /dev/null +++ b/services/jni/com_android_server_InputApplicationHandle.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2011 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. + */ + +#define LOG_TAG "InputApplicationHandle" + +#include "JNIHelp.h" +#include "jni.h" +#include <android_runtime/AndroidRuntime.h> +#include <utils/threads.h> + +#include "com_android_server_InputApplicationHandle.h" + +namespace android { + +static struct { + jclass clazz; + + jfieldID ptr; +} gInputApplicationHandleClassInfo; + +static Mutex gHandleMutex; + + +// --- NativeInputApplicationHandle --- + +NativeInputApplicationHandle::NativeInputApplicationHandle(jweak objWeak) : + mObjWeak(objWeak) { +} + +NativeInputApplicationHandle::~NativeInputApplicationHandle() { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->DeleteWeakGlobalRef(mObjWeak); +} + +jobject NativeInputApplicationHandle::getInputApplicationHandleObjLocalRef(JNIEnv* env) { + return env->NewLocalRef(mObjWeak); +} + + +// --- Global functions --- + +sp<InputApplicationHandle> android_server_InputApplicationHandle_getHandle( + JNIEnv* env, jobject inputApplicationHandleObj) { + if (!inputApplicationHandleObj) { + return NULL; + } + + AutoMutex _l(gHandleMutex); + + int ptr = env->GetIntField(inputApplicationHandleObj, gInputApplicationHandleClassInfo.ptr); + NativeInputApplicationHandle* handle; + if (ptr) { + handle = reinterpret_cast<NativeInputApplicationHandle*>(ptr); + } else { + jweak objWeak = env->NewWeakGlobalRef(inputApplicationHandleObj); + handle = new NativeInputApplicationHandle(objWeak); + handle->incStrong(inputApplicationHandleObj); + env->SetIntField(inputApplicationHandleObj, gInputApplicationHandleClassInfo.ptr, + reinterpret_cast<int>(handle)); + } + return handle; +} + + +// --- JNI --- + +static void android_server_InputApplicationHandle_nativeDispose(JNIEnv* env, jobject obj) { + AutoMutex _l(gHandleMutex); + + int ptr = env->GetIntField(obj, gInputApplicationHandleClassInfo.ptr); + if (ptr) { + env->SetIntField(obj, gInputApplicationHandleClassInfo.ptr, 0); + + NativeInputApplicationHandle* handle = reinterpret_cast<NativeInputApplicationHandle*>(ptr); + handle->decStrong(obj); + } +} + + +static JNINativeMethod gInputApplicationHandleMethods[] = { + /* name, signature, funcPtr */ + { "nativeDispose", "()V", + (void*) android_server_InputApplicationHandle_nativeDispose }, +}; + +#define FIND_CLASS(var, className) \ + var = env->FindClass(className); \ + LOG_FATAL_IF(! var, "Unable to find class " className); \ + var = jclass(env->NewGlobalRef(var)); + +#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ + var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find field " fieldName); + +int register_android_server_InputApplicationHandle(JNIEnv* env) { + int res = jniRegisterNativeMethods(env, "com/android/server/InputApplicationHandle", + gInputApplicationHandleMethods, NELEM(gInputApplicationHandleMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + FIND_CLASS(gInputApplicationHandleClassInfo.clazz, "com/android/server/InputApplicationHandle"); + + GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, gInputApplicationHandleClassInfo.clazz, + "ptr", "I"); + + return 0; +} + +} /* namespace android */ diff --git a/services/jni/com_android_server_InputApplicationHandle.h b/services/jni/com_android_server_InputApplicationHandle.h new file mode 100644 index 000000000000..9d187219b2ec --- /dev/null +++ b/services/jni/com_android_server_InputApplicationHandle.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef _ANDROID_SERVER_INPUT_APPLICATION_HANDLE_H +#define _ANDROID_SERVER_INPUT_APPLICATION_HANDLE_H + +#include <input/InputApplication.h> + +#include "JNIHelp.h" +#include "jni.h" + +namespace android { + +class NativeInputApplicationHandle : public InputApplicationHandle { +public: + NativeInputApplicationHandle(jweak objWeak); + virtual ~NativeInputApplicationHandle(); + + jobject getInputApplicationHandleObjLocalRef(JNIEnv* env); + +private: + jweak mObjWeak; +}; + + +extern sp<InputApplicationHandle> android_server_InputApplicationHandle_getHandle( + JNIEnv* env, jobject inputApplicationHandleObj); + +} // namespace android + +#endif // _ANDROID_SERVER_INPUT_APPLICATION_HANDLE_H diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index 5ed63f0b14dc..e04e4c3324f3 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -42,11 +42,13 @@ #include <android/graphics/GraphicsJNI.h> #include "com_android_server_PowerManagerService.h" +#include "com_android_server_InputApplication.h" +#include "com_android_server_InputApplicationHandle.h" +#include "com_android_server_InputWindow.h" +#include "com_android_server_InputWindowHandle.h" namespace android { -// ---------------------------------------------------------------------------- - static struct { jclass clazz; @@ -68,44 +70,6 @@ static struct { static struct { jclass clazz; - - jfieldID inputChannel; - jfieldID name; - jfieldID layoutParamsFlags; - jfieldID layoutParamsType; - jfieldID dispatchingTimeoutNanos; - jfieldID frameLeft; - jfieldID frameTop; - jfieldID frameRight; - jfieldID frameBottom; - jfieldID visibleFrameLeft; - jfieldID visibleFrameTop; - jfieldID visibleFrameRight; - jfieldID visibleFrameBottom; - jfieldID touchableAreaLeft; - jfieldID touchableAreaTop; - jfieldID touchableAreaRight; - jfieldID touchableAreaBottom; - jfieldID visible; - jfieldID canReceiveKeys; - jfieldID hasFocus; - jfieldID hasWallpaper; - jfieldID paused; - jfieldID layer; - jfieldID ownerPid; - jfieldID ownerUid; -} gInputWindowClassInfo; - -static struct { - jclass clazz; - - jfieldID name; - jfieldID dispatchingTimeoutNanos; - jfieldID token; -} gInputApplicationClassInfo; - -static struct { - jclass clazz; } gKeyEventClassInfo; static struct { @@ -141,7 +105,29 @@ static struct { jfieldID hotSpotY; } gPointerIconClassInfo; -// ---------------------------------------------------------------------------- + +// --- Global functions --- + +static jobject getInputApplicationHandleObjLocalRef(JNIEnv* env, + const sp<InputApplicationHandle>& inputApplicationHandle) { + if (inputApplicationHandle == NULL) { + return NULL; + } + return static_cast<NativeInputApplicationHandle*>(inputApplicationHandle.get())-> + getInputApplicationHandleObjLocalRef(env); +} + +static jobject getInputWindowHandleObjLocalRef(JNIEnv* env, + const sp<InputWindowHandle>& inputWindowHandle) { + if (inputWindowHandle == NULL) { + return NULL; + } + return static_cast<NativeInputWindowHandle*>(inputWindowHandle.get())-> + getInputWindowHandleObjLocalRef(env); +} + + +// --- NativeInputManager --- class NativeInputManager : public virtual RefBase, public virtual InputReaderPolicyInterface, @@ -160,7 +146,7 @@ public: void setDisplayOrientation(int32_t displayId, int32_t orientation); status_t registerInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel, - jweak inputChannelObjWeak, bool monitor); + const sp<InputWindowHandle>& inputWindowHandle, bool monitor); status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel); void setInputWindows(JNIEnv* env, jobjectArray windowObjArray); @@ -182,37 +168,22 @@ public: uint32_t policyFlags); virtual void notifyConfigurationChanged(nsecs_t when); virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, - const sp<InputChannel>& inputChannel); - virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel); + const sp<InputWindowHandle>& inputWindowHandle); + virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle); virtual nsecs_t getKeyRepeatTimeout(); virtual nsecs_t getKeyRepeatDelay(); virtual int32_t getMaxEventsPerSecond(); virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags); virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags); - virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel, + virtual bool interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags); - virtual bool dispatchUnhandledKey(const sp<InputChannel>& inputChannel, + virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent); virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType); virtual bool checkInjectEventsPermissionNonReentrant( int32_t injectorPid, int32_t injectorUid); private: - class ApplicationToken : public InputApplicationHandle { - jweak mTokenObjWeak; - - public: - ApplicationToken(jweak tokenObjWeak) : - mTokenObjWeak(tokenObjWeak) { } - - virtual ~ApplicationToken() { - JNIEnv* env = NativeInputManager::jniEnv(); - env->DeleteWeakGlobalRef(mTokenObjWeak); - } - - inline jweak getTokenObj() { return mTokenObjWeak; } - }; - sp<InputManager> mInputManager; jobject mCallbacksObj; @@ -232,19 +203,12 @@ private: // Pointer controller singleton, created and destroyed as needed. wp<PointerController> pointerController; - - // Weak references to all currently registered input channels by connection pointer. - KeyedVector<InputChannel*, jweak> inputChannelObjWeakTable; } mLocked; // Power manager interactions. bool isScreenOn(); bool isScreenBright(); - jobject getInputChannelObjLocal(JNIEnv* env, const sp<InputChannel>& inputChannel); - - static bool populateWindow(JNIEnv* env, jobject windowObj, InputWindow& outWindow); - static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName); static inline JNIEnv* jniEnv() { @@ -252,7 +216,7 @@ private: } }; -// ---------------------------------------------------------------------------- + NativeInputManager::NativeInputManager(jobject callbacksObj) : mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1), @@ -328,88 +292,17 @@ void NativeInputManager::setDisplayOrientation(int32_t displayId, int32_t orient } status_t NativeInputManager::registerInputChannel(JNIEnv* env, - const sp<InputChannel>& inputChannel, jobject inputChannelObj, bool monitor) { - jweak inputChannelObjWeak = env->NewWeakGlobalRef(inputChannelObj); - if (! inputChannelObjWeak) { - LOGE("Could not create weak reference for input channel."); - LOGE_EX(env); - return NO_MEMORY; - } - - status_t status; - { - AutoMutex _l(mLock); - - ssize_t index = mLocked.inputChannelObjWeakTable.indexOfKey(inputChannel.get()); - if (index >= 0) { - LOGE("Input channel object '%s' has already been registered", - inputChannel->getName().string()); - status = INVALID_OPERATION; - goto DeleteWeakRef; - } - - mLocked.inputChannelObjWeakTable.add(inputChannel.get(), inputChannelObjWeak); - } - - status = mInputManager->getDispatcher()->registerInputChannel(inputChannel, monitor); - if (! status) { - // Success. - return OK; - } - - // Failed! - { - AutoMutex _l(mLock); - mLocked.inputChannelObjWeakTable.removeItem(inputChannel.get()); - } - -DeleteWeakRef: - env->DeleteWeakGlobalRef(inputChannelObjWeak); - return status; + const sp<InputChannel>& inputChannel, + const sp<InputWindowHandle>& inputWindowHandle, bool monitor) { + return mInputManager->getDispatcher()->registerInputChannel( + inputChannel, inputWindowHandle, monitor); } status_t NativeInputManager::unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel) { - jweak inputChannelObjWeak; - { - AutoMutex _l(mLock); - - ssize_t index = mLocked.inputChannelObjWeakTable.indexOfKey(inputChannel.get()); - if (index < 0) { - LOGE("Input channel object '%s' is not currently registered", - inputChannel->getName().string()); - return INVALID_OPERATION; - } - - inputChannelObjWeak = mLocked.inputChannelObjWeakTable.valueAt(index); - mLocked.inputChannelObjWeakTable.removeItemsAt(index); - } - - env->DeleteWeakGlobalRef(inputChannelObjWeak); - return mInputManager->getDispatcher()->unregisterInputChannel(inputChannel); } -jobject NativeInputManager::getInputChannelObjLocal(JNIEnv* env, - const sp<InputChannel>& inputChannel) { - InputChannel* inputChannelPtr = inputChannel.get(); - if (! inputChannelPtr) { - return NULL; - } - - { - AutoMutex _l(mLock); - - ssize_t index = mLocked.inputChannelObjWeakTable.indexOfKey(inputChannelPtr); - if (index < 0) { - return NULL; - } - - jweak inputChannelObjWeak = mLocked.inputChannelObjWeakTable.valueAt(index); - return env->NewLocalRef(inputChannelObjWeak); - } -} - bool NativeInputManager::getDisplayInfo(int32_t displayId, int32_t* width, int32_t* height, int32_t* orientation) { bool result = false; @@ -549,50 +442,46 @@ void NativeInputManager::notifyConfigurationChanged(nsecs_t when) { } nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, - const sp<InputChannel>& inputChannel) { + const sp<InputWindowHandle>& inputWindowHandle) { #if DEBUG_INPUT_DISPATCHER_POLICY LOGD("notifyANR"); #endif JNIEnv* env = jniEnv(); - jobject tokenObjLocal; - if (inputApplicationHandle.get()) { - ApplicationToken* token = static_cast<ApplicationToken*>(inputApplicationHandle.get()); - jweak tokenObjWeak = token->getTokenObj(); - tokenObjLocal = env->NewLocalRef(tokenObjWeak); - } else { - tokenObjLocal = NULL; - } + jobject inputApplicationHandleObj = + getInputApplicationHandleObjLocalRef(env, inputApplicationHandle); + jobject inputWindowHandleObj = + getInputWindowHandleObjLocalRef(env, inputWindowHandle); - jobject inputChannelObjLocal = getInputChannelObjLocal(env, inputChannel); jlong newTimeout = env->CallLongMethod(mCallbacksObj, - gCallbacksClassInfo.notifyANR, tokenObjLocal, inputChannelObjLocal); + gCallbacksClassInfo.notifyANR, inputApplicationHandleObj, inputWindowHandleObj); if (checkAndClearExceptionFromCallback(env, "notifyANR")) { newTimeout = 0; // abort dispatch } else { assert(newTimeout >= 0); } - env->DeleteLocalRef(tokenObjLocal); - env->DeleteLocalRef(inputChannelObjLocal); + env->DeleteLocalRef(inputWindowHandleObj); + env->DeleteLocalRef(inputApplicationHandleObj); return newTimeout; } -void NativeInputManager::notifyInputChannelBroken(const sp<InputChannel>& inputChannel) { +void NativeInputManager::notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) { #if DEBUG_INPUT_DISPATCHER_POLICY - LOGD("notifyInputChannelBroken - inputChannel='%s'", inputChannel->getName().string()); + LOGD("notifyInputChannelBroken"); #endif JNIEnv* env = jniEnv(); - jobject inputChannelObjLocal = getInputChannelObjLocal(env, inputChannel); - if (inputChannelObjLocal) { + jobject inputWindowHandleObj = + getInputWindowHandleObjLocalRef(env, inputWindowHandle); + if (inputWindowHandleObj) { env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyInputChannelBroken, - inputChannelObjLocal); + inputWindowHandleObj); checkAndClearExceptionFromCallback(env, "notifyInputChannelBroken"); - env->DeleteLocalRef(inputChannelObjLocal); + env->DeleteLocalRef(inputWindowHandleObj); } } @@ -630,160 +519,32 @@ void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowObjArra jsize length = env->GetArrayLength(windowObjArray); for (jsize i = 0; i < length; i++) { - jobject inputTargetObj = env->GetObjectArrayElement(windowObjArray, i); - if (! inputTargetObj) { + jobject windowObj = env->GetObjectArrayElement(windowObjArray, i); + if (! windowObj) { break; // found null element indicating end of used portion of the array } windows.push(); InputWindow& window = windows.editTop(); - bool valid = populateWindow(env, inputTargetObj, window); - if (! valid) { + android_server_InputWindow_toNative(env, windowObj, &window); + if (window.inputChannel == NULL) { windows.pop(); } - - env->DeleteLocalRef(inputTargetObj); + env->DeleteLocalRef(windowObj); } mInputManager->getDispatcher()->setInputWindows(windows); } -bool NativeInputManager::populateWindow(JNIEnv* env, jobject windowObj, - InputWindow& outWindow) { - bool valid = false; - - jobject inputChannelObj = env->GetObjectField(windowObj, - gInputWindowClassInfo.inputChannel); - if (inputChannelObj) { - sp<InputChannel> inputChannel = - android_view_InputChannel_getInputChannel(env, inputChannelObj); - if (inputChannel != NULL) { - jstring name = jstring(env->GetObjectField(windowObj, - gInputWindowClassInfo.name)); - jint layoutParamsFlags = env->GetIntField(windowObj, - gInputWindowClassInfo.layoutParamsFlags); - jint layoutParamsType = env->GetIntField(windowObj, - gInputWindowClassInfo.layoutParamsType); - jlong dispatchingTimeoutNanos = env->GetLongField(windowObj, - gInputWindowClassInfo.dispatchingTimeoutNanos); - jint frameLeft = env->GetIntField(windowObj, - gInputWindowClassInfo.frameLeft); - jint frameTop = env->GetIntField(windowObj, - gInputWindowClassInfo.frameTop); - jint frameRight = env->GetIntField(windowObj, - gInputWindowClassInfo.frameRight); - jint frameBottom = env->GetIntField(windowObj, - gInputWindowClassInfo.frameBottom); - jint visibleFrameLeft = env->GetIntField(windowObj, - gInputWindowClassInfo.visibleFrameLeft); - jint visibleFrameTop = env->GetIntField(windowObj, - gInputWindowClassInfo.visibleFrameTop); - jint visibleFrameRight = env->GetIntField(windowObj, - gInputWindowClassInfo.visibleFrameRight); - jint visibleFrameBottom = env->GetIntField(windowObj, - gInputWindowClassInfo.visibleFrameBottom); - jint touchableAreaLeft = env->GetIntField(windowObj, - gInputWindowClassInfo.touchableAreaLeft); - jint touchableAreaTop = env->GetIntField(windowObj, - gInputWindowClassInfo.touchableAreaTop); - jint touchableAreaRight = env->GetIntField(windowObj, - gInputWindowClassInfo.touchableAreaRight); - jint touchableAreaBottom = env->GetIntField(windowObj, - gInputWindowClassInfo.touchableAreaBottom); - jboolean visible = env->GetBooleanField(windowObj, - gInputWindowClassInfo.visible); - jboolean canReceiveKeys = env->GetBooleanField(windowObj, - gInputWindowClassInfo.canReceiveKeys); - jboolean hasFocus = env->GetBooleanField(windowObj, - gInputWindowClassInfo.hasFocus); - jboolean hasWallpaper = env->GetBooleanField(windowObj, - gInputWindowClassInfo.hasWallpaper); - jboolean paused = env->GetBooleanField(windowObj, - gInputWindowClassInfo.paused); - jint layer = env->GetIntField(windowObj, - gInputWindowClassInfo.layer); - jint ownerPid = env->GetIntField(windowObj, - gInputWindowClassInfo.ownerPid); - jint ownerUid = env->GetIntField(windowObj, - gInputWindowClassInfo.ownerUid); - - const char* nameStr = env->GetStringUTFChars(name, NULL); - - outWindow.inputChannel = inputChannel; - outWindow.name.setTo(nameStr); - outWindow.layoutParamsFlags = layoutParamsFlags; - outWindow.layoutParamsType = layoutParamsType; - outWindow.dispatchingTimeout = dispatchingTimeoutNanos; - outWindow.frameLeft = frameLeft; - outWindow.frameTop = frameTop; - outWindow.frameRight = frameRight; - outWindow.frameBottom = frameBottom; - outWindow.visibleFrameLeft = visibleFrameLeft; - outWindow.visibleFrameTop = visibleFrameTop; - outWindow.visibleFrameRight = visibleFrameRight; - outWindow.visibleFrameBottom = visibleFrameBottom; - outWindow.touchableAreaLeft = touchableAreaLeft; - outWindow.touchableAreaTop = touchableAreaTop; - outWindow.touchableAreaRight = touchableAreaRight; - outWindow.touchableAreaBottom = touchableAreaBottom; - outWindow.visible = visible; - outWindow.canReceiveKeys = canReceiveKeys; - outWindow.hasFocus = hasFocus; - outWindow.hasWallpaper = hasWallpaper; - outWindow.paused = paused; - outWindow.layer = layer; - outWindow.ownerPid = ownerPid; - outWindow.ownerUid = ownerUid; - - env->ReleaseStringUTFChars(name, nameStr); - env->DeleteLocalRef(name); - valid = true; - } else { - LOGW("Dropping input target because its input channel is not initialized."); - } - - env->DeleteLocalRef(inputChannelObj); - } else { - LOGW("Dropping input target because the input channel object was null."); - } - return valid; -} - void NativeInputManager::setFocusedApplication(JNIEnv* env, jobject applicationObj) { if (applicationObj) { - jstring nameObj = jstring(env->GetObjectField(applicationObj, - gInputApplicationClassInfo.name)); - jlong dispatchingTimeoutNanos = env->GetLongField(applicationObj, - gInputApplicationClassInfo.dispatchingTimeoutNanos); - jobject tokenObj = env->GetObjectField(applicationObj, - gInputApplicationClassInfo.token); - jweak tokenObjWeak = env->NewWeakGlobalRef(tokenObj); - if (! tokenObjWeak) { - LOGE("Could not create weak reference for application token."); - LOGE_EX(env); - env->ExceptionClear(); - } - env->DeleteLocalRef(tokenObj); - - String8 name; - if (nameObj) { - const char* nameStr = env->GetStringUTFChars(nameObj, NULL); - name.setTo(nameStr); - env->ReleaseStringUTFChars(nameObj, nameStr); - env->DeleteLocalRef(nameObj); - } else { - LOGE("InputApplication.name should not be null."); - name.setTo("unknown"); - } - InputApplication application; - application.name = name; - application.dispatchingTimeout = dispatchingTimeoutNanos; - application.handle = new ApplicationToken(tokenObjWeak); - mInputManager->getDispatcher()->setFocusedApplication(& application); - } else { - mInputManager->getDispatcher()->setFocusedApplication(NULL); + android_server_InputApplication_toNative(env, applicationObj, &application); + if (application.inputApplicationHandle != NULL) { + mInputManager->getDispatcher()->setFocusedApplication(&application); + } } + mInputManager->getDispatcher()->setFocusedApplication(NULL); } void NativeInputManager::setInputDispatchMode(bool enabled, bool frozen) { @@ -875,7 +636,8 @@ void NativeInputManager::interceptGenericBeforeQueueing(nsecs_t when, uint32_t& } } -bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel, +bool NativeInputManager::interceptKeyBeforeDispatching( + const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags) { // Policy: // - Ignore untrusted events and pass them along. @@ -885,13 +647,13 @@ bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& i if (policyFlags & POLICY_FLAG_TRUSTED) { JNIEnv* env = jniEnv(); - // Note: inputChannel may be null. - jobject inputChannelObj = getInputChannelObjLocal(env, inputChannel); + // Note: inputWindowHandle may be null. + jobject inputWindowHandleObj = getInputWindowHandleObjLocalRef(env, inputWindowHandle); jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent); if (keyEventObj) { jboolean consumed = env->CallBooleanMethod(mCallbacksObj, gCallbacksClassInfo.interceptKeyBeforeDispatching, - inputChannelObj, keyEventObj, policyFlags); + inputWindowHandleObj, keyEventObj, policyFlags); bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching"); android_view_KeyEvent_recycle(env, keyEventObj); env->DeleteLocalRef(keyEventObj); @@ -899,12 +661,12 @@ bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& i } else { LOGE("Failed to obtain key event object for interceptKeyBeforeDispatching."); } - env->DeleteLocalRef(inputChannelObj); + env->DeleteLocalRef(inputWindowHandleObj); } return result; } -bool NativeInputManager::dispatchUnhandledKey(const sp<InputChannel>& inputChannel, +bool NativeInputManager::dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) { // Policy: // - Ignore untrusted events and do not perform default handling. @@ -912,13 +674,13 @@ bool NativeInputManager::dispatchUnhandledKey(const sp<InputChannel>& inputChann if (policyFlags & POLICY_FLAG_TRUSTED) { JNIEnv* env = jniEnv(); - // Note: inputChannel may be null. - jobject inputChannelObj = getInputChannelObjLocal(env, inputChannel); + // Note: inputWindowHandle may be null. + jobject inputWindowHandleObj = getInputWindowHandleObjLocalRef(env, inputWindowHandle); jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent); if (keyEventObj) { jobject fallbackKeyEventObj = env->CallObjectMethod(mCallbacksObj, gCallbacksClassInfo.dispatchUnhandledKey, - inputChannelObj, keyEventObj, policyFlags); + inputWindowHandleObj, keyEventObj, policyFlags); checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey"); android_view_KeyEvent_recycle(env, keyEventObj); env->DeleteLocalRef(keyEventObj); @@ -935,7 +697,7 @@ bool NativeInputManager::dispatchUnhandledKey(const sp<InputChannel>& inputChann } else { LOGE("Failed to obtain key event object for dispatchUnhandledKey."); } - env->DeleteLocalRef(inputChannelObj); + env->DeleteLocalRef(inputWindowHandleObj); } return result; } @@ -1079,7 +841,7 @@ static void android_server_InputManager_handleInputChannelDisposed(JNIEnv* env, } static void android_server_InputManager_nativeRegisterInputChannel(JNIEnv* env, jclass clazz, - jobject inputChannelObj, jboolean monitor) { + jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) { if (checkInputManagerUnitialized(env)) { return; } @@ -1091,9 +853,11 @@ static void android_server_InputManager_nativeRegisterInputChannel(JNIEnv* env, return; } + sp<InputWindowHandle> inputWindowHandle = + android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj); status_t status = gNativeInputManager->registerInputChannel( - env, inputChannel, inputChannelObj, monitor); + env, inputChannel, inputWindowHandle, monitor); if (status) { jniThrowRuntimeException(env, "Failed to register input channel. " "Check logs for details."); @@ -1311,7 +1075,8 @@ static JNINativeMethod gInputManagerMethods[] = { (void*) android_server_InputManager_nativeGetSwitchState }, { "nativeHasKeys", "(II[I[Z)Z", (void*) android_server_InputManager_nativeHasKeys }, - { "nativeRegisterInputChannel", "(Landroid/view/InputChannel;Z)V", + { "nativeRegisterInputChannel", + "(Landroid/view/InputChannel;Lcom/android/server/InputWindowHandle;Z)V", (void*) android_server_InputManager_nativeRegisterInputChannel }, { "nativeUnregisterInputChannel", "(Landroid/view/InputChannel;)V", (void*) android_server_InputManager_nativeUnregisterInputChannel }, @@ -1364,21 +1129,22 @@ int register_android_server_InputManager(JNIEnv* env) { "notifyLidSwitchChanged", "(JZ)V"); GET_METHOD_ID(gCallbacksClassInfo.notifyInputChannelBroken, gCallbacksClassInfo.clazz, - "notifyInputChannelBroken", "(Landroid/view/InputChannel;)V"); + "notifyInputChannelBroken", "(Lcom/android/server/InputWindowHandle;)V"); GET_METHOD_ID(gCallbacksClassInfo.notifyANR, gCallbacksClassInfo.clazz, - "notifyANR", "(Ljava/lang/Object;Landroid/view/InputChannel;)J"); + "notifyANR", + "(Lcom/android/server/InputApplicationHandle;Lcom/android/server/InputWindowHandle;)J"); GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz, "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;IZ)I"); GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, gCallbacksClassInfo.clazz, "interceptKeyBeforeDispatching", - "(Landroid/view/InputChannel;Landroid/view/KeyEvent;I)Z"); + "(Lcom/android/server/InputWindowHandle;Landroid/view/KeyEvent;I)Z"); GET_METHOD_ID(gCallbacksClassInfo.dispatchUnhandledKey, gCallbacksClassInfo.clazz, "dispatchUnhandledKey", - "(Landroid/view/InputChannel;Landroid/view/KeyEvent;I)Landroid/view/KeyEvent;"); + "(Lcom/android/server/InputWindowHandle;Landroid/view/KeyEvent;I)Landroid/view/KeyEvent;"); GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, gCallbacksClassInfo.clazz, "checkInjectEventsPermission", "(II)Z"); @@ -1401,99 +1167,6 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gCallbacksClassInfo.getPointerIcon, gCallbacksClassInfo.clazz, "getPointerIcon", "()Lcom/android/server/InputManager$PointerIcon;"); - // InputWindow - - FIND_CLASS(gInputWindowClassInfo.clazz, "com/android/server/InputWindow"); - - GET_FIELD_ID(gInputWindowClassInfo.inputChannel, gInputWindowClassInfo.clazz, - "inputChannel", "Landroid/view/InputChannel;"); - - GET_FIELD_ID(gInputWindowClassInfo.name, gInputWindowClassInfo.clazz, - "name", "Ljava/lang/String;"); - - GET_FIELD_ID(gInputWindowClassInfo.layoutParamsFlags, gInputWindowClassInfo.clazz, - "layoutParamsFlags", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.layoutParamsType, gInputWindowClassInfo.clazz, - "layoutParamsType", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.dispatchingTimeoutNanos, gInputWindowClassInfo.clazz, - "dispatchingTimeoutNanos", "J"); - - GET_FIELD_ID(gInputWindowClassInfo.frameLeft, gInputWindowClassInfo.clazz, - "frameLeft", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.frameTop, gInputWindowClassInfo.clazz, - "frameTop", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.frameRight, gInputWindowClassInfo.clazz, - "frameRight", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.frameBottom, gInputWindowClassInfo.clazz, - "frameBottom", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.visibleFrameLeft, gInputWindowClassInfo.clazz, - "visibleFrameLeft", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.visibleFrameTop, gInputWindowClassInfo.clazz, - "visibleFrameTop", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.visibleFrameRight, gInputWindowClassInfo.clazz, - "visibleFrameRight", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.visibleFrameBottom, gInputWindowClassInfo.clazz, - "visibleFrameBottom", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.touchableAreaLeft, gInputWindowClassInfo.clazz, - "touchableAreaLeft", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.touchableAreaTop, gInputWindowClassInfo.clazz, - "touchableAreaTop", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.touchableAreaRight, gInputWindowClassInfo.clazz, - "touchableAreaRight", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.touchableAreaBottom, gInputWindowClassInfo.clazz, - "touchableAreaBottom", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.visible, gInputWindowClassInfo.clazz, - "visible", "Z"); - - GET_FIELD_ID(gInputWindowClassInfo.canReceiveKeys, gInputWindowClassInfo.clazz, - "canReceiveKeys", "Z"); - - GET_FIELD_ID(gInputWindowClassInfo.hasFocus, gInputWindowClassInfo.clazz, - "hasFocus", "Z"); - - GET_FIELD_ID(gInputWindowClassInfo.hasWallpaper, gInputWindowClassInfo.clazz, - "hasWallpaper", "Z"); - - GET_FIELD_ID(gInputWindowClassInfo.paused, gInputWindowClassInfo.clazz, - "paused", "Z"); - - GET_FIELD_ID(gInputWindowClassInfo.layer, gInputWindowClassInfo.clazz, - "layer", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.ownerPid, gInputWindowClassInfo.clazz, - "ownerPid", "I"); - - GET_FIELD_ID(gInputWindowClassInfo.ownerUid, gInputWindowClassInfo.clazz, - "ownerUid", "I"); - - // InputApplication - - FIND_CLASS(gInputApplicationClassInfo.clazz, "com/android/server/InputApplication"); - - GET_FIELD_ID(gInputApplicationClassInfo.name, gInputApplicationClassInfo.clazz, - "name", "Ljava/lang/String;"); - - GET_FIELD_ID(gInputApplicationClassInfo.dispatchingTimeoutNanos, - gInputApplicationClassInfo.clazz, - "dispatchingTimeoutNanos", "J"); - - GET_FIELD_ID(gInputApplicationClassInfo.token, gInputApplicationClassInfo.clazz, - "token", "Ljava/lang/Object;"); - // KeyEvent FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent"); diff --git a/services/jni/com_android_server_InputWindow.cpp b/services/jni/com_android_server_InputWindow.cpp new file mode 100644 index 000000000000..a4609a0f9b85 --- /dev/null +++ b/services/jni/com_android_server_InputWindow.cpp @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2011 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. + */ + +#define LOG_TAG "InputWindow" + +#include "JNIHelp.h" +#include "jni.h" +#include <android_runtime/AndroidRuntime.h> + +#include <android_view_InputChannel.h> +#include "com_android_server_InputWindow.h" +#include "com_android_server_InputWindowHandle.h" + +namespace android { + +static struct { + jclass clazz; + + jfieldID inputWindowHandle; + jfieldID inputChannel; + jfieldID name; + jfieldID layoutParamsFlags; + jfieldID layoutParamsType; + jfieldID dispatchingTimeoutNanos; + jfieldID frameLeft; + jfieldID frameTop; + jfieldID frameRight; + jfieldID frameBottom; + jfieldID visibleFrameLeft; + jfieldID visibleFrameTop; + jfieldID visibleFrameRight; + jfieldID visibleFrameBottom; + jfieldID touchableAreaLeft; + jfieldID touchableAreaTop; + jfieldID touchableAreaRight; + jfieldID touchableAreaBottom; + jfieldID visible; + jfieldID canReceiveKeys; + jfieldID hasFocus; + jfieldID hasWallpaper; + jfieldID paused; + jfieldID layer; + jfieldID ownerPid; + jfieldID ownerUid; +} gInputWindowClassInfo; + + +// --- Global functions --- + +void android_server_InputWindow_toNative( + JNIEnv* env, jobject inputWindowObj, InputWindow* outInputWindow) { + jobject inputWindowHandleObj = env->GetObjectField(inputWindowObj, + gInputWindowClassInfo.inputWindowHandle); + if (inputWindowHandleObj) { + outInputWindow->inputWindowHandle = + android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj); + env->DeleteLocalRef(inputWindowHandleObj); + } else { + outInputWindow->inputWindowHandle = NULL; + } + + jobject inputChannelObj = env->GetObjectField(inputWindowObj, + gInputWindowClassInfo.inputChannel); + if (inputChannelObj) { + outInputWindow->inputChannel = + android_view_InputChannel_getInputChannel(env, inputChannelObj); + env->DeleteLocalRef(inputChannelObj); + } else { + outInputWindow->inputChannel = NULL; + } + + jstring nameObj = jstring(env->GetObjectField(inputWindowObj, + gInputWindowClassInfo.name)); + if (nameObj) { + const char* nameStr = env->GetStringUTFChars(nameObj, NULL); + outInputWindow->name.setTo(nameStr); + env->ReleaseStringUTFChars(nameObj, nameStr); + env->DeleteLocalRef(nameObj); + } else { + LOGE("InputWindow.name should not be null."); + outInputWindow->name.setTo("unknown"); + } + + outInputWindow->layoutParamsFlags = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.layoutParamsFlags); + outInputWindow->layoutParamsType = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.layoutParamsType); + outInputWindow->dispatchingTimeout = env->GetLongField(inputWindowObj, + gInputWindowClassInfo.dispatchingTimeoutNanos); + outInputWindow->frameLeft = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.frameLeft); + outInputWindow->frameTop = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.frameTop); + outInputWindow->frameRight = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.frameRight); + outInputWindow->frameBottom = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.frameBottom); + outInputWindow->visibleFrameLeft = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.visibleFrameLeft); + outInputWindow->visibleFrameTop = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.visibleFrameTop); + outInputWindow->visibleFrameRight = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.visibleFrameRight); + outInputWindow->visibleFrameBottom = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.visibleFrameBottom); + outInputWindow->touchableAreaLeft = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.touchableAreaLeft); + outInputWindow->touchableAreaTop = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.touchableAreaTop); + outInputWindow->touchableAreaRight = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.touchableAreaRight); + outInputWindow->touchableAreaBottom = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.touchableAreaBottom); + outInputWindow->visible = env->GetBooleanField(inputWindowObj, + gInputWindowClassInfo.visible); + outInputWindow->canReceiveKeys = env->GetBooleanField(inputWindowObj, + gInputWindowClassInfo.canReceiveKeys); + outInputWindow->hasFocus = env->GetBooleanField(inputWindowObj, + gInputWindowClassInfo.hasFocus); + outInputWindow->hasWallpaper = env->GetBooleanField(inputWindowObj, + gInputWindowClassInfo.hasWallpaper); + outInputWindow->paused = env->GetBooleanField(inputWindowObj, + gInputWindowClassInfo.paused); + outInputWindow->layer = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.layer); + outInputWindow->ownerPid = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.ownerPid); + outInputWindow->ownerUid = env->GetIntField(inputWindowObj, + gInputWindowClassInfo.ownerUid); +} + + +// --- JNI --- + +#define FIND_CLASS(var, className) \ + var = env->FindClass(className); \ + LOG_FATAL_IF(! var, "Unable to find class " className); \ + var = jclass(env->NewGlobalRef(var)); + +#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ + var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find field " fieldName); + +int register_android_server_InputWindow(JNIEnv* env) { + FIND_CLASS(gInputWindowClassInfo.clazz, "com/android/server/InputWindow"); + + GET_FIELD_ID(gInputWindowClassInfo.inputWindowHandle, gInputWindowClassInfo.clazz, + "inputWindowHandle", "Lcom/android/server/InputWindowHandle;"); + + GET_FIELD_ID(gInputWindowClassInfo.inputChannel, gInputWindowClassInfo.clazz, + "inputChannel", "Landroid/view/InputChannel;"); + + GET_FIELD_ID(gInputWindowClassInfo.name, gInputWindowClassInfo.clazz, + "name", "Ljava/lang/String;"); + + GET_FIELD_ID(gInputWindowClassInfo.layoutParamsFlags, gInputWindowClassInfo.clazz, + "layoutParamsFlags", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.layoutParamsType, gInputWindowClassInfo.clazz, + "layoutParamsType", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.dispatchingTimeoutNanos, gInputWindowClassInfo.clazz, + "dispatchingTimeoutNanos", "J"); + + GET_FIELD_ID(gInputWindowClassInfo.frameLeft, gInputWindowClassInfo.clazz, + "frameLeft", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.frameTop, gInputWindowClassInfo.clazz, + "frameTop", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.frameRight, gInputWindowClassInfo.clazz, + "frameRight", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.frameBottom, gInputWindowClassInfo.clazz, + "frameBottom", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.visibleFrameLeft, gInputWindowClassInfo.clazz, + "visibleFrameLeft", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.visibleFrameTop, gInputWindowClassInfo.clazz, + "visibleFrameTop", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.visibleFrameRight, gInputWindowClassInfo.clazz, + "visibleFrameRight", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.visibleFrameBottom, gInputWindowClassInfo.clazz, + "visibleFrameBottom", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.touchableAreaLeft, gInputWindowClassInfo.clazz, + "touchableAreaLeft", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.touchableAreaTop, gInputWindowClassInfo.clazz, + "touchableAreaTop", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.touchableAreaRight, gInputWindowClassInfo.clazz, + "touchableAreaRight", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.touchableAreaBottom, gInputWindowClassInfo.clazz, + "touchableAreaBottom", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.visible, gInputWindowClassInfo.clazz, + "visible", "Z"); + + GET_FIELD_ID(gInputWindowClassInfo.canReceiveKeys, gInputWindowClassInfo.clazz, + "canReceiveKeys", "Z"); + + GET_FIELD_ID(gInputWindowClassInfo.hasFocus, gInputWindowClassInfo.clazz, + "hasFocus", "Z"); + + GET_FIELD_ID(gInputWindowClassInfo.hasWallpaper, gInputWindowClassInfo.clazz, + "hasWallpaper", "Z"); + + GET_FIELD_ID(gInputWindowClassInfo.paused, gInputWindowClassInfo.clazz, + "paused", "Z"); + + GET_FIELD_ID(gInputWindowClassInfo.layer, gInputWindowClassInfo.clazz, + "layer", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.ownerPid, gInputWindowClassInfo.clazz, + "ownerPid", "I"); + + GET_FIELD_ID(gInputWindowClassInfo.ownerUid, gInputWindowClassInfo.clazz, + "ownerUid", "I"); + return 0; +} + +} /* namespace android */ diff --git a/services/jni/com_android_server_InputWindow.h b/services/jni/com_android_server_InputWindow.h new file mode 100644 index 000000000000..eaf7bdedbd7c --- /dev/null +++ b/services/jni/com_android_server_InputWindow.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef _ANDROID_SERVER_INPUT_WINDOW_H +#define _ANDROID_SERVER_INPUT_WINDOW_H + +#include <input/InputWindow.h> + +#include "JNIHelp.h" +#include "jni.h" + +namespace android { + +extern void android_server_InputWindow_toNative( + JNIEnv* env, jobject inputWindowObj, InputWindow* outInputWindow); + +} // namespace android + +#endif // _ANDROID_SERVER_INPUT_WINDOW_H diff --git a/services/jni/com_android_server_InputWindowHandle.cpp b/services/jni/com_android_server_InputWindowHandle.cpp new file mode 100644 index 000000000000..4d66212087ca --- /dev/null +++ b/services/jni/com_android_server_InputWindowHandle.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2011 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. + */ + +#define LOG_TAG "InputWindowHandle" + +#include "JNIHelp.h" +#include "jni.h" +#include <android_runtime/AndroidRuntime.h> +#include <utils/threads.h> + +#include "com_android_server_InputWindowHandle.h" +#include "com_android_server_InputApplicationHandle.h" + +namespace android { + +static struct { + jclass clazz; + + jfieldID ptr; + jfieldID inputApplicationHandle; +} gInputWindowHandleClassInfo; + +static Mutex gHandleMutex; + + +// --- NativeInputWindowHandle --- + +NativeInputWindowHandle::NativeInputWindowHandle( + const sp<InputApplicationHandle>& inputApplicationHandle, jweak objWeak) : + InputWindowHandle(inputApplicationHandle), + mObjWeak(objWeak) { +} + +NativeInputWindowHandle::~NativeInputWindowHandle() { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->DeleteWeakGlobalRef(mObjWeak); +} + +jobject NativeInputWindowHandle::getInputWindowHandleObjLocalRef(JNIEnv* env) { + return env->NewLocalRef(mObjWeak); +} + + +// --- Global functions --- + +sp<NativeInputWindowHandle> android_server_InputWindowHandle_getHandle( + JNIEnv* env, jobject inputWindowHandleObj) { + if (!inputWindowHandleObj) { + return NULL; + } + + AutoMutex _l(gHandleMutex); + + int ptr = env->GetIntField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr); + NativeInputWindowHandle* handle; + if (ptr) { + handle = reinterpret_cast<NativeInputWindowHandle*>(ptr); + } else { + jobject inputApplicationHandleObj = env->GetObjectField(inputWindowHandleObj, + gInputWindowHandleClassInfo.inputApplicationHandle); + sp<InputApplicationHandle> inputApplicationHandle = + android_server_InputApplicationHandle_getHandle(env, inputApplicationHandleObj); + env->DeleteLocalRef(inputApplicationHandleObj); + + jweak objWeak = env->NewWeakGlobalRef(inputWindowHandleObj); + handle = new NativeInputWindowHandle(inputApplicationHandle, objWeak); + handle->incStrong(inputWindowHandleObj); + env->SetIntField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr, + reinterpret_cast<int>(handle)); + } + return handle; +} + + +// --- JNI --- + +static void android_server_InputWindowHandle_nativeDispose(JNIEnv* env, jobject obj) { + AutoMutex _l(gHandleMutex); + + int ptr = env->GetIntField(obj, gInputWindowHandleClassInfo.ptr); + if (ptr) { + env->SetIntField(obj, gInputWindowHandleClassInfo.ptr, 0); + + NativeInputWindowHandle* handle = reinterpret_cast<NativeInputWindowHandle*>(ptr); + handle->decStrong(obj); + } +} + + +static JNINativeMethod gInputWindowHandleMethods[] = { + /* name, signature, funcPtr */ + { "nativeDispose", "()V", + (void*) android_server_InputWindowHandle_nativeDispose }, +}; + +#define FIND_CLASS(var, className) \ + var = env->FindClass(className); \ + LOG_FATAL_IF(! var, "Unable to find class " className); \ + var = jclass(env->NewGlobalRef(var)); + +#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ + var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find field " fieldName); + +int register_android_server_InputWindowHandle(JNIEnv* env) { + int res = jniRegisterNativeMethods(env, "com/android/server/InputWindowHandle", + gInputWindowHandleMethods, NELEM(gInputWindowHandleMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + + FIND_CLASS(gInputWindowHandleClassInfo.clazz, "com/android/server/InputWindowHandle"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.ptr, gInputWindowHandleClassInfo.clazz, + "ptr", "I"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.inputApplicationHandle, + gInputWindowHandleClassInfo.clazz, + "inputApplicationHandle", "Lcom/android/server/InputApplicationHandle;"); + + return 0; +} + +} /* namespace android */ diff --git a/services/jni/com_android_server_InputWindowHandle.h b/services/jni/com_android_server_InputWindowHandle.h new file mode 100644 index 000000000000..43f2a6ba9536 --- /dev/null +++ b/services/jni/com_android_server_InputWindowHandle.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef _ANDROID_SERVER_INPUT_WINDOW_HANDLE_H +#define _ANDROID_SERVER_INPUT_WINDOW_HANDLE_H + +#include <input/InputWindow.h> + +#include "JNIHelp.h" +#include "jni.h" + +namespace android { + +class NativeInputWindowHandle : public InputWindowHandle { +public: + NativeInputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle, + jweak objWeak); + virtual ~NativeInputWindowHandle(); + + jobject getInputWindowHandleObjLocalRef(JNIEnv* env); + +private: + jweak mObjWeak; +}; + + +extern sp<NativeInputWindowHandle> android_server_InputWindowHandle_getHandle( + JNIEnv* env, jobject inputWindowHandleObj); + +} // namespace android + +#endif // _ANDROID_SERVER_INPUT_WINDOW_HANDLE_H diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp index cd4f0a46c517..bdd6d808ac42 100644 --- a/services/jni/onload.cpp +++ b/services/jni/onload.cpp @@ -6,6 +6,10 @@ namespace android { int register_android_server_AlarmManagerService(JNIEnv* env); int register_android_server_BatteryService(JNIEnv* env); +int register_android_server_InputApplication(JNIEnv* env); +int register_android_server_InputApplicationHandle(JNIEnv* env); +int register_android_server_InputWindow(JNIEnv* env); +int register_android_server_InputWindowHandle(JNIEnv* env); int register_android_server_InputManager(JNIEnv* env); int register_android_server_LightsService(JNIEnv* env); int register_android_server_PowerManagerService(JNIEnv* env); @@ -28,6 +32,10 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) LOG_ASSERT(env, "Could not retrieve the env!"); register_android_server_PowerManagerService(env); + register_android_server_InputApplication(env); + register_android_server_InputApplicationHandle(env); + register_android_server_InputWindow(env); + register_android_server_InputWindowHandle(env); register_android_server_InputManager(env); register_android_server_LightsService(env); register_android_server_AlarmManagerService(env); |