1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=4 sw=4 sts=4 tw=80 et: */
3 /* Copyright 2012 Mozilla Foundation and Mozilla contributors
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
25 #include <hardware_legacy/power.h>
27 #include <sys/epoll.h>
28 #include <sys/ioctl.h>
29 #include <sys/param.h>
31 #include <sys/types.h>
33 #include <utils/BitSet.h>
35 #include "base/basictypes.h"
36 #include "GonkPermission.h"
38 #ifdef MOZ_OMX_DECODER
39 #include "MediaResourceManagerService.h"
41 #include "mozilla/TouchEvents.h"
42 #include "mozilla/FileUtils.h"
43 #include "mozilla/Hal.h"
44 #include "mozilla/MouseEvents.h"
45 #include "mozilla/Mutex.h"
46 #include "mozilla/Services.h"
47 #include "mozilla/TextEvents.h"
48 #if ANDROID_VERSION >= 18
49 #include "nativewindow/FakeSurfaceComposer.h"
51 #include "nsAppShell.h"
52 #include "mozilla/dom/Touch.h"
53 #include "nsGkAtoms.h"
54 #include "nsIObserverService.h"
55 #include "nsIScreen.h"
56 #include "nsScreenManagerGonk.h"
57 #include "nsThreadUtils.h"
59 #include "OrientationObserver.h"
60 #include "GonkMemoryPressureMonitoring.h"
62 #include "android/log.h"
63 #include "libui/EventHub.h"
64 #include "libui/InputReader.h"
65 #include "libui/InputDispatcher.h"
67 #ifdef MOZ_NUWA_PROCESS
71 #include "mozilla/Preferences.h"
72 #include "GeckoProfiler.h"
74 // Defines kKeyMapping and GetKeyNameIndex()
75 #include "GonkKeyMapping.h"
76 #include "mozilla/layers/CompositorParent.h"
77 #include "GeckoTouchDispatcher.h"
79 #define LOG(args...) \
80 __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
81 #ifdef VERBOSE_LOG_ENABLED
82 # define VERBOSE_LOG(args...) \
83 __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
85 # define VERBOSE_LOG(args...) \
89 using namespace android
;
90 using namespace mozilla
;
91 using namespace mozilla::dom
;
92 using namespace mozilla::services
;
93 using namespace mozilla::widget
;
95 bool gDrawRequest
= false;
96 static nsAppShell
*gAppShell
= nullptr;
97 static int epollfd
= 0;
98 static int signalfds
[2] = {0};
99 static bool sDevInputAudioJack
;
100 static int32_t sHeadphoneState
;
101 static int32_t sMicrophoneState
;
103 // Amount of time in MS before an input is considered expired.
104 static const uint64_t kInputExpirationThresholdMs
= 1000;
105 static const char kKey_WAKE_LOCK_ID
[] = "GeckoKeyEvent";
107 NS_IMPL_ISUPPORTS_INHERITED(nsAppShell
, nsBaseAppShell
, nsIObserver
)
110 nanosecsToMillisecs(nsecs_t nsecs
)
112 return nsecs
/ 1000000;
117 bool ProcessNextEvent()
119 return gAppShell
->ProcessNextNativeEvent(true);
124 gAppShell
->NotifyNativeEvent();
127 } // namespace mozilla
130 pipeHandler(int fd
, FdHandler
*data
)
135 len
= read(fd
, tmp
, sizeof(tmp
));
141 PointerCoords coords
;
144 struct UserInputData
{
161 ::Touch touches
[MAX_POINTERS
];
166 static mozilla::Modifiers
167 getDOMModifiers(int32_t metaState
)
169 mozilla::Modifiers result
= 0;
170 if (metaState
& (AMETA_ALT_ON
| AMETA_ALT_LEFT_ON
| AMETA_ALT_RIGHT_ON
)) {
171 result
|= MODIFIER_ALT
;
173 if (metaState
& (AMETA_SHIFT_ON
|
174 AMETA_SHIFT_LEFT_ON
| AMETA_SHIFT_RIGHT_ON
)) {
175 result
|= MODIFIER_SHIFT
;
177 if (metaState
& AMETA_FUNCTION_ON
) {
178 result
|= MODIFIER_FN
;
180 if (metaState
& (AMETA_CTRL_ON
|
181 AMETA_CTRL_LEFT_ON
| AMETA_CTRL_RIGHT_ON
)) {
182 result
|= MODIFIER_CONTROL
;
184 if (metaState
& (AMETA_META_ON
|
185 AMETA_META_LEFT_ON
| AMETA_META_RIGHT_ON
)) {
186 result
|= MODIFIER_META
;
188 if (metaState
& AMETA_CAPS_LOCK_ON
) {
189 result
|= MODIFIER_CAPSLOCK
;
191 if (metaState
& AMETA_NUM_LOCK_ON
) {
192 result
|= MODIFIER_NUMLOCK
;
194 if (metaState
& AMETA_SCROLL_LOCK_ON
) {
195 result
|= MODIFIER_SCROLLLOCK
;
200 class MOZ_STACK_CLASS KeyEventDispatcher
203 KeyEventDispatcher(const UserInputData
& aData
,
204 KeyCharacterMap
* aKeyCharMap
);
208 const UserInputData
& mData
;
209 sp
<KeyCharacterMap
> mKeyCharMap
;
212 char16_t mUnmodifiedChar
;
214 uint32_t mDOMKeyCode
;
215 KeyNameIndex mDOMKeyNameIndex
;
216 CodeNameIndex mDOMCodeNameIndex
;
217 char16_t mDOMPrintableKeyValue
;
219 bool IsKeyPress() const
221 return mData
.action
== AKEY_EVENT_ACTION_DOWN
;
223 bool IsRepeat() const
225 return IsKeyPress() && (mData
.flags
& AKEY_EVENT_FLAG_LONG_PRESS
);
228 char16_t
PrintableKeyValue() const;
230 int32_t UnmodifiedMetaState() const
232 return mData
.metaState
&
233 ~(AMETA_ALT_ON
| AMETA_ALT_LEFT_ON
| AMETA_ALT_RIGHT_ON
|
234 AMETA_CTRL_ON
| AMETA_CTRL_LEFT_ON
| AMETA_CTRL_RIGHT_ON
|
235 AMETA_META_ON
| AMETA_META_LEFT_ON
| AMETA_META_RIGHT_ON
);
238 static bool IsControlChar(char16_t aChar
)
240 return (aChar
< ' ' || aChar
== 0x7F);
243 void DispatchKeyDownEvent();
244 void DispatchKeyUpEvent();
245 nsEventStatus
DispatchKeyEventInternal(uint32_t aEventMessage
);
248 KeyEventDispatcher::KeyEventDispatcher(const UserInputData
& aData
,
249 KeyCharacterMap
* aKeyCharMap
) :
250 mData(aData
), mKeyCharMap(aKeyCharMap
), mChar(0), mUnmodifiedChar(0),
251 mDOMPrintableKeyValue(0)
253 // XXX Printable key's keyCode value should be computed with actual
255 mDOMKeyCode
= (mData
.key
.keyCode
< (ssize_t
)ArrayLength(kKeyMapping
)) ?
256 kKeyMapping
[mData
.key
.keyCode
] : 0;
257 mDOMKeyNameIndex
= GetKeyNameIndex(mData
.key
.keyCode
);
258 mDOMCodeNameIndex
= GetCodeNameIndex(mData
.key
.scanCode
);
260 if (!mKeyCharMap
.get()) {
264 mChar
= mKeyCharMap
->getCharacter(mData
.key
.keyCode
, mData
.metaState
);
265 if (IsControlChar(mChar
)) {
268 int32_t unmodifiedMetaState
= UnmodifiedMetaState();
269 if (mData
.metaState
== unmodifiedMetaState
) {
270 mUnmodifiedChar
= mChar
;
272 mUnmodifiedChar
= mKeyCharMap
->getCharacter(mData
.key
.keyCode
,
273 unmodifiedMetaState
);
274 if (IsControlChar(mUnmodifiedChar
)) {
279 mDOMPrintableKeyValue
= PrintableKeyValue();
283 KeyEventDispatcher::PrintableKeyValue() const
285 if (mDOMKeyNameIndex
!= KEY_NAME_INDEX_USE_STRING
) {
288 return mChar
? mChar
: mUnmodifiedChar
;
292 KeyEventDispatcher::DispatchKeyEventInternal(uint32_t aEventMessage
)
294 WidgetKeyboardEvent
event(true, aEventMessage
, nullptr);
295 if (aEventMessage
== NS_KEY_PRESS
) {
296 // XXX If the charCode is not a printable character, the charCode
297 // should be computed without Ctrl/Alt/Meta modifiers.
298 event
.charCode
= static_cast<uint32_t>(mChar
);
300 if (!event
.charCode
) {
301 event
.keyCode
= mDOMKeyCode
;
303 event
.isChar
= !!event
.charCode
;
304 event
.mIsRepeat
= IsRepeat();
305 event
.mKeyNameIndex
= mDOMKeyNameIndex
;
306 if (mDOMPrintableKeyValue
) {
307 event
.mKeyValue
= mDOMPrintableKeyValue
;
309 event
.mCodeNameIndex
= mDOMCodeNameIndex
;
310 event
.modifiers
= getDOMModifiers(mData
.metaState
);
311 event
.location
= nsIDOMKeyEvent::DOM_KEY_LOCATION_MOBILE
;
312 event
.time
= mData
.timeMs
;
313 return nsWindow::DispatchInputEvent(event
);
317 KeyEventDispatcher::Dispatch()
319 // XXX Even if unknown key is pressed, DOM key event should be
320 // dispatched since Gecko for the other platforms are implemented
322 if (!mDOMKeyCode
&& mDOMKeyNameIndex
== KEY_NAME_INDEX_Unidentified
) {
323 VERBOSE_LOG("Got unknown key event code. "
324 "type 0x%04x code 0x%04x value %d",
325 mData
.action
, mData
.key
.keyCode
, IsKeyPress());
330 DispatchKeyDownEvent();
332 DispatchKeyUpEvent();
337 KeyEventDispatcher::DispatchKeyDownEvent()
339 nsEventStatus status
= DispatchKeyEventInternal(NS_KEY_DOWN
);
340 if (status
!= nsEventStatus_eConsumeNoDefault
) {
341 DispatchKeyEventInternal(NS_KEY_PRESS
);
346 KeyEventDispatcher::DispatchKeyUpEvent()
348 DispatchKeyEventInternal(NS_KEY_UP
);
351 class SwitchEventRunnable
: public nsRunnable
{
353 SwitchEventRunnable(hal::SwitchEvent
& aEvent
) : mEvent(aEvent
)
358 hal::NotifySwitchStateFromInputDevice(mEvent
.device(),
363 hal::SwitchEvent mEvent
;
367 updateHeadphoneSwitch()
369 hal::SwitchEvent event
;
371 switch (sHeadphoneState
) {
373 event
.status() = hal::SWITCH_STATE_OFF
;
375 case AKEY_STATE_DOWN
:
376 event
.status() = sMicrophoneState
== AKEY_STATE_DOWN
?
377 hal::SWITCH_STATE_HEADSET
: hal::SWITCH_STATE_HEADPHONE
;
383 event
.device() = hal::SWITCH_HEADPHONES
;
384 NS_DispatchToMainThread(new SwitchEventRunnable(event
));
387 class GeckoPointerController
: public PointerControllerInterface
{
390 int32_t mButtonState
;
391 InputReaderConfiguration
* mConfig
;
393 GeckoPointerController(InputReaderConfiguration
* config
)
400 virtual bool getBounds(float* outMinX
, float* outMinY
,
401 float* outMaxX
, float* outMaxY
) const;
402 virtual void move(float deltaX
, float deltaY
);
403 virtual void setButtonState(int32_t buttonState
);
404 virtual int32_t getButtonState() const;
405 virtual void setPosition(float x
, float y
);
406 virtual void getPosition(float* outX
, float* outY
) const;
407 virtual void fade(Transition transition
) {}
408 virtual void unfade(Transition transition
) {}
409 virtual void setPresentation(Presentation presentation
) {}
410 virtual void setSpots(const PointerCoords
* spotCoords
, const uint32_t* spotIdToIndex
,
411 BitSet32 spotIdBits
) {}
412 virtual void clearSpots() {}
416 GeckoPointerController::getBounds(float* outMinX
,
419 float* outMaxY
) const
421 DisplayViewport viewport
;
423 mConfig
->getDisplayInfo(false, &viewport
);
425 *outMinX
= *outMinY
= 0;
426 *outMaxX
= viewport
.logicalRight
;
427 *outMaxY
= viewport
.logicalBottom
;
432 GeckoPointerController::move(float deltaX
, float deltaY
)
434 float minX
, minY
, maxX
, maxY
;
435 getBounds(&minX
, &minY
, &maxX
, &maxY
);
437 mX
= clamped(mX
+ deltaX
, minX
, maxX
);
438 mY
= clamped(mY
+ deltaY
, minY
, maxY
);
442 GeckoPointerController::setButtonState(int32_t buttonState
)
444 mButtonState
= buttonState
;
448 GeckoPointerController::getButtonState() const
454 GeckoPointerController::setPosition(float x
, float y
)
461 GeckoPointerController::getPosition(float* outX
, float* outY
) const
467 class GeckoInputReaderPolicy
: public InputReaderPolicyInterface
{
468 InputReaderConfiguration mConfig
;
470 GeckoInputReaderPolicy() {}
472 virtual void getReaderConfiguration(InputReaderConfiguration
* outConfig
);
473 virtual sp
<PointerControllerInterface
> obtainPointerController(int32_t
476 return new GeckoPointerController(&mConfig
);
478 virtual void notifyInputDevicesChanged(const android::Vector
<InputDeviceInfo
>& inputDevices
) {};
479 virtual sp
<KeyCharacterMap
> getKeyboardLayoutOverlay(const String8
& inputDeviceDescriptor
)
483 virtual String8
getDeviceAlias(const InputDeviceIdentifier
& identifier
)
485 return String8::empty();
488 void setDisplayInfo();
491 virtual ~GeckoInputReaderPolicy() {}
494 class GeckoInputDispatcher
: public InputDispatcherInterface
{
496 GeckoInputDispatcher(sp
<EventHub
> &aEventHub
)
497 : mQueueLock("GeckoInputDispatcher::mQueueMutex")
498 , mEventHub(aEventHub
)
500 , mKeyEventsFiltered(false)
501 , mPowerWakelock(false)
503 mTouchDispatcher
= new GeckoTouchDispatcher();
506 virtual void dump(String8
& dump
);
508 virtual void monitor() {}
510 // Called on the main thread
511 virtual void dispatchOnce();
513 // notify* methods are called on the InputReaderThread
514 virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs
* args
);
515 virtual void notifyKey(const NotifyKeyArgs
* args
);
516 virtual void notifyMotion(const NotifyMotionArgs
* args
);
517 virtual void notifySwitch(const NotifySwitchArgs
* args
);
518 virtual void notifyDeviceReset(const NotifyDeviceResetArgs
* args
);
520 virtual int32_t injectInputEvent(const InputEvent
* event
,
521 int32_t injectorPid
, int32_t injectorUid
, int32_t syncMode
, int32_t timeoutMillis
,
522 uint32_t policyFlags
);
524 virtual void setInputWindows(const android::Vector
<sp
<InputWindowHandle
> >& inputWindowHandles
);
525 virtual void setFocusedApplication(const sp
<InputApplicationHandle
>& inputApplicationHandle
);
527 virtual void setInputDispatchMode(bool enabled
, bool frozen
);
528 virtual void setInputFilterEnabled(bool enabled
) {}
529 virtual bool transferTouchFocus(const sp
<InputChannel
>& fromChannel
,
530 const sp
<InputChannel
>& toChannel
) { return true; }
532 virtual status_t
registerInputChannel(const sp
<InputChannel
>& inputChannel
,
533 const sp
<InputWindowHandle
>& inputWindowHandle
, bool monitor
);
534 virtual status_t
unregisterInputChannel(const sp
<InputChannel
>& inputChannel
);
539 virtual ~GeckoInputDispatcher() { }
542 // mQueueLock should generally be locked while using mEventQueue.
543 // UserInputData is pushed on on the InputReaderThread and
544 // popped and dispatched on the main thread.
545 mozilla::Mutex mQueueLock
;
546 std::queue
<UserInputData
> mEventQueue
;
547 sp
<EventHub
> mEventHub
;
548 nsRefPtr
<GeckoTouchDispatcher
> mTouchDispatcher
;
551 bool mKeyEventsFiltered
;
555 // GeckoInputReaderPolicy
557 GeckoInputReaderPolicy::setDisplayInfo()
559 static_assert(nsIScreen::ROTATION_0_DEG
==
560 DISPLAY_ORIENTATION_0
,
561 "Orientation enums not matched!");
562 static_assert(nsIScreen::ROTATION_90_DEG
==
563 DISPLAY_ORIENTATION_90
,
564 "Orientation enums not matched!");
565 static_assert(nsIScreen::ROTATION_180_DEG
==
566 DISPLAY_ORIENTATION_180
,
567 "Orientation enums not matched!");
568 static_assert(nsIScreen::ROTATION_270_DEG
==
569 DISPLAY_ORIENTATION_270
,
570 "Orientation enums not matched!");
572 DisplayViewport viewport
;
573 viewport
.displayId
= 0;
574 viewport
.orientation
= nsScreenGonk::GetRotation();
575 viewport
.physicalRight
= viewport
.deviceWidth
= gScreenBounds
.width
;
576 viewport
.physicalBottom
= viewport
.deviceHeight
= gScreenBounds
.height
;
577 if (viewport
.orientation
== DISPLAY_ORIENTATION_90
||
578 viewport
.orientation
== DISPLAY_ORIENTATION_270
) {
579 viewport
.logicalRight
= gScreenBounds
.height
;
580 viewport
.logicalBottom
= gScreenBounds
.width
;
582 viewport
.logicalRight
= gScreenBounds
.width
;
583 viewport
.logicalBottom
= gScreenBounds
.height
;
585 mConfig
.setDisplayInfo(false, viewport
);
588 void GeckoInputReaderPolicy::getReaderConfiguration(InputReaderConfiguration
* outConfig
)
590 *outConfig
= mConfig
;
594 // GeckoInputDispatcher
596 GeckoInputDispatcher::dump(String8
& dump
)
601 isExpired(const UserInputData
& data
)
604 nanosecsToMillisecs(systemTime(SYSTEM_TIME_MONOTONIC
));
605 return (timeNowMs
- data
.timeMs
) > kInputExpirationThresholdMs
;
609 GeckoInputDispatcher::dispatchOnce()
613 MutexAutoLock
lock(mQueueLock
);
614 if (mEventQueue
.empty())
616 data
= mEventQueue
.front();
618 if (!mEventQueue
.empty())
619 gAppShell
->NotifyNativeEvent();
623 case UserInputData::MOTION_DATA
: {
624 MOZ_ASSERT_UNREACHABLE("Should not dispatch touch events here anymore");
627 case UserInputData::KEY_DATA
: {
628 if (!mKeyDownCount
) {
629 // No pending events, the filter state can be updated.
630 mKeyEventsFiltered
= isExpired(data
);
633 mKeyDownCount
+= (data
.action
== AKEY_EVENT_ACTION_DOWN
) ? 1 : -1;
634 if (mKeyEventsFiltered
) {
638 sp
<KeyCharacterMap
> kcm
= mEventHub
->getKeyCharacterMap(data
.deviceId
);
639 KeyEventDispatcher
dispatcher(data
, kcm
.get());
640 dispatcher
.Dispatch();
644 MutexAutoLock
lock(mQueueLock
);
645 if (mPowerWakelock
&& mEventQueue
.empty()) {
646 release_wake_lock(kKey_WAKE_LOCK_ID
);
647 mPowerWakelock
= false;
652 GeckoInputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs
*)
657 GeckoInputDispatcher::notifyKey(const NotifyKeyArgs
* args
)
660 data
.timeMs
= nanosecsToMillisecs(args
->eventTime
);
661 data
.type
= UserInputData::KEY_DATA
;
662 data
.action
= args
->action
;
663 data
.flags
= args
->flags
;
664 data
.metaState
= args
->metaState
;
665 data
.deviceId
= args
->deviceId
;
666 data
.key
.keyCode
= args
->keyCode
;
667 data
.key
.scanCode
= args
->scanCode
;
669 MutexAutoLock
lock(mQueueLock
);
670 mEventQueue
.push(data
);
671 if (!mPowerWakelock
) {
673 acquire_wake_lock(PARTIAL_WAKE_LOCK
, kKey_WAKE_LOCK_ID
);
676 gAppShell
->NotifyNativeEvent();
680 addMultiTouch(MultiTouchInput
& aMultiTouch
,
681 const NotifyMotionArgs
* args
, int aIndex
)
683 int32_t id
= args
->pointerProperties
[aIndex
].id
;
684 PointerCoords coords
= args
->pointerCoords
[aIndex
];
685 float force
= coords
.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE
);
687 float orientation
= coords
.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION
);
688 float rotationAngle
= orientation
* 180 / M_PI
;
689 if (rotationAngle
== 90) {
693 float radiusX
, radiusY
;
694 if (rotationAngle
< 0) {
695 radiusX
= coords
.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR
) / 2;
696 radiusY
= coords
.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR
) / 2;
699 radiusX
= coords
.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR
) / 2;
700 radiusY
= coords
.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR
) / 2;
703 ScreenIntPoint
point(floor(coords
.getX() + 0.5),
704 floor(coords
.getY() + 0.5));
706 SingleTouchData
touchData(id
, point
, ScreenSize(radiusX
, radiusY
),
707 rotationAngle
, force
);
709 aMultiTouch
.mTouches
.AppendElement(touchData
);
713 GeckoInputDispatcher::notifyMotion(const NotifyMotionArgs
* args
)
715 uint32_t time
= nanosecsToMillisecs(args
->eventTime
);
716 int32_t action
= args
->action
& AMOTION_EVENT_ACTION_MASK
;
717 int touchCount
= args
->pointerCount
;
718 MOZ_ASSERT(touchCount
<= MAX_POINTERS
);
719 TimeStamp timestamp
= mozilla::TimeStamp::FromSystemTime(args
->eventTime
);
720 Modifiers modifiers
= getDOMModifiers(args
->metaState
);
722 MultiTouchInput::MultiTouchType touchType
= MultiTouchInput::MULTITOUCH_CANCEL
;
724 case AMOTION_EVENT_ACTION_DOWN
:
725 case AMOTION_EVENT_ACTION_POINTER_DOWN
:
726 touchType
= MultiTouchInput::MULTITOUCH_START
;
728 case AMOTION_EVENT_ACTION_MOVE
:
729 touchType
= MultiTouchInput::MULTITOUCH_MOVE
;
731 case AMOTION_EVENT_ACTION_UP
:
732 case AMOTION_EVENT_ACTION_POINTER_UP
:
733 touchType
= MultiTouchInput::MULTITOUCH_END
;
735 case AMOTION_EVENT_ACTION_OUTSIDE
:
736 case AMOTION_EVENT_ACTION_CANCEL
:
737 touchType
= MultiTouchInput::MULTITOUCH_CANCEL
;
739 case AMOTION_EVENT_ACTION_HOVER_EXIT
:
740 case AMOTION_EVENT_ACTION_HOVER_ENTER
:
741 case AMOTION_EVENT_ACTION_HOVER_MOVE
:
742 NS_WARNING("Ignoring hover touch events");
745 MOZ_ASSERT_UNREACHABLE("Could not assign a touch type");
749 MultiTouchInput
touchData(touchType
, time
, timestamp
, modifiers
);
751 // For touch ends, we have to filter out which finger is actually
752 // the touch end since the touch array has all fingers, not just the touch
753 // that we want to end
754 if (touchType
== MultiTouchInput::MULTITOUCH_END
) {
755 int touchIndex
= args
->action
& AMOTION_EVENT_ACTION_POINTER_INDEX_MASK
;
756 touchIndex
>>= AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT
;
757 addMultiTouch(touchData
, args
, touchIndex
);
759 for (int32_t i
= 0; i
< touchCount
; ++i
) {
760 addMultiTouch(touchData
, args
, i
);
764 mTouchDispatcher
->NotifyTouch(touchData
, timestamp
);
767 void GeckoInputDispatcher::notifySwitch(const NotifySwitchArgs
* args
)
769 if (!sDevInputAudioJack
)
772 bool needSwitchUpdate
= false;
774 if (args
->switchMask
& (1 << SW_HEADPHONE_INSERT
)) {
775 sHeadphoneState
= (args
->switchValues
& (1 << SW_HEADPHONE_INSERT
)) ?
776 AKEY_STATE_DOWN
: AKEY_STATE_UP
;
777 needSwitchUpdate
= true;
780 if (args
->switchMask
& (1 << SW_MICROPHONE_INSERT
)) {
781 sMicrophoneState
= (args
->switchValues
& (1 << SW_MICROPHONE_INSERT
)) ?
782 AKEY_STATE_DOWN
: AKEY_STATE_UP
;
783 needSwitchUpdate
= true;
786 if (needSwitchUpdate
)
787 updateHeadphoneSwitch();
790 void GeckoInputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs
* args
)
794 int32_t GeckoInputDispatcher::injectInputEvent(
795 const InputEvent
* event
,
796 int32_t injectorPid
, int32_t injectorUid
, int32_t syncMode
,
797 int32_t timeoutMillis
, uint32_t policyFlags
)
799 return INPUT_EVENT_INJECTION_SUCCEEDED
;
803 GeckoInputDispatcher::setInputWindows(const android::Vector
<sp
<InputWindowHandle
> >& inputWindowHandles
)
808 GeckoInputDispatcher::setFocusedApplication(const sp
<InputApplicationHandle
>& inputApplicationHandle
)
813 GeckoInputDispatcher::setInputDispatchMode(bool enabled
, bool frozen
)
818 GeckoInputDispatcher::registerInputChannel(const sp
<InputChannel
>& inputChannel
,
819 const sp
<InputWindowHandle
>& inputWindowHandle
, bool monitor
)
825 GeckoInputDispatcher::unregisterInputChannel(const sp
<InputChannel
>& inputChannel
)
830 nsAppShell::nsAppShell()
831 : mNativeCallbackRequest(false)
838 nsAppShell::~nsAppShell()
840 // mReaderThread and mEventHub will both be null if InitInputDevices
842 if (mReaderThread
.get()) {
843 // We separate requestExit() and join() here so we can wake the EventHub's
844 // input loop, and stop it from polling for input events
845 mReaderThread
->requestExit();
848 status_t result
= mReaderThread
->requestExitAndWait();
850 LOG("Could not stop reader thread - %d", result
);
858 nsresult rv
= nsBaseAppShell::Init();
859 NS_ENSURE_SUCCESS(rv
, rv
);
861 epollfd
= epoll_create(16);
862 NS_ENSURE_TRUE(epollfd
>= 0, NS_ERROR_UNEXPECTED
);
864 int ret
= pipe2(signalfds
, O_NONBLOCK
);
865 NS_ENSURE_FALSE(ret
, NS_ERROR_UNEXPECTED
);
867 rv
= AddFdHandler(signalfds
[0], pipeHandler
, "");
868 NS_ENSURE_SUCCESS(rv
, rv
);
870 InitGonkMemoryPressureMonitoring();
872 if (XRE_GetProcessType() == GeckoProcessType_Default
) {
873 printf("*****************************************************************\n");
875 printf("*** This is stdout. Most of the useful output will be in logcat.\n");
877 printf("*****************************************************************\n");
878 #ifdef MOZ_OMX_DECODER
879 android::MediaResourceManagerService::instantiate();
881 #if ANDROID_VERSION >= 18 && (defined(MOZ_OMX_DECODER) || defined(MOZ_B2G_CAMERA))
882 android::FakeSurfaceComposer::instantiate();
884 GonkPermissionService::instantiate();
886 // Causes the kernel timezone to be set, which in turn causes the
887 // timestamps on SD cards to have the local time rather than UTC time.
888 hal::SetTimezone(hal::GetTimezone());
891 nsCOMPtr
<nsIObserverService
> obsServ
= GetObserverService();
893 obsServ
->AddObserver(this, "browser-ui-startup-complete", false);
894 obsServ
->AddObserver(this, "network-connection-state-changed", false);
897 #ifdef MOZ_NUWA_PROCESS
898 // Make sure main thread was woken up after Nuwa fork.
899 NuwaAddConstructor((void (*)(void *))&NotifyEvent
, nullptr);
902 // Delay initializing input devices until the screen has been
903 // initialized (and we know the resolution).
908 nsAppShell::Observe(nsISupports
* aSubject
,
910 const char16_t
* aData
)
912 if (!strcmp(aTopic
, "network-connection-state-changed")) {
913 NS_ConvertUTF16toUTF8
type(aData
);
914 if (!type
.IsEmpty()) {
915 hal::NotifyNetworkChange(hal::NetworkInformation(atoi(type
.get()), 0, 0));
918 } else if (!strcmp(aTopic
, "browser-ui-startup-complete")) {
919 if (sDevInputAudioJack
) {
920 sHeadphoneState
= mReader
->getSwitchState(-1, AINPUT_SOURCE_SWITCH
, SW_HEADPHONE_INSERT
);
921 sMicrophoneState
= mReader
->getSwitchState(-1, AINPUT_SOURCE_SWITCH
, SW_MICROPHONE_INSERT
);
922 updateHeadphoneSwitch();
929 return nsBaseAppShell::Observe(aSubject
, aTopic
, aData
);
935 OrientationObserver::ShutDown();
936 nsCOMPtr
<nsIObserverService
> obsServ
= GetObserverService();
938 obsServ
->RemoveObserver(this, "browser-ui-startup-complete");
939 obsServ
->RemoveObserver(this, "network-connection-state-changed");
941 return nsBaseAppShell::Exit();
945 nsAppShell::InitInputDevices()
947 sDevInputAudioJack
= hal::IsHeadphoneEventFromInputDev();
948 sHeadphoneState
= AKEY_STATE_UNKNOWN
;
949 sMicrophoneState
= AKEY_STATE_UNKNOWN
;
951 mEventHub
= new EventHub();
952 mReaderPolicy
= new GeckoInputReaderPolicy();
953 mReaderPolicy
->setDisplayInfo();
954 mDispatcher
= new GeckoInputDispatcher(mEventHub
);
956 mReader
= new InputReader(mEventHub
, mReaderPolicy
, mDispatcher
);
957 mReaderThread
= new InputReaderThread(mReader
);
959 status_t result
= mReaderThread
->run("InputReader", PRIORITY_URGENT_DISPLAY
);
961 LOG("Failed to initialize InputReader thread, bad things are going to happen...");
966 nsAppShell::AddFdHandler(int fd
, FdHandlerCallback handlerFunc
,
967 const char* deviceName
)
969 epoll_event event
= {
974 FdHandler
*handler
= mHandlers
.AppendElement();
976 strncpy(handler
->name
, deviceName
, sizeof(handler
->name
) - 1);
977 handler
->func
= handlerFunc
;
978 event
.data
.u32
= mHandlers
.Length() - 1;
979 return epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fd
, &event
) ?
980 NS_ERROR_UNEXPECTED
: NS_OK
;
984 nsAppShell::ScheduleNativeEventCallback()
986 mNativeCallbackRequest
= true;
991 nsAppShell::ProcessNextNativeEvent(bool mayWait
)
993 PROFILER_LABEL("nsAppShell", "ProcessNextNativeEvent",
994 js::ProfileEntry::Category::EVENTS
);
996 epoll_event events
[16] = {{ 0 }};
1000 PROFILER_LABEL("nsAppShell", "ProcessNextNativeEvent::Wait",
1001 js::ProfileEntry::Category::EVENTS
);
1003 if ((event_count
= epoll_wait(epollfd
, events
, 16, mayWait
? -1 : 0)) <= 0)
1007 for (int i
= 0; i
< event_count
; i
++)
1008 mHandlers
[events
[i
].data
.u32
].run();
1010 if (mDispatcher
.get())
1011 mDispatcher
->dispatchOnce();
1013 // NativeEventCallback always schedules more if it needs it
1014 // so we can coalesce these.
1015 // See the implementation in nsBaseAppShell.cpp for more info
1016 if (mNativeCallbackRequest
) {
1017 mNativeCallbackRequest
= false;
1018 NativeEventCallback();
1021 if (gDrawRequest
&& mEnableDraw
) {
1022 gDrawRequest
= false;
1030 nsAppShell::NotifyNativeEvent()
1032 write(signalfds
[1], "w", 1);
1036 nsAppShell::NotifyScreenInitialized()
1038 gAppShell
->InitInputDevices();
1040 // Getting the instance of OrientationObserver to initialize it.
1041 OrientationObserver::GetInstance();
1045 nsAppShell::NotifyScreenRotation()
1047 gAppShell
->mReaderPolicy
->setDisplayInfo();
1048 gAppShell
->mReader
->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO
);
1050 hal::NotifyScreenConfigurationChange(nsScreenGonk::GetConfiguration());