Bumping manifests a=b2g-bump
[gecko.git] / widget / gonk / nsAppShell.cpp
blobacc588ac2456759dc25639066b8a03bcc58b9666
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.
18 #ifndef _GNU_SOURCE
19 #define _GNU_SOURCE
20 #endif
22 #include <dirent.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <hardware_legacy/power.h>
26 #include <signal.h>
27 #include <sys/epoll.h>
28 #include <sys/ioctl.h>
29 #include <sys/param.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <utils/BitSet.h>
35 #include "base/basictypes.h"
36 #include "GonkPermission.h"
37 #include "nscore.h"
38 #ifdef MOZ_OMX_DECODER
39 #include "MediaResourceManagerService.h"
40 #endif
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"
50 #endif
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"
58 #include "nsWindow.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
68 #include "ipc/Nuwa.h"
69 #endif
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)
84 #else
85 # define VERBOSE_LOG(args...) \
86 (void)0
87 #endif
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)
109 static uint64_t
110 nanosecsToMillisecs(nsecs_t nsecs)
112 return nsecs / 1000000;
115 namespace mozilla {
117 bool ProcessNextEvent()
119 return gAppShell->ProcessNextNativeEvent(true);
122 void NotifyEvent()
124 gAppShell->NotifyNativeEvent();
127 } // namespace mozilla
129 static void
130 pipeHandler(int fd, FdHandler *data)
132 ssize_t len;
133 do {
134 char tmp[32];
135 len = read(fd, tmp, sizeof(tmp));
136 } while (len > 0);
139 struct Touch {
140 int32_t id;
141 PointerCoords coords;
144 struct UserInputData {
145 uint64_t timeMs;
146 enum {
147 MOTION_DATA,
148 KEY_DATA
149 } type;
150 int32_t action;
151 int32_t flags;
152 int32_t metaState;
153 int32_t deviceId;
154 union {
155 struct {
156 int32_t keyCode;
157 int32_t scanCode;
158 } key;
159 struct {
160 int32_t touchCount;
161 ::Touch touches[MAX_POINTERS];
162 } motion;
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;
197 return result;
200 class MOZ_STACK_CLASS KeyEventDispatcher
202 public:
203 KeyEventDispatcher(const UserInputData& aData,
204 KeyCharacterMap* aKeyCharMap);
205 void Dispatch();
207 private:
208 const UserInputData& mData;
209 sp<KeyCharacterMap> mKeyCharMap;
211 char16_t mChar;
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
254 // input character.
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()) {
261 return;
264 mChar = mKeyCharMap->getCharacter(mData.key.keyCode, mData.metaState);
265 if (IsControlChar(mChar)) {
266 mChar = 0;
268 int32_t unmodifiedMetaState = UnmodifiedMetaState();
269 if (mData.metaState == unmodifiedMetaState) {
270 mUnmodifiedChar = mChar;
271 } else {
272 mUnmodifiedChar = mKeyCharMap->getCharacter(mData.key.keyCode,
273 unmodifiedMetaState);
274 if (IsControlChar(mUnmodifiedChar)) {
275 mUnmodifiedChar = 0;
279 mDOMPrintableKeyValue = PrintableKeyValue();
282 char16_t
283 KeyEventDispatcher::PrintableKeyValue() const
285 if (mDOMKeyNameIndex != KEY_NAME_INDEX_USE_STRING) {
286 return 0;
288 return mChar ? mChar : mUnmodifiedChar;
291 nsEventStatus
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);
316 void
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
321 // as so.
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());
326 return;
329 if (IsKeyPress()) {
330 DispatchKeyDownEvent();
331 } else {
332 DispatchKeyUpEvent();
336 void
337 KeyEventDispatcher::DispatchKeyDownEvent()
339 nsEventStatus status = DispatchKeyEventInternal(NS_KEY_DOWN);
340 if (status != nsEventStatus_eConsumeNoDefault) {
341 DispatchKeyEventInternal(NS_KEY_PRESS);
345 void
346 KeyEventDispatcher::DispatchKeyUpEvent()
348 DispatchKeyEventInternal(NS_KEY_UP);
351 class SwitchEventRunnable : public nsRunnable {
352 public:
353 SwitchEventRunnable(hal::SwitchEvent& aEvent) : mEvent(aEvent)
356 NS_IMETHOD Run()
358 hal::NotifySwitchStateFromInputDevice(mEvent.device(),
359 mEvent.status());
360 return NS_OK;
362 private:
363 hal::SwitchEvent mEvent;
366 static void
367 updateHeadphoneSwitch()
369 hal::SwitchEvent event;
371 switch (sHeadphoneState) {
372 case AKEY_STATE_UP:
373 event.status() = hal::SWITCH_STATE_OFF;
374 break;
375 case AKEY_STATE_DOWN:
376 event.status() = sMicrophoneState == AKEY_STATE_DOWN ?
377 hal::SWITCH_STATE_HEADSET : hal::SWITCH_STATE_HEADPHONE;
378 break;
379 default:
380 return;
383 event.device() = hal::SWITCH_HEADPHONES;
384 NS_DispatchToMainThread(new SwitchEventRunnable(event));
387 class GeckoPointerController : public PointerControllerInterface {
388 float mX;
389 float mY;
390 int32_t mButtonState;
391 InputReaderConfiguration* mConfig;
392 public:
393 GeckoPointerController(InputReaderConfiguration* config)
394 : mX(0)
395 , mY(0)
396 , mButtonState(0)
397 , mConfig(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() {}
415 bool
416 GeckoPointerController::getBounds(float* outMinX,
417 float* outMinY,
418 float* outMaxX,
419 float* outMaxY) const
421 DisplayViewport viewport;
423 mConfig->getDisplayInfo(false, &viewport);
425 *outMinX = *outMinY = 0;
426 *outMaxX = viewport.logicalRight;
427 *outMaxY = viewport.logicalBottom;
428 return true;
431 void
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);
441 void
442 GeckoPointerController::setButtonState(int32_t buttonState)
444 mButtonState = buttonState;
447 int32_t
448 GeckoPointerController::getButtonState() const
450 return mButtonState;
453 void
454 GeckoPointerController::setPosition(float x, float y)
456 mX = x;
457 mY = y;
460 void
461 GeckoPointerController::getPosition(float* outX, float* outY) const
463 *outX = mX;
464 *outY = mY;
467 class GeckoInputReaderPolicy : public InputReaderPolicyInterface {
468 InputReaderConfiguration mConfig;
469 public:
470 GeckoInputReaderPolicy() {}
472 virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
473 virtual sp<PointerControllerInterface> obtainPointerController(int32_t
474 deviceId)
476 return new GeckoPointerController(&mConfig);
478 virtual void notifyInputDevicesChanged(const android::Vector<InputDeviceInfo>& inputDevices) {};
479 virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor)
481 return nullptr;
483 virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier)
485 return String8::empty();
488 void setDisplayInfo();
490 protected:
491 virtual ~GeckoInputReaderPolicy() {}
494 class GeckoInputDispatcher : public InputDispatcherInterface {
495 public:
496 GeckoInputDispatcher(sp<EventHub> &aEventHub)
497 : mQueueLock("GeckoInputDispatcher::mQueueMutex")
498 , mEventHub(aEventHub)
499 , mKeyDownCount(0)
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);
538 protected:
539 virtual ~GeckoInputDispatcher() { }
541 private:
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;
550 int mKeyDownCount;
551 bool mKeyEventsFiltered;
552 bool mPowerWakelock;
555 // GeckoInputReaderPolicy
556 void
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;
581 } else {
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
595 void
596 GeckoInputDispatcher::dump(String8& dump)
600 static bool
601 isExpired(const UserInputData& data)
603 uint64_t timeNowMs =
604 nanosecsToMillisecs(systemTime(SYSTEM_TIME_MONOTONIC));
605 return (timeNowMs - data.timeMs) > kInputExpirationThresholdMs;
608 void
609 GeckoInputDispatcher::dispatchOnce()
611 UserInputData data;
613 MutexAutoLock lock(mQueueLock);
614 if (mEventQueue.empty())
615 return;
616 data = mEventQueue.front();
617 mEventQueue.pop();
618 if (!mEventQueue.empty())
619 gAppShell->NotifyNativeEvent();
622 switch (data.type) {
623 case UserInputData::MOTION_DATA: {
624 MOZ_ASSERT_UNREACHABLE("Should not dispatch touch events here anymore");
625 break;
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) {
635 return;
638 sp<KeyCharacterMap> kcm = mEventHub->getKeyCharacterMap(data.deviceId);
639 KeyEventDispatcher dispatcher(data, kcm.get());
640 dispatcher.Dispatch();
641 break;
644 MutexAutoLock lock(mQueueLock);
645 if (mPowerWakelock && mEventQueue.empty()) {
646 release_wake_lock(kKey_WAKE_LOCK_ID);
647 mPowerWakelock = false;
651 void
652 GeckoInputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs*)
656 void
657 GeckoInputDispatcher::notifyKey(const NotifyKeyArgs* args)
659 UserInputData data;
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) {
672 mPowerWakelock =
673 acquire_wake_lock(PARTIAL_WAKE_LOCK, kKey_WAKE_LOCK_ID);
676 gAppShell->NotifyNativeEvent();
679 static void
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) {
690 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;
697 rotationAngle += 90;
698 } else {
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);
712 void
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;
723 switch (action) {
724 case AMOTION_EVENT_ACTION_DOWN:
725 case AMOTION_EVENT_ACTION_POINTER_DOWN:
726 touchType = MultiTouchInput::MULTITOUCH_START;
727 break;
728 case AMOTION_EVENT_ACTION_MOVE:
729 touchType = MultiTouchInput::MULTITOUCH_MOVE;
730 break;
731 case AMOTION_EVENT_ACTION_UP:
732 case AMOTION_EVENT_ACTION_POINTER_UP:
733 touchType = MultiTouchInput::MULTITOUCH_END;
734 break;
735 case AMOTION_EVENT_ACTION_OUTSIDE:
736 case AMOTION_EVENT_ACTION_CANCEL:
737 touchType = MultiTouchInput::MULTITOUCH_CANCEL;
738 break;
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");
743 return;
744 default:
745 MOZ_ASSERT_UNREACHABLE("Could not assign a touch type");
746 break;
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);
758 } else {
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)
770 return;
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;
802 void
803 GeckoInputDispatcher::setInputWindows(const android::Vector<sp<InputWindowHandle> >& inputWindowHandles)
807 void
808 GeckoInputDispatcher::setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle)
812 void
813 GeckoInputDispatcher::setInputDispatchMode(bool enabled, bool frozen)
817 status_t
818 GeckoInputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
819 const sp<InputWindowHandle>& inputWindowHandle, bool monitor)
821 return OK;
824 status_t
825 GeckoInputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel)
827 return OK;
830 nsAppShell::nsAppShell()
831 : mNativeCallbackRequest(false)
832 , mEnableDraw(false)
833 , mHandlers()
835 gAppShell = this;
838 nsAppShell::~nsAppShell()
840 // mReaderThread and mEventHub will both be null if InitInputDevices
841 // is not called.
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();
846 mEventHub->wake();
848 status_t result = mReaderThread->requestExitAndWait();
849 if (result)
850 LOG("Could not stop reader thread - %d", result);
852 gAppShell = nullptr;
855 nsresult
856 nsAppShell::Init()
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");
874 printf("***\n");
875 printf("*** This is stdout. Most of the useful output will be in logcat.\n");
876 printf("***\n");
877 printf("*****************************************************************\n");
878 #ifdef MOZ_OMX_DECODER
879 android::MediaResourceManagerService::instantiate();
880 #endif
881 #if ANDROID_VERSION >= 18 && (defined(MOZ_OMX_DECODER) || defined(MOZ_B2G_CAMERA))
882 android::FakeSurfaceComposer::instantiate();
883 #endif
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();
892 if (obsServ) {
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);
900 #endif
902 // Delay initializing input devices until the screen has been
903 // initialized (and we know the resolution).
904 return rv;
907 NS_IMETHODIMP
908 nsAppShell::Observe(nsISupports* aSubject,
909 const char* aTopic,
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));
917 return NS_OK;
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();
924 mEnableDraw = true;
925 NotifyEvent();
926 return NS_OK;
929 return nsBaseAppShell::Observe(aSubject, aTopic, aData);
932 NS_IMETHODIMP
933 nsAppShell::Exit()
935 OrientationObserver::ShutDown();
936 nsCOMPtr<nsIObserverService> obsServ = GetObserverService();
937 if (obsServ) {
938 obsServ->RemoveObserver(this, "browser-ui-startup-complete");
939 obsServ->RemoveObserver(this, "network-connection-state-changed");
941 return nsBaseAppShell::Exit();
944 void
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);
960 if (result) {
961 LOG("Failed to initialize InputReader thread, bad things are going to happen...");
965 nsresult
966 nsAppShell::AddFdHandler(int fd, FdHandlerCallback handlerFunc,
967 const char* deviceName)
969 epoll_event event = {
970 EPOLLIN,
971 { 0 }
974 FdHandler *handler = mHandlers.AppendElement();
975 handler->fd = fd;
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;
983 void
984 nsAppShell::ScheduleNativeEventCallback()
986 mNativeCallbackRequest = true;
987 NotifyEvent();
990 bool
991 nsAppShell::ProcessNextNativeEvent(bool mayWait)
993 PROFILER_LABEL("nsAppShell", "ProcessNextNativeEvent",
994 js::ProfileEntry::Category::EVENTS);
996 epoll_event events[16] = {{ 0 }};
998 int event_count;
1000 PROFILER_LABEL("nsAppShell", "ProcessNextNativeEvent::Wait",
1001 js::ProfileEntry::Category::EVENTS);
1003 if ((event_count = epoll_wait(epollfd, events, 16, mayWait ? -1 : 0)) <= 0)
1004 return true;
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;
1023 nsWindow::DoDraw();
1026 return true;
1029 void
1030 nsAppShell::NotifyNativeEvent()
1032 write(signalfds[1], "w", 1);
1035 /* static */ void
1036 nsAppShell::NotifyScreenInitialized()
1038 gAppShell->InitInputDevices();
1040 // Getting the instance of OrientationObserver to initialize it.
1041 OrientationObserver::GetInstance();
1044 /* static */ void
1045 nsAppShell::NotifyScreenRotation()
1047 gAppShell->mReaderPolicy->setDisplayInfo();
1048 gAppShell->mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
1050 hal::NotifyScreenConfigurationChange(nsScreenGonk::GetConfiguration());