widget/gonk/nsAppShell.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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
     4  *
     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
     8  *
     9  *     http://www.apache.org/licenses/LICENSE-2.0
    10  *
    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.
    16  */
    18 #ifndef _GNU_SOURCE
    19 #define _GNU_SOURCE
    20 #endif
    22 #include <dirent.h>
    23 #include <errno.h>
    24 #include <fcntl.h>
    25 #include <signal.h>
    26 #include <sys/epoll.h>
    27 #include <sys/ioctl.h>
    28 #include <sys/param.h>
    29 #include <sys/stat.h>
    30 #include <sys/types.h>
    31 #include <unistd.h>
    32 #include <utils/BitSet.h>
    34 #include "base/basictypes.h"
    35 #include "GonkPermission.h"
    36 #include "nscore.h"
    37 #ifdef MOZ_OMX_DECODER
    38 #include "MediaResourceManagerService.h"
    39 #endif
    40 #include "mozilla/TouchEvents.h"
    41 #include "mozilla/FileUtils.h"
    42 #include "mozilla/Hal.h"
    43 #include "mozilla/MouseEvents.h"
    44 #include "mozilla/Mutex.h"
    45 #include "mozilla/Services.h"
    46 #include "mozilla/TextEvents.h"
    47 #if ANDROID_VERSION >= 18
    48 #include "nativewindow/FakeSurfaceComposer.h"
    49 #endif
    50 #include "nsAppShell.h"
    51 #include "mozilla/dom/Touch.h"
    52 #include "nsGkAtoms.h"
    53 #include "nsIObserverService.h"
    54 #include "nsIScreen.h"
    55 #include "nsScreenManagerGonk.h"
    56 #include "nsThreadUtils.h"
    57 #include "nsWindow.h"
    58 #include "OrientationObserver.h"
    59 #include "GonkMemoryPressureMonitoring.h"
    61 #include "android/log.h"
    62 #include "libui/EventHub.h"
    63 #include "libui/InputReader.h"
    64 #include "libui/InputDispatcher.h"
    65 #include "cutils/properties.h"
    67 #ifdef MOZ_NUWA_PROCESS
    68 #include "ipc/Nuwa.h"
    69 #endif
    71 #include "GeckoProfiler.h"
    73 // Defines kKeyMapping and GetKeyNameIndex()
    74 #include "GonkKeyMapping.h"
    76 #define LOG(args...)                                            \
    77     __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
    78 #ifdef VERBOSE_LOG_ENABLED
    79 # define VERBOSE_LOG(args...)                           \
    80     __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
    81 #else
    82 # define VERBOSE_LOG(args...)                   \
    83     (void)0
    84 #endif
    86 using namespace android;
    87 using namespace mozilla;
    88 using namespace mozilla::dom;
    89 using namespace mozilla::services;
    90 using namespace mozilla::widget;
    92 bool gDrawRequest = false;
    93 static nsAppShell *gAppShell = nullptr;
    94 static int epollfd = 0;
    95 static int signalfds[2] = {0};
    96 static bool sDevInputAudioJack;
    97 static int32_t sHeadphoneState;
    98 static int32_t sMicrophoneState;
   100 // Amount of time in MS before an input is considered expired.
   101 static const uint64_t kInputExpirationThresholdMs = 1000;
   103 NS_IMPL_ISUPPORTS_INHERITED(nsAppShell, nsBaseAppShell, nsIObserver)
   105 static uint64_t
   106 nanosecsToMillisecs(nsecs_t nsecs)
   107 {
   108     return nsecs / 1000000;
   109 }
   111 namespace mozilla {
   113 bool ProcessNextEvent()
   114 {
   115     return gAppShell->ProcessNextNativeEvent(true);
   116 }
   118 void NotifyEvent()
   119 {
   120     gAppShell->NotifyNativeEvent();
   121 }
   123 } // namespace mozilla
   125 static void
   126 pipeHandler(int fd, FdHandler *data)
   127 {
   128     ssize_t len;
   129     do {
   130         char tmp[32];
   131         len = read(fd, tmp, sizeof(tmp));
   132     } while (len > 0);
   133 }
   135 struct Touch {
   136     int32_t id;
   137     PointerCoords coords;
   138 };
   140 struct UserInputData {
   141     uint64_t timeMs;
   142     enum {
   143         MOTION_DATA,
   144         KEY_DATA
   145     } type;
   146     int32_t action;
   147     int32_t flags;
   148     int32_t metaState;
   149     int32_t deviceId;
   150     union {
   151         struct {
   152             int32_t keyCode;
   153             int32_t scanCode;
   154         } key;
   155         struct {
   156             int32_t touchCount;
   157             ::Touch touches[MAX_POINTERS];
   158         } motion;
   159     };
   161     Modifiers DOMModifiers() const;
   162 };
   164 Modifiers
   165 UserInputData::DOMModifiers() const
   166 {
   167     Modifiers result = 0;
   168     if (metaState & (AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
   169         result |= MODIFIER_ALT;
   170     }
   171     if (metaState & (AMETA_SHIFT_ON |
   172                      AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
   173         result |= MODIFIER_SHIFT;
   174     }
   175     if (metaState & AMETA_FUNCTION_ON) {
   176         result |= MODIFIER_FN;
   177     }
   178     if (metaState & (AMETA_CTRL_ON |
   179                      AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
   180         result |= MODIFIER_CONTROL;
   181     }
   182     if (metaState & (AMETA_META_ON |
   183                      AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
   184         result |= MODIFIER_META;
   185     }
   186     if (metaState & AMETA_CAPS_LOCK_ON) {
   187         result |= MODIFIER_CAPSLOCK;
   188     }
   189     if (metaState & AMETA_NUM_LOCK_ON) {
   190         result |= MODIFIER_NUMLOCK;
   191     }
   192     if (metaState & AMETA_SCROLL_LOCK_ON) {
   193         result |= MODIFIER_SCROLLLOCK;
   194     }
   195     return result;
   196 }
   198 static void
   199 sendMouseEvent(uint32_t msg, UserInputData& data, bool forwardToChildren)
   200 {
   201     WidgetMouseEvent event(true, msg, nullptr,
   202                            WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
   204     event.refPoint.x = data.motion.touches[0].coords.getX();
   205     event.refPoint.y = data.motion.touches[0].coords.getY();
   206     event.time = data.timeMs;
   207     event.button = WidgetMouseEvent::eLeftButton;
   208     event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
   209     if (msg != NS_MOUSE_MOVE)
   210         event.clickCount = 1;
   211     event.modifiers = data.DOMModifiers();
   213     event.mFlags.mNoCrossProcessBoundaryForwarding = !forwardToChildren;
   215     nsWindow::DispatchInputEvent(event);
   216 }
   218 static void
   219 addDOMTouch(UserInputData& data, WidgetTouchEvent& event, int i)
   220 {
   221     const ::Touch& touch = data.motion.touches[i];
   222     event.touches.AppendElement(
   223         new dom::Touch(touch.id,
   224                        nsIntPoint(floor(touch.coords.getX() + 0.5), floor(touch.coords.getY() + 0.5)),
   225                        nsIntPoint(touch.coords.getAxisValue(AMOTION_EVENT_AXIS_SIZE),
   226                                   touch.coords.getAxisValue(AMOTION_EVENT_AXIS_SIZE)),
   227                        0,
   228                        touch.coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE))
   229     );
   230 }
   232 static nsEventStatus
   233 sendTouchEvent(UserInputData& data, bool* captured)
   234 {
   235     uint32_t msg;
   236     int32_t action = data.action & AMOTION_EVENT_ACTION_MASK;
   237     switch (action) {
   238     case AMOTION_EVENT_ACTION_DOWN:
   239     case AMOTION_EVENT_ACTION_POINTER_DOWN:
   240         msg = NS_TOUCH_START;
   241         break;
   242     case AMOTION_EVENT_ACTION_MOVE:
   243         msg = NS_TOUCH_MOVE;
   244         break;
   245     case AMOTION_EVENT_ACTION_UP:
   246     case AMOTION_EVENT_ACTION_POINTER_UP:
   247         msg = NS_TOUCH_END;
   248         break;
   249     case AMOTION_EVENT_ACTION_OUTSIDE:
   250     case AMOTION_EVENT_ACTION_CANCEL:
   251         msg = NS_TOUCH_CANCEL;
   252         break;
   253     default:
   254         msg = NS_EVENT_NULL;
   255         break;
   256     }
   258     WidgetTouchEvent event(true, msg, nullptr);
   260     event.time = data.timeMs;
   261     event.modifiers = data.DOMModifiers();
   263     int32_t i;
   264     if (msg == NS_TOUCH_END) {
   265         i = data.action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK;
   266         i >>= AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
   267         addDOMTouch(data, event, i);
   268     } else {
   269         for (i = 0; i < data.motion.touchCount; ++i)
   270             addDOMTouch(data, event, i);
   271     }
   273     return nsWindow::DispatchInputEvent(event, captured);
   274 }
   276 class MOZ_STACK_CLASS KeyEventDispatcher
   277 {
   278 public:
   279     KeyEventDispatcher(const UserInputData& aData,
   280                        KeyCharacterMap* aKeyCharMap);
   281     void Dispatch();
   283 private:
   284     const UserInputData& mData;
   285     sp<KeyCharacterMap> mKeyCharMap;
   287     char16_t mChar;
   288     char16_t mUnmodifiedChar;
   290     uint32_t mDOMKeyCode;
   291     KeyNameIndex mDOMKeyNameIndex;
   292     char16_t mDOMPrintableKeyValue;
   294     bool IsKeyPress() const
   295     {
   296         return mData.action == AKEY_EVENT_ACTION_DOWN;
   297     }
   298     bool IsRepeat() const
   299     {
   300         return IsKeyPress() && (mData.flags & AKEY_EVENT_FLAG_LONG_PRESS);
   301     }
   303     char16_t PrintableKeyValue() const;
   305     int32_t UnmodifiedMetaState() const
   306     {
   307         return mData.metaState &
   308             ~(AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON |
   309               AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON |
   310               AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
   311     }
   313     static bool IsControlChar(char16_t aChar)
   314     {
   315         return (aChar < ' ' || aChar == 0x7F);
   316     }
   318     void DispatchKeyDownEvent();
   319     void DispatchKeyUpEvent();
   320     nsEventStatus DispatchKeyEventInternal(uint32_t aEventMessage);
   321 };
   323 KeyEventDispatcher::KeyEventDispatcher(const UserInputData& aData,
   324                                        KeyCharacterMap* aKeyCharMap) :
   325     mData(aData), mKeyCharMap(aKeyCharMap), mChar(0), mUnmodifiedChar(0),
   326     mDOMPrintableKeyValue(0)
   327 {
   328     // XXX Printable key's keyCode value should be computed with actual
   329     //     input character.
   330     mDOMKeyCode = (mData.key.keyCode < (ssize_t)ArrayLength(kKeyMapping)) ?
   331         kKeyMapping[mData.key.keyCode] : 0;
   332     mDOMKeyNameIndex = GetKeyNameIndex(mData.key.keyCode);
   334     if (!mKeyCharMap.get()) {
   335         return;
   336     }
   338     mChar = mKeyCharMap->getCharacter(mData.key.keyCode, mData.metaState);
   339     if (IsControlChar(mChar)) {
   340         mChar = 0;
   341     }
   342     int32_t unmodifiedMetaState = UnmodifiedMetaState();
   343     if (mData.metaState == unmodifiedMetaState) {
   344         mUnmodifiedChar = mChar;
   345     } else {
   346         mUnmodifiedChar = mKeyCharMap->getCharacter(mData.key.keyCode,
   347                                                     unmodifiedMetaState);
   348         if (IsControlChar(mUnmodifiedChar)) {
   349             mUnmodifiedChar = 0;
   350         }
   351     }
   353     mDOMPrintableKeyValue = PrintableKeyValue();
   354 }
   356 char16_t
   357 KeyEventDispatcher::PrintableKeyValue() const
   358 {
   359     if (mDOMKeyNameIndex != KEY_NAME_INDEX_USE_STRING) {
   360         return 0;
   361     }
   362     return mChar ? mChar : mUnmodifiedChar;
   363 }
   365 nsEventStatus
   366 KeyEventDispatcher::DispatchKeyEventInternal(uint32_t aEventMessage)
   367 {
   368     WidgetKeyboardEvent event(true, aEventMessage, nullptr);
   369     if (aEventMessage == NS_KEY_PRESS) {
   370         // XXX If the charCode is not a printable character, the charCode
   371         //     should be computed without Ctrl/Alt/Meta modifiers.
   372         event.charCode = static_cast<uint32_t>(mChar);
   373     }
   374     if (!event.charCode) {
   375         event.keyCode = mDOMKeyCode;
   376     }
   377     event.isChar = !!event.charCode;
   378     event.mIsRepeat = IsRepeat();
   379     event.mKeyNameIndex = mDOMKeyNameIndex;
   380     if (mDOMPrintableKeyValue) {
   381         event.mKeyValue = mDOMPrintableKeyValue;
   382     }
   383     event.modifiers = mData.DOMModifiers();
   384     event.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_MOBILE;
   385     event.time = mData.timeMs;
   386     return nsWindow::DispatchInputEvent(event);
   387 }
   389 void
   390 KeyEventDispatcher::Dispatch()
   391 {
   392     // XXX Even if unknown key is pressed, DOM key event should be
   393     //     dispatched since Gecko for the other platforms are implemented
   394     //     as so.
   395     if (!mDOMKeyCode && mDOMKeyNameIndex == KEY_NAME_INDEX_Unidentified) {
   396         VERBOSE_LOG("Got unknown key event code. "
   397                     "type 0x%04x code 0x%04x value %d",
   398                     mData.action, mData.key.keyCode, IsKeyPress());
   399         return;
   400     }
   402     if (IsKeyPress()) {
   403         DispatchKeyDownEvent();
   404     } else {
   405         DispatchKeyUpEvent();
   406     }
   407 }
   409 void
   410 KeyEventDispatcher::DispatchKeyDownEvent()
   411 {
   412     nsEventStatus status = DispatchKeyEventInternal(NS_KEY_DOWN);
   413     if (status != nsEventStatus_eConsumeNoDefault) {
   414         DispatchKeyEventInternal(NS_KEY_PRESS);
   415     }
   416 }
   418 void
   419 KeyEventDispatcher::DispatchKeyUpEvent()
   420 {
   421     DispatchKeyEventInternal(NS_KEY_UP);
   422 }
   424 class SwitchEventRunnable : public nsRunnable {
   425 public:
   426     SwitchEventRunnable(hal::SwitchEvent& aEvent) : mEvent(aEvent)
   427     {}
   429     NS_IMETHOD Run()
   430     {
   431         hal::NotifySwitchStateFromInputDevice(mEvent.device(),
   432           mEvent.status());
   433         return NS_OK;
   434     }
   435 private:
   436     hal::SwitchEvent mEvent;
   437 };
   439 static void
   440 updateHeadphoneSwitch()
   441 {
   442     hal::SwitchEvent event;
   444     switch (sHeadphoneState) {
   445     case AKEY_STATE_UP:
   446         event.status() = hal::SWITCH_STATE_OFF;
   447         break;
   448     case AKEY_STATE_DOWN:
   449         event.status() = sMicrophoneState == AKEY_STATE_DOWN ?
   450             hal::SWITCH_STATE_HEADSET : hal::SWITCH_STATE_HEADPHONE;
   451         break;
   452     default:
   453         return;
   454     }
   456     event.device() = hal::SWITCH_HEADPHONES;
   457     NS_DispatchToMainThread(new SwitchEventRunnable(event));
   458 }
   460 class GeckoPointerController : public PointerControllerInterface {
   461     float mX;
   462     float mY;
   463     int32_t mButtonState;
   464     InputReaderConfiguration* mConfig;
   465 public:
   466     GeckoPointerController(InputReaderConfiguration* config)
   467         : mX(0)
   468         , mY(0)
   469         , mButtonState(0)
   470         , mConfig(config)
   471     {}
   473     virtual bool getBounds(float* outMinX, float* outMinY,
   474             float* outMaxX, float* outMaxY) const;
   475     virtual void move(float deltaX, float deltaY);
   476     virtual void setButtonState(int32_t buttonState);
   477     virtual int32_t getButtonState() const;
   478     virtual void setPosition(float x, float y);
   479     virtual void getPosition(float* outX, float* outY) const;
   480     virtual void fade(Transition transition) {}
   481     virtual void unfade(Transition transition) {}
   482     virtual void setPresentation(Presentation presentation) {}
   483     virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
   484             BitSet32 spotIdBits) {}
   485     virtual void clearSpots() {}
   486 };
   488 bool
   489 GeckoPointerController::getBounds(float* outMinX,
   490                                   float* outMinY,
   491                                   float* outMaxX,
   492                                   float* outMaxY) const
   493 {
   494     DisplayViewport viewport;
   496     mConfig->getDisplayInfo(false, &viewport);
   498     *outMinX = *outMinY = 0;
   499     *outMaxX = viewport.logicalRight;
   500     *outMaxY = viewport.logicalBottom;
   501     return true;
   502 }
   504 void
   505 GeckoPointerController::move(float deltaX, float deltaY)
   506 {
   507     float minX, minY, maxX, maxY;
   508     getBounds(&minX, &minY, &maxX, &maxY);
   510     mX = clamped(mX + deltaX, minX, maxX);
   511     mY = clamped(mY + deltaY, minY, maxY);
   512 }
   514 void
   515 GeckoPointerController::setButtonState(int32_t buttonState)
   516 {
   517     mButtonState = buttonState;
   518 }
   520 int32_t
   521 GeckoPointerController::getButtonState() const
   522 {
   523     return mButtonState;
   524 }
   526 void
   527 GeckoPointerController::setPosition(float x, float y)
   528 {
   529     mX = x;
   530     mY = y;
   531 }
   533 void
   534 GeckoPointerController::getPosition(float* outX, float* outY) const
   535 {
   536     *outX = mX;
   537     *outY = mY;
   538 }
   540 class GeckoInputReaderPolicy : public InputReaderPolicyInterface {
   541     InputReaderConfiguration mConfig;
   542 public:
   543     GeckoInputReaderPolicy() {}
   545     virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
   546     virtual sp<PointerControllerInterface> obtainPointerController(int32_t
   547 deviceId)
   548     {
   549         return new GeckoPointerController(&mConfig);
   550     };
   551     virtual void notifyInputDevicesChanged(const android::Vector<InputDeviceInfo>& inputDevices) {};
   552     virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor)
   553     {
   554         return nullptr;
   555     };
   556     virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier)
   557     {
   558         return String8::empty();
   559     };
   561     void setDisplayInfo();
   563 protected:
   564     virtual ~GeckoInputReaderPolicy() {}
   565 };
   567 class GeckoInputDispatcher : public InputDispatcherInterface {
   568 public:
   569     GeckoInputDispatcher(sp<EventHub> &aEventHub)
   570         : mQueueLock("GeckoInputDispatcher::mQueueMutex")
   571         , mEventHub(aEventHub)
   572         , mTouchDownCount(0)
   573         , mKeyDownCount(0)
   574         , mTouchEventsFiltered(false)
   575         , mKeyEventsFiltered(false)
   576     {}
   578     virtual void dump(String8& dump);
   580     virtual void monitor() {}
   582     // Called on the main thread
   583     virtual void dispatchOnce();
   585     // notify* methods are called on the InputReaderThread
   586     virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
   587     virtual void notifyKey(const NotifyKeyArgs* args);
   588     virtual void notifyMotion(const NotifyMotionArgs* args);
   589     virtual void notifySwitch(const NotifySwitchArgs* args);
   590     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
   592     virtual int32_t injectInputEvent(const InputEvent* event,
   593             int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
   594             uint32_t policyFlags);
   596     virtual void setInputWindows(const android::Vector<sp<InputWindowHandle> >& inputWindowHandles);
   597     virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle);
   599     virtual void setInputDispatchMode(bool enabled, bool frozen);
   600     virtual void setInputFilterEnabled(bool enabled) {}
   601     virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
   602             const sp<InputChannel>& toChannel) { return true; }
   604     virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
   605             const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
   606     virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
   610 protected:
   611     virtual ~GeckoInputDispatcher() {}
   613 private:
   614     // mQueueLock should generally be locked while using mEventQueue.
   615     // UserInputData is pushed on on the InputReaderThread and
   616     // popped and dispatched on the main thread.
   617     mozilla::Mutex mQueueLock;
   618     std::queue<UserInputData> mEventQueue;
   619     sp<EventHub> mEventHub;
   621     int mTouchDownCount;
   622     int mKeyDownCount;
   623     bool mTouchEventsFiltered;
   624     bool mKeyEventsFiltered;
   625     BitSet32 mTouchDown;
   626 };
   628 // GeckoInputReaderPolicy
   629 void
   630 GeckoInputReaderPolicy::setDisplayInfo()
   631 {
   632     static_assert(nsIScreen::ROTATION_0_DEG ==
   633                   DISPLAY_ORIENTATION_0,
   634                   "Orientation enums not matched!");
   635     static_assert(nsIScreen::ROTATION_90_DEG ==
   636                   DISPLAY_ORIENTATION_90,
   637                   "Orientation enums not matched!");
   638     static_assert(nsIScreen::ROTATION_180_DEG ==
   639                   DISPLAY_ORIENTATION_180,
   640                   "Orientation enums not matched!");
   641     static_assert(nsIScreen::ROTATION_270_DEG ==
   642                   DISPLAY_ORIENTATION_270,
   643                   "Orientation enums not matched!");
   645     DisplayViewport viewport;
   646     viewport.displayId = 0;
   647     viewport.orientation = nsScreenGonk::GetRotation();
   648     viewport.physicalRight = viewport.deviceWidth = gScreenBounds.width;
   649     viewport.physicalBottom = viewport.deviceHeight = gScreenBounds.height;
   650     if (viewport.orientation == DISPLAY_ORIENTATION_90 ||
   651         viewport.orientation == DISPLAY_ORIENTATION_270) {
   652         viewport.logicalRight = gScreenBounds.height;
   653         viewport.logicalBottom = gScreenBounds.width;
   654     } else {
   655         viewport.logicalRight = gScreenBounds.width;
   656         viewport.logicalBottom = gScreenBounds.height;
   657     }
   658     mConfig.setDisplayInfo(false, viewport);
   659 }
   661 void GeckoInputReaderPolicy::getReaderConfiguration(InputReaderConfiguration* outConfig)
   662 {
   663     *outConfig = mConfig;
   664 }
   667 // GeckoInputDispatcher
   668 void
   669 GeckoInputDispatcher::dump(String8& dump)
   670 {
   671 }
   673 static bool
   674 isExpired(const UserInputData& data)
   675 {
   676     uint64_t timeNowMs =
   677         nanosecsToMillisecs(systemTime(SYSTEM_TIME_MONOTONIC));
   678     return (timeNowMs - data.timeMs) > kInputExpirationThresholdMs;
   679 }
   681 void
   682 GeckoInputDispatcher::dispatchOnce()
   683 {
   684     UserInputData data;
   685     {
   686         MutexAutoLock lock(mQueueLock);
   687         if (mEventQueue.empty())
   688             return;
   689         data = mEventQueue.front();
   690         mEventQueue.pop();
   691         if (!mEventQueue.empty())
   692             gAppShell->NotifyNativeEvent();
   693     }
   695     switch (data.type) {
   696     case UserInputData::MOTION_DATA: {
   697         if (!mTouchDownCount) {
   698             // No pending events, the filter state can be updated.
   699             mTouchEventsFiltered = isExpired(data);
   700         }
   702         int32_t action = data.action & AMOTION_EVENT_ACTION_MASK;
   703         int32_t index = data.action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK;
   704         index >>= AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
   705         switch (action) {
   706         case AMOTION_EVENT_ACTION_DOWN:
   707         case AMOTION_EVENT_ACTION_POINTER_DOWN:
   708             if (!mTouchDown.hasBit(index)) {
   709                 mTouchDown.markBit(index);
   710                 mTouchDownCount++;
   711             }
   712             break;
   713         case AMOTION_EVENT_ACTION_MOVE:
   714         case AMOTION_EVENT_ACTION_HOVER_MOVE:
   715             // No need to update the count on move.
   716             break;
   717         case AMOTION_EVENT_ACTION_UP:
   718         case AMOTION_EVENT_ACTION_POINTER_UP:
   719         case AMOTION_EVENT_ACTION_OUTSIDE:
   720         case AMOTION_EVENT_ACTION_CANCEL:
   721             if (mTouchDown.hasBit(index)) {
   722                 mTouchDown.clearBit(index);
   723                 mTouchDownCount--;
   724             }
   725             break;
   726         default:
   727             break;
   728         }
   730         if (mTouchEventsFiltered) {
   731             return;
   732         }
   734         nsEventStatus status = nsEventStatus_eIgnore;
   735         if (action != AMOTION_EVENT_ACTION_HOVER_MOVE) {
   736             bool captured;
   737             status = sendTouchEvent(data, &captured);
   738             if (captured) {
   739                 return;
   740             }
   741         }
   743         uint32_t msg;
   744         switch (action) {
   745         case AMOTION_EVENT_ACTION_DOWN:
   746             msg = NS_MOUSE_BUTTON_DOWN;
   747             break;
   748         case AMOTION_EVENT_ACTION_POINTER_DOWN:
   749         case AMOTION_EVENT_ACTION_POINTER_UP:
   750         case AMOTION_EVENT_ACTION_MOVE:
   751         case AMOTION_EVENT_ACTION_HOVER_MOVE:
   752             msg = NS_MOUSE_MOVE;
   753             break;
   754         case AMOTION_EVENT_ACTION_OUTSIDE:
   755         case AMOTION_EVENT_ACTION_CANCEL:
   756         case AMOTION_EVENT_ACTION_UP:
   757             msg = NS_MOUSE_BUTTON_UP;
   758             break;
   759         default:
   760             msg = NS_EVENT_NULL;
   761             break;
   762         }
   763         if (msg != NS_EVENT_NULL) {
   764             sendMouseEvent(msg, data, 
   765                            status != nsEventStatus_eConsumeNoDefault);
   766         }
   767         break;
   768     }
   769     case UserInputData::KEY_DATA: {
   770         if (!mKeyDownCount) {
   771             // No pending events, the filter state can be updated.
   772             mKeyEventsFiltered = isExpired(data);
   773         }
   775         mKeyDownCount += (data.action == AKEY_EVENT_ACTION_DOWN) ? 1 : -1;
   776         if (mKeyEventsFiltered) {
   777             return;
   778         }
   780         sp<KeyCharacterMap> kcm = mEventHub->getKeyCharacterMap(data.deviceId);
   781         KeyEventDispatcher dispatcher(data, kcm.get());
   782         dispatcher.Dispatch();
   783         break;
   784     }
   785     }
   786 }
   788 void
   789 GeckoInputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs*)
   790 {
   791 }
   793 void
   794 GeckoInputDispatcher::notifyKey(const NotifyKeyArgs* args)
   795 {
   796     UserInputData data;
   797     data.timeMs = nanosecsToMillisecs(args->eventTime);
   798     data.type = UserInputData::KEY_DATA;
   799     data.action = args->action;
   800     data.flags = args->flags;
   801     data.metaState = args->metaState;
   802     data.deviceId = args->deviceId;
   803     data.key.keyCode = args->keyCode;
   804     data.key.scanCode = args->scanCode;
   805     {
   806         MutexAutoLock lock(mQueueLock);
   807         mEventQueue.push(data);
   808     }
   809     gAppShell->NotifyNativeEvent();
   810 }
   813 void
   814 GeckoInputDispatcher::notifyMotion(const NotifyMotionArgs* args)
   815 {
   816     UserInputData data;
   817     data.timeMs = nanosecsToMillisecs(args->eventTime);
   818     data.type = UserInputData::MOTION_DATA;
   819     data.action = args->action;
   820     data.flags = args->flags;
   821     data.metaState = args->metaState;
   822     data.deviceId = args->deviceId;
   823     MOZ_ASSERT(args->pointerCount <= MAX_POINTERS);
   824     data.motion.touchCount = args->pointerCount;
   825     for (uint32_t i = 0; i < args->pointerCount; ++i) {
   826         ::Touch& touch = data.motion.touches[i];
   827         touch.id = args->pointerProperties[i].id;
   828         memcpy(&touch.coords, &args->pointerCoords[i], sizeof(*args->pointerCoords));
   829     }
   830     {
   831         MutexAutoLock lock(mQueueLock);
   832         if (!mEventQueue.empty() &&
   833              mEventQueue.back().type == UserInputData::MOTION_DATA &&
   834            ((mEventQueue.back().action & AMOTION_EVENT_ACTION_MASK) ==
   835              AMOTION_EVENT_ACTION_MOVE ||
   836             (mEventQueue.back().action & AMOTION_EVENT_ACTION_MASK) ==
   837              AMOTION_EVENT_ACTION_HOVER_MOVE))
   838             mEventQueue.back() = data;
   839         else
   840             mEventQueue.push(data);
   841     }
   842     gAppShell->NotifyNativeEvent();
   843 }
   847 void GeckoInputDispatcher::notifySwitch(const NotifySwitchArgs* args)
   848 {
   849     if (!sDevInputAudioJack)
   850         return;
   852     bool needSwitchUpdate = false;
   854     if (args->switchMask & (1 << SW_HEADPHONE_INSERT)) {
   855         sHeadphoneState = (args->switchValues & (1 << SW_HEADPHONE_INSERT)) ?
   856                           AKEY_STATE_DOWN : AKEY_STATE_UP;
   857         needSwitchUpdate = true;
   858     }
   860     if (args->switchMask & (1 << SW_MICROPHONE_INSERT)) {
   861         sMicrophoneState = (args->switchValues & (1 << SW_MICROPHONE_INSERT)) ?
   862                            AKEY_STATE_DOWN : AKEY_STATE_UP;
   863         needSwitchUpdate = true;
   864     }
   866     if (needSwitchUpdate)
   867         updateHeadphoneSwitch();
   868 }
   870 void GeckoInputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args)
   871 {
   872 }
   874 int32_t GeckoInputDispatcher::injectInputEvent(
   875     const InputEvent* event,
   876     int32_t injectorPid, int32_t injectorUid, int32_t syncMode,
   877     int32_t timeoutMillis, uint32_t policyFlags)
   878 {
   879     return INPUT_EVENT_INJECTION_SUCCEEDED;
   880 }
   882 void
   883 GeckoInputDispatcher::setInputWindows(const android::Vector<sp<InputWindowHandle> >& inputWindowHandles)
   884 {
   885 }
   887 void
   888 GeckoInputDispatcher::setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle)
   889 {
   890 }
   892 void
   893 GeckoInputDispatcher::setInputDispatchMode(bool enabled, bool frozen)
   894 {
   895 }
   897 status_t
   898 GeckoInputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
   899                                            const sp<InputWindowHandle>& inputWindowHandle, bool monitor)
   900 {
   901     return OK;
   902 }
   904 status_t
   905 GeckoInputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel)
   906 {
   907     return OK;
   908 }
   910 nsAppShell::nsAppShell()
   911     : mNativeCallbackRequest(false)
   912     , mEnableDraw(false)
   913     , mHandlers()
   914 {
   915     gAppShell = this;
   916 }
   918 nsAppShell::~nsAppShell()
   919 {
   920     // mReaderThread and mEventHub will both be null if InitInputDevices
   921     // is not called.
   922     if (mReaderThread.get()) {
   923         // We separate requestExit() and join() here so we can wake the EventHub's
   924         // input loop, and stop it from polling for input events
   925         mReaderThread->requestExit();
   926         mEventHub->wake();
   928         status_t result = mReaderThread->requestExitAndWait();
   929         if (result)
   930             LOG("Could not stop reader thread - %d", result);
   931     }
   932     gAppShell = nullptr;
   933 }
   935 nsresult
   936 nsAppShell::Init()
   937 {
   938     nsresult rv = nsBaseAppShell::Init();
   939     NS_ENSURE_SUCCESS(rv, rv);
   941     epollfd = epoll_create(16);
   942     NS_ENSURE_TRUE(epollfd >= 0, NS_ERROR_UNEXPECTED);
   944     int ret = pipe2(signalfds, O_NONBLOCK);
   945     NS_ENSURE_FALSE(ret, NS_ERROR_UNEXPECTED);
   947     rv = AddFdHandler(signalfds[0], pipeHandler, "");
   948     NS_ENSURE_SUCCESS(rv, rv);
   950     InitGonkMemoryPressureMonitoring();
   952     if (XRE_GetProcessType() == GeckoProcessType_Default) {
   953 #ifdef MOZ_OMX_DECODER
   954         android::MediaResourceManagerService::instantiate();
   955 #endif
   956 #if ANDROID_VERSION >= 18 && (defined(MOZ_OMX_DECODER) || defined(MOZ_B2G_CAMERA))
   957         android::FakeSurfaceComposer::instantiate();
   958 #endif
   959         GonkPermissionService::instantiate();
   961         // Causes the kernel timezone to be set, which in turn causes the
   962         // timestamps on SD cards to have the local time rather than UTC time.
   963         hal::SetTimezone(hal::GetTimezone());
   964     }
   966     nsCOMPtr<nsIObserverService> obsServ = GetObserverService();
   967     if (obsServ) {
   968         obsServ->AddObserver(this, "browser-ui-startup-complete", false);
   969         obsServ->AddObserver(this, "network-connection-state-changed", false);
   970     }
   972 #ifdef MOZ_NUWA_PROCESS
   973     // Make sure main thread was woken up after Nuwa fork.
   974     NuwaAddConstructor((void (*)(void *))&NotifyEvent, nullptr);
   975 #endif
   977     // Delay initializing input devices until the screen has been
   978     // initialized (and we know the resolution).
   979     return rv;
   980 }
   982 NS_IMETHODIMP
   983 nsAppShell::Observe(nsISupports* aSubject,
   984                     const char* aTopic,
   985                     const char16_t* aData)
   986 {
   987     if (!strcmp(aTopic, "network-connection-state-changed")) {
   988         NS_ConvertUTF16toUTF8 type(aData);
   989         if (!type.IsEmpty()) {
   990             hal::NotifyNetworkChange(hal::NetworkInformation(atoi(type.get()), 0, 0));
   991         }
   992         return NS_OK;
   993     } else if (!strcmp(aTopic, "browser-ui-startup-complete")) {
   994         if (sDevInputAudioJack) {
   995             sHeadphoneState  = mReader->getSwitchState(-1, AINPUT_SOURCE_SWITCH, SW_HEADPHONE_INSERT);
   996             sMicrophoneState = mReader->getSwitchState(-1, AINPUT_SOURCE_SWITCH, SW_MICROPHONE_INSERT);
   997             updateHeadphoneSwitch();
   998         }
   999         mEnableDraw = true;
  1000         NotifyEvent();
  1001         return NS_OK;
  1004     return nsBaseAppShell::Observe(aSubject, aTopic, aData);
  1007 NS_IMETHODIMP
  1008 nsAppShell::Exit()
  1010     OrientationObserver::ShutDown();
  1011     nsCOMPtr<nsIObserverService> obsServ = GetObserverService();
  1012     if (obsServ) {
  1013         obsServ->RemoveObserver(this, "browser-ui-startup-complete");
  1014         obsServ->RemoveObserver(this, "network-connection-state-changed");
  1016     return nsBaseAppShell::Exit();
  1019 void
  1020 nsAppShell::InitInputDevices()
  1022     char value[PROPERTY_VALUE_MAX];
  1023     property_get("ro.moz.devinputjack", value, "0");
  1024     sDevInputAudioJack = !strcmp(value, "1");
  1025     sHeadphoneState = AKEY_STATE_UNKNOWN;
  1026     sMicrophoneState = AKEY_STATE_UNKNOWN;
  1028     mEventHub = new EventHub();
  1029     mReaderPolicy = new GeckoInputReaderPolicy();
  1030     mReaderPolicy->setDisplayInfo();
  1031     mDispatcher = new GeckoInputDispatcher(mEventHub);
  1033     mReader = new InputReader(mEventHub, mReaderPolicy, mDispatcher);
  1034     mReaderThread = new InputReaderThread(mReader);
  1036     status_t result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
  1037     if (result) {
  1038         LOG("Failed to initialize InputReader thread, bad things are going to happen...");
  1042 nsresult
  1043 nsAppShell::AddFdHandler(int fd, FdHandlerCallback handlerFunc,
  1044                          const char* deviceName)
  1046     epoll_event event = {
  1047         EPOLLIN,
  1048         { 0 }
  1049     };
  1051     FdHandler *handler = mHandlers.AppendElement();
  1052     handler->fd = fd;
  1053     strncpy(handler->name, deviceName, sizeof(handler->name) - 1);
  1054     handler->func = handlerFunc;
  1055     event.data.u32 = mHandlers.Length() - 1;
  1056     return epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event) ?
  1057            NS_ERROR_UNEXPECTED : NS_OK;
  1060 void
  1061 nsAppShell::ScheduleNativeEventCallback()
  1063     mNativeCallbackRequest = true;
  1064     NotifyEvent();
  1067 bool
  1068 nsAppShell::ProcessNextNativeEvent(bool mayWait)
  1070     PROFILER_LABEL("nsAppShell", "ProcessNextNativeEvent");
  1071     epoll_event events[16] = {{ 0 }};
  1073     int event_count;
  1075         PROFILER_LABEL("nsAppShell", "ProcessNextNativeEvent::Wait");
  1076         if ((event_count = epoll_wait(epollfd, events, 16,  mayWait ? -1 : 0)) <= 0)
  1077             return true;
  1080     for (int i = 0; i < event_count; i++)
  1081         mHandlers[events[i].data.u32].run();
  1083     if (mDispatcher.get())
  1084         mDispatcher->dispatchOnce();
  1086     // NativeEventCallback always schedules more if it needs it
  1087     // so we can coalesce these.
  1088     // See the implementation in nsBaseAppShell.cpp for more info
  1089     if (mNativeCallbackRequest) {
  1090         mNativeCallbackRequest = false;
  1091         NativeEventCallback();
  1094     if (gDrawRequest && mEnableDraw) {
  1095         gDrawRequest = false;
  1096         nsWindow::DoDraw();
  1099     return true;
  1102 void
  1103 nsAppShell::NotifyNativeEvent()
  1105     write(signalfds[1], "w", 1);
  1108 /* static */ void
  1109 nsAppShell::NotifyScreenInitialized()
  1111     gAppShell->InitInputDevices();
  1113     // Getting the instance of OrientationObserver to initialize it.
  1114     OrientationObserver::GetInstance();
  1117 /* static */ void
  1118 nsAppShell::NotifyScreenRotation()
  1120     gAppShell->mReaderPolicy->setDisplayInfo();
  1121     gAppShell->mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
  1123     hal::NotifyScreenConfigurationChange(nsScreenGonk::GetConfiguration());

mercurial