widget/gonk/nsAppShell.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/widget/gonk/nsAppShell.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1124 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* vim: set ts=4 sw=4 sts=4 tw=80 et: */
     1.6 +/* Copyright 2012 Mozilla Foundation and Mozilla contributors
     1.7 + *
     1.8 + * Licensed under the Apache License, Version 2.0 (the "License");
     1.9 + * you may not use this file except in compliance with the License.
    1.10 + * You may obtain a copy of the License at
    1.11 + *
    1.12 + *     http://www.apache.org/licenses/LICENSE-2.0
    1.13 + *
    1.14 + * Unless required by applicable law or agreed to in writing, software
    1.15 + * distributed under the License is distributed on an "AS IS" BASIS,
    1.16 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1.17 + * See the License for the specific language governing permissions and
    1.18 + * limitations under the License.
    1.19 + */
    1.20 +
    1.21 +#ifndef _GNU_SOURCE
    1.22 +#define _GNU_SOURCE
    1.23 +#endif
    1.24 +
    1.25 +#include <dirent.h>
    1.26 +#include <errno.h>
    1.27 +#include <fcntl.h>
    1.28 +#include <signal.h>
    1.29 +#include <sys/epoll.h>
    1.30 +#include <sys/ioctl.h>
    1.31 +#include <sys/param.h>
    1.32 +#include <sys/stat.h>
    1.33 +#include <sys/types.h>
    1.34 +#include <unistd.h>
    1.35 +#include <utils/BitSet.h>
    1.36 +
    1.37 +#include "base/basictypes.h"
    1.38 +#include "GonkPermission.h"
    1.39 +#include "nscore.h"
    1.40 +#ifdef MOZ_OMX_DECODER
    1.41 +#include "MediaResourceManagerService.h"
    1.42 +#endif
    1.43 +#include "mozilla/TouchEvents.h"
    1.44 +#include "mozilla/FileUtils.h"
    1.45 +#include "mozilla/Hal.h"
    1.46 +#include "mozilla/MouseEvents.h"
    1.47 +#include "mozilla/Mutex.h"
    1.48 +#include "mozilla/Services.h"
    1.49 +#include "mozilla/TextEvents.h"
    1.50 +#if ANDROID_VERSION >= 18
    1.51 +#include "nativewindow/FakeSurfaceComposer.h"
    1.52 +#endif
    1.53 +#include "nsAppShell.h"
    1.54 +#include "mozilla/dom/Touch.h"
    1.55 +#include "nsGkAtoms.h"
    1.56 +#include "nsIObserverService.h"
    1.57 +#include "nsIScreen.h"
    1.58 +#include "nsScreenManagerGonk.h"
    1.59 +#include "nsThreadUtils.h"
    1.60 +#include "nsWindow.h"
    1.61 +#include "OrientationObserver.h"
    1.62 +#include "GonkMemoryPressureMonitoring.h"
    1.63 +
    1.64 +#include "android/log.h"
    1.65 +#include "libui/EventHub.h"
    1.66 +#include "libui/InputReader.h"
    1.67 +#include "libui/InputDispatcher.h"
    1.68 +#include "cutils/properties.h"
    1.69 +
    1.70 +#ifdef MOZ_NUWA_PROCESS
    1.71 +#include "ipc/Nuwa.h"
    1.72 +#endif
    1.73 +
    1.74 +#include "GeckoProfiler.h"
    1.75 +
    1.76 +// Defines kKeyMapping and GetKeyNameIndex()
    1.77 +#include "GonkKeyMapping.h"
    1.78 +
    1.79 +#define LOG(args...)                                            \
    1.80 +    __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
    1.81 +#ifdef VERBOSE_LOG_ENABLED
    1.82 +# define VERBOSE_LOG(args...)                           \
    1.83 +    __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
    1.84 +#else
    1.85 +# define VERBOSE_LOG(args...)                   \
    1.86 +    (void)0
    1.87 +#endif
    1.88 +
    1.89 +using namespace android;
    1.90 +using namespace mozilla;
    1.91 +using namespace mozilla::dom;
    1.92 +using namespace mozilla::services;
    1.93 +using namespace mozilla::widget;
    1.94 +
    1.95 +bool gDrawRequest = false;
    1.96 +static nsAppShell *gAppShell = nullptr;
    1.97 +static int epollfd = 0;
    1.98 +static int signalfds[2] = {0};
    1.99 +static bool sDevInputAudioJack;
   1.100 +static int32_t sHeadphoneState;
   1.101 +static int32_t sMicrophoneState;
   1.102 +
   1.103 +// Amount of time in MS before an input is considered expired.
   1.104 +static const uint64_t kInputExpirationThresholdMs = 1000;
   1.105 +
   1.106 +NS_IMPL_ISUPPORTS_INHERITED(nsAppShell, nsBaseAppShell, nsIObserver)
   1.107 +
   1.108 +static uint64_t
   1.109 +nanosecsToMillisecs(nsecs_t nsecs)
   1.110 +{
   1.111 +    return nsecs / 1000000;
   1.112 +}
   1.113 +
   1.114 +namespace mozilla {
   1.115 +
   1.116 +bool ProcessNextEvent()
   1.117 +{
   1.118 +    return gAppShell->ProcessNextNativeEvent(true);
   1.119 +}
   1.120 +
   1.121 +void NotifyEvent()
   1.122 +{
   1.123 +    gAppShell->NotifyNativeEvent();
   1.124 +}
   1.125 +
   1.126 +} // namespace mozilla
   1.127 +
   1.128 +static void
   1.129 +pipeHandler(int fd, FdHandler *data)
   1.130 +{
   1.131 +    ssize_t len;
   1.132 +    do {
   1.133 +        char tmp[32];
   1.134 +        len = read(fd, tmp, sizeof(tmp));
   1.135 +    } while (len > 0);
   1.136 +}
   1.137 +
   1.138 +struct Touch {
   1.139 +    int32_t id;
   1.140 +    PointerCoords coords;
   1.141 +};
   1.142 +
   1.143 +struct UserInputData {
   1.144 +    uint64_t timeMs;
   1.145 +    enum {
   1.146 +        MOTION_DATA,
   1.147 +        KEY_DATA
   1.148 +    } type;
   1.149 +    int32_t action;
   1.150 +    int32_t flags;
   1.151 +    int32_t metaState;
   1.152 +    int32_t deviceId;
   1.153 +    union {
   1.154 +        struct {
   1.155 +            int32_t keyCode;
   1.156 +            int32_t scanCode;
   1.157 +        } key;
   1.158 +        struct {
   1.159 +            int32_t touchCount;
   1.160 +            ::Touch touches[MAX_POINTERS];
   1.161 +        } motion;
   1.162 +    };
   1.163 +
   1.164 +    Modifiers DOMModifiers() const;
   1.165 +};
   1.166 +
   1.167 +Modifiers
   1.168 +UserInputData::DOMModifiers() const
   1.169 +{
   1.170 +    Modifiers result = 0;
   1.171 +    if (metaState & (AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
   1.172 +        result |= MODIFIER_ALT;
   1.173 +    }
   1.174 +    if (metaState & (AMETA_SHIFT_ON |
   1.175 +                     AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
   1.176 +        result |= MODIFIER_SHIFT;
   1.177 +    }
   1.178 +    if (metaState & AMETA_FUNCTION_ON) {
   1.179 +        result |= MODIFIER_FN;
   1.180 +    }
   1.181 +    if (metaState & (AMETA_CTRL_ON |
   1.182 +                     AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
   1.183 +        result |= MODIFIER_CONTROL;
   1.184 +    }
   1.185 +    if (metaState & (AMETA_META_ON |
   1.186 +                     AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
   1.187 +        result |= MODIFIER_META;
   1.188 +    }
   1.189 +    if (metaState & AMETA_CAPS_LOCK_ON) {
   1.190 +        result |= MODIFIER_CAPSLOCK;
   1.191 +    }
   1.192 +    if (metaState & AMETA_NUM_LOCK_ON) {
   1.193 +        result |= MODIFIER_NUMLOCK;
   1.194 +    }
   1.195 +    if (metaState & AMETA_SCROLL_LOCK_ON) {
   1.196 +        result |= MODIFIER_SCROLLLOCK;
   1.197 +    }
   1.198 +    return result;
   1.199 +}
   1.200 +
   1.201 +static void
   1.202 +sendMouseEvent(uint32_t msg, UserInputData& data, bool forwardToChildren)
   1.203 +{
   1.204 +    WidgetMouseEvent event(true, msg, nullptr,
   1.205 +                           WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
   1.206 +
   1.207 +    event.refPoint.x = data.motion.touches[0].coords.getX();
   1.208 +    event.refPoint.y = data.motion.touches[0].coords.getY();
   1.209 +    event.time = data.timeMs;
   1.210 +    event.button = WidgetMouseEvent::eLeftButton;
   1.211 +    event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
   1.212 +    if (msg != NS_MOUSE_MOVE)
   1.213 +        event.clickCount = 1;
   1.214 +    event.modifiers = data.DOMModifiers();
   1.215 +
   1.216 +    event.mFlags.mNoCrossProcessBoundaryForwarding = !forwardToChildren;
   1.217 +
   1.218 +    nsWindow::DispatchInputEvent(event);
   1.219 +}
   1.220 +
   1.221 +static void
   1.222 +addDOMTouch(UserInputData& data, WidgetTouchEvent& event, int i)
   1.223 +{
   1.224 +    const ::Touch& touch = data.motion.touches[i];
   1.225 +    event.touches.AppendElement(
   1.226 +        new dom::Touch(touch.id,
   1.227 +                       nsIntPoint(floor(touch.coords.getX() + 0.5), floor(touch.coords.getY() + 0.5)),
   1.228 +                       nsIntPoint(touch.coords.getAxisValue(AMOTION_EVENT_AXIS_SIZE),
   1.229 +                                  touch.coords.getAxisValue(AMOTION_EVENT_AXIS_SIZE)),
   1.230 +                       0,
   1.231 +                       touch.coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE))
   1.232 +    );
   1.233 +}
   1.234 +
   1.235 +static nsEventStatus
   1.236 +sendTouchEvent(UserInputData& data, bool* captured)
   1.237 +{
   1.238 +    uint32_t msg;
   1.239 +    int32_t action = data.action & AMOTION_EVENT_ACTION_MASK;
   1.240 +    switch (action) {
   1.241 +    case AMOTION_EVENT_ACTION_DOWN:
   1.242 +    case AMOTION_EVENT_ACTION_POINTER_DOWN:
   1.243 +        msg = NS_TOUCH_START;
   1.244 +        break;
   1.245 +    case AMOTION_EVENT_ACTION_MOVE:
   1.246 +        msg = NS_TOUCH_MOVE;
   1.247 +        break;
   1.248 +    case AMOTION_EVENT_ACTION_UP:
   1.249 +    case AMOTION_EVENT_ACTION_POINTER_UP:
   1.250 +        msg = NS_TOUCH_END;
   1.251 +        break;
   1.252 +    case AMOTION_EVENT_ACTION_OUTSIDE:
   1.253 +    case AMOTION_EVENT_ACTION_CANCEL:
   1.254 +        msg = NS_TOUCH_CANCEL;
   1.255 +        break;
   1.256 +    default:
   1.257 +        msg = NS_EVENT_NULL;
   1.258 +        break;
   1.259 +    }
   1.260 +
   1.261 +    WidgetTouchEvent event(true, msg, nullptr);
   1.262 +
   1.263 +    event.time = data.timeMs;
   1.264 +    event.modifiers = data.DOMModifiers();
   1.265 +
   1.266 +    int32_t i;
   1.267 +    if (msg == NS_TOUCH_END) {
   1.268 +        i = data.action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK;
   1.269 +        i >>= AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
   1.270 +        addDOMTouch(data, event, i);
   1.271 +    } else {
   1.272 +        for (i = 0; i < data.motion.touchCount; ++i)
   1.273 +            addDOMTouch(data, event, i);
   1.274 +    }
   1.275 +
   1.276 +    return nsWindow::DispatchInputEvent(event, captured);
   1.277 +}
   1.278 +
   1.279 +class MOZ_STACK_CLASS KeyEventDispatcher
   1.280 +{
   1.281 +public:
   1.282 +    KeyEventDispatcher(const UserInputData& aData,
   1.283 +                       KeyCharacterMap* aKeyCharMap);
   1.284 +    void Dispatch();
   1.285 +
   1.286 +private:
   1.287 +    const UserInputData& mData;
   1.288 +    sp<KeyCharacterMap> mKeyCharMap;
   1.289 +
   1.290 +    char16_t mChar;
   1.291 +    char16_t mUnmodifiedChar;
   1.292 +
   1.293 +    uint32_t mDOMKeyCode;
   1.294 +    KeyNameIndex mDOMKeyNameIndex;
   1.295 +    char16_t mDOMPrintableKeyValue;
   1.296 +
   1.297 +    bool IsKeyPress() const
   1.298 +    {
   1.299 +        return mData.action == AKEY_EVENT_ACTION_DOWN;
   1.300 +    }
   1.301 +    bool IsRepeat() const
   1.302 +    {
   1.303 +        return IsKeyPress() && (mData.flags & AKEY_EVENT_FLAG_LONG_PRESS);
   1.304 +    }
   1.305 +
   1.306 +    char16_t PrintableKeyValue() const;
   1.307 +
   1.308 +    int32_t UnmodifiedMetaState() const
   1.309 +    {
   1.310 +        return mData.metaState &
   1.311 +            ~(AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON |
   1.312 +              AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON |
   1.313 +              AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
   1.314 +    }
   1.315 +
   1.316 +    static bool IsControlChar(char16_t aChar)
   1.317 +    {
   1.318 +        return (aChar < ' ' || aChar == 0x7F);
   1.319 +    }
   1.320 +
   1.321 +    void DispatchKeyDownEvent();
   1.322 +    void DispatchKeyUpEvent();
   1.323 +    nsEventStatus DispatchKeyEventInternal(uint32_t aEventMessage);
   1.324 +};
   1.325 +
   1.326 +KeyEventDispatcher::KeyEventDispatcher(const UserInputData& aData,
   1.327 +                                       KeyCharacterMap* aKeyCharMap) :
   1.328 +    mData(aData), mKeyCharMap(aKeyCharMap), mChar(0), mUnmodifiedChar(0),
   1.329 +    mDOMPrintableKeyValue(0)
   1.330 +{
   1.331 +    // XXX Printable key's keyCode value should be computed with actual
   1.332 +    //     input character.
   1.333 +    mDOMKeyCode = (mData.key.keyCode < (ssize_t)ArrayLength(kKeyMapping)) ?
   1.334 +        kKeyMapping[mData.key.keyCode] : 0;
   1.335 +    mDOMKeyNameIndex = GetKeyNameIndex(mData.key.keyCode);
   1.336 +
   1.337 +    if (!mKeyCharMap.get()) {
   1.338 +        return;
   1.339 +    }
   1.340 +
   1.341 +    mChar = mKeyCharMap->getCharacter(mData.key.keyCode, mData.metaState);
   1.342 +    if (IsControlChar(mChar)) {
   1.343 +        mChar = 0;
   1.344 +    }
   1.345 +    int32_t unmodifiedMetaState = UnmodifiedMetaState();
   1.346 +    if (mData.metaState == unmodifiedMetaState) {
   1.347 +        mUnmodifiedChar = mChar;
   1.348 +    } else {
   1.349 +        mUnmodifiedChar = mKeyCharMap->getCharacter(mData.key.keyCode,
   1.350 +                                                    unmodifiedMetaState);
   1.351 +        if (IsControlChar(mUnmodifiedChar)) {
   1.352 +            mUnmodifiedChar = 0;
   1.353 +        }
   1.354 +    }
   1.355 +
   1.356 +    mDOMPrintableKeyValue = PrintableKeyValue();
   1.357 +}
   1.358 +
   1.359 +char16_t
   1.360 +KeyEventDispatcher::PrintableKeyValue() const
   1.361 +{
   1.362 +    if (mDOMKeyNameIndex != KEY_NAME_INDEX_USE_STRING) {
   1.363 +        return 0;
   1.364 +    }
   1.365 +    return mChar ? mChar : mUnmodifiedChar;
   1.366 +}
   1.367 +
   1.368 +nsEventStatus
   1.369 +KeyEventDispatcher::DispatchKeyEventInternal(uint32_t aEventMessage)
   1.370 +{
   1.371 +    WidgetKeyboardEvent event(true, aEventMessage, nullptr);
   1.372 +    if (aEventMessage == NS_KEY_PRESS) {
   1.373 +        // XXX If the charCode is not a printable character, the charCode
   1.374 +        //     should be computed without Ctrl/Alt/Meta modifiers.
   1.375 +        event.charCode = static_cast<uint32_t>(mChar);
   1.376 +    }
   1.377 +    if (!event.charCode) {
   1.378 +        event.keyCode = mDOMKeyCode;
   1.379 +    }
   1.380 +    event.isChar = !!event.charCode;
   1.381 +    event.mIsRepeat = IsRepeat();
   1.382 +    event.mKeyNameIndex = mDOMKeyNameIndex;
   1.383 +    if (mDOMPrintableKeyValue) {
   1.384 +        event.mKeyValue = mDOMPrintableKeyValue;
   1.385 +    }
   1.386 +    event.modifiers = mData.DOMModifiers();
   1.387 +    event.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_MOBILE;
   1.388 +    event.time = mData.timeMs;
   1.389 +    return nsWindow::DispatchInputEvent(event);
   1.390 +}
   1.391 +
   1.392 +void
   1.393 +KeyEventDispatcher::Dispatch()
   1.394 +{
   1.395 +    // XXX Even if unknown key is pressed, DOM key event should be
   1.396 +    //     dispatched since Gecko for the other platforms are implemented
   1.397 +    //     as so.
   1.398 +    if (!mDOMKeyCode && mDOMKeyNameIndex == KEY_NAME_INDEX_Unidentified) {
   1.399 +        VERBOSE_LOG("Got unknown key event code. "
   1.400 +                    "type 0x%04x code 0x%04x value %d",
   1.401 +                    mData.action, mData.key.keyCode, IsKeyPress());
   1.402 +        return;
   1.403 +    }
   1.404 +
   1.405 +    if (IsKeyPress()) {
   1.406 +        DispatchKeyDownEvent();
   1.407 +    } else {
   1.408 +        DispatchKeyUpEvent();
   1.409 +    }
   1.410 +}
   1.411 +
   1.412 +void
   1.413 +KeyEventDispatcher::DispatchKeyDownEvent()
   1.414 +{
   1.415 +    nsEventStatus status = DispatchKeyEventInternal(NS_KEY_DOWN);
   1.416 +    if (status != nsEventStatus_eConsumeNoDefault) {
   1.417 +        DispatchKeyEventInternal(NS_KEY_PRESS);
   1.418 +    }
   1.419 +}
   1.420 +
   1.421 +void
   1.422 +KeyEventDispatcher::DispatchKeyUpEvent()
   1.423 +{
   1.424 +    DispatchKeyEventInternal(NS_KEY_UP);
   1.425 +}
   1.426 +
   1.427 +class SwitchEventRunnable : public nsRunnable {
   1.428 +public:
   1.429 +    SwitchEventRunnable(hal::SwitchEvent& aEvent) : mEvent(aEvent)
   1.430 +    {}
   1.431 +
   1.432 +    NS_IMETHOD Run()
   1.433 +    {
   1.434 +        hal::NotifySwitchStateFromInputDevice(mEvent.device(),
   1.435 +          mEvent.status());
   1.436 +        return NS_OK;
   1.437 +    }
   1.438 +private:
   1.439 +    hal::SwitchEvent mEvent;
   1.440 +};
   1.441 +
   1.442 +static void
   1.443 +updateHeadphoneSwitch()
   1.444 +{
   1.445 +    hal::SwitchEvent event;
   1.446 +
   1.447 +    switch (sHeadphoneState) {
   1.448 +    case AKEY_STATE_UP:
   1.449 +        event.status() = hal::SWITCH_STATE_OFF;
   1.450 +        break;
   1.451 +    case AKEY_STATE_DOWN:
   1.452 +        event.status() = sMicrophoneState == AKEY_STATE_DOWN ?
   1.453 +            hal::SWITCH_STATE_HEADSET : hal::SWITCH_STATE_HEADPHONE;
   1.454 +        break;
   1.455 +    default:
   1.456 +        return;
   1.457 +    }
   1.458 +
   1.459 +    event.device() = hal::SWITCH_HEADPHONES;
   1.460 +    NS_DispatchToMainThread(new SwitchEventRunnable(event));
   1.461 +}
   1.462 +
   1.463 +class GeckoPointerController : public PointerControllerInterface {
   1.464 +    float mX;
   1.465 +    float mY;
   1.466 +    int32_t mButtonState;
   1.467 +    InputReaderConfiguration* mConfig;
   1.468 +public:
   1.469 +    GeckoPointerController(InputReaderConfiguration* config)
   1.470 +        : mX(0)
   1.471 +        , mY(0)
   1.472 +        , mButtonState(0)
   1.473 +        , mConfig(config)
   1.474 +    {}
   1.475 +
   1.476 +    virtual bool getBounds(float* outMinX, float* outMinY,
   1.477 +            float* outMaxX, float* outMaxY) const;
   1.478 +    virtual void move(float deltaX, float deltaY);
   1.479 +    virtual void setButtonState(int32_t buttonState);
   1.480 +    virtual int32_t getButtonState() const;
   1.481 +    virtual void setPosition(float x, float y);
   1.482 +    virtual void getPosition(float* outX, float* outY) const;
   1.483 +    virtual void fade(Transition transition) {}
   1.484 +    virtual void unfade(Transition transition) {}
   1.485 +    virtual void setPresentation(Presentation presentation) {}
   1.486 +    virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
   1.487 +            BitSet32 spotIdBits) {}
   1.488 +    virtual void clearSpots() {}
   1.489 +};
   1.490 +
   1.491 +bool
   1.492 +GeckoPointerController::getBounds(float* outMinX,
   1.493 +                                  float* outMinY,
   1.494 +                                  float* outMaxX,
   1.495 +                                  float* outMaxY) const
   1.496 +{
   1.497 +    DisplayViewport viewport;
   1.498 +
   1.499 +    mConfig->getDisplayInfo(false, &viewport);
   1.500 +
   1.501 +    *outMinX = *outMinY = 0;
   1.502 +    *outMaxX = viewport.logicalRight;
   1.503 +    *outMaxY = viewport.logicalBottom;
   1.504 +    return true;
   1.505 +}
   1.506 +
   1.507 +void
   1.508 +GeckoPointerController::move(float deltaX, float deltaY)
   1.509 +{
   1.510 +    float minX, minY, maxX, maxY;
   1.511 +    getBounds(&minX, &minY, &maxX, &maxY);
   1.512 +
   1.513 +    mX = clamped(mX + deltaX, minX, maxX);
   1.514 +    mY = clamped(mY + deltaY, minY, maxY);
   1.515 +}
   1.516 +
   1.517 +void
   1.518 +GeckoPointerController::setButtonState(int32_t buttonState)
   1.519 +{
   1.520 +    mButtonState = buttonState;
   1.521 +}
   1.522 +
   1.523 +int32_t
   1.524 +GeckoPointerController::getButtonState() const
   1.525 +{
   1.526 +    return mButtonState;
   1.527 +}
   1.528 +
   1.529 +void
   1.530 +GeckoPointerController::setPosition(float x, float y)
   1.531 +{
   1.532 +    mX = x;
   1.533 +    mY = y;
   1.534 +}
   1.535 +
   1.536 +void
   1.537 +GeckoPointerController::getPosition(float* outX, float* outY) const
   1.538 +{
   1.539 +    *outX = mX;
   1.540 +    *outY = mY;
   1.541 +}
   1.542 +
   1.543 +class GeckoInputReaderPolicy : public InputReaderPolicyInterface {
   1.544 +    InputReaderConfiguration mConfig;
   1.545 +public:
   1.546 +    GeckoInputReaderPolicy() {}
   1.547 +
   1.548 +    virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
   1.549 +    virtual sp<PointerControllerInterface> obtainPointerController(int32_t
   1.550 +deviceId)
   1.551 +    {
   1.552 +        return new GeckoPointerController(&mConfig);
   1.553 +    };
   1.554 +    virtual void notifyInputDevicesChanged(const android::Vector<InputDeviceInfo>& inputDevices) {};
   1.555 +    virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor)
   1.556 +    {
   1.557 +        return nullptr;
   1.558 +    };
   1.559 +    virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier)
   1.560 +    {
   1.561 +        return String8::empty();
   1.562 +    };
   1.563 +
   1.564 +    void setDisplayInfo();
   1.565 +
   1.566 +protected:
   1.567 +    virtual ~GeckoInputReaderPolicy() {}
   1.568 +};
   1.569 +
   1.570 +class GeckoInputDispatcher : public InputDispatcherInterface {
   1.571 +public:
   1.572 +    GeckoInputDispatcher(sp<EventHub> &aEventHub)
   1.573 +        : mQueueLock("GeckoInputDispatcher::mQueueMutex")
   1.574 +        , mEventHub(aEventHub)
   1.575 +        , mTouchDownCount(0)
   1.576 +        , mKeyDownCount(0)
   1.577 +        , mTouchEventsFiltered(false)
   1.578 +        , mKeyEventsFiltered(false)
   1.579 +    {}
   1.580 +
   1.581 +    virtual void dump(String8& dump);
   1.582 +
   1.583 +    virtual void monitor() {}
   1.584 +
   1.585 +    // Called on the main thread
   1.586 +    virtual void dispatchOnce();
   1.587 +
   1.588 +    // notify* methods are called on the InputReaderThread
   1.589 +    virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
   1.590 +    virtual void notifyKey(const NotifyKeyArgs* args);
   1.591 +    virtual void notifyMotion(const NotifyMotionArgs* args);
   1.592 +    virtual void notifySwitch(const NotifySwitchArgs* args);
   1.593 +    virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
   1.594 +
   1.595 +    virtual int32_t injectInputEvent(const InputEvent* event,
   1.596 +            int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
   1.597 +            uint32_t policyFlags);
   1.598 +
   1.599 +    virtual void setInputWindows(const android::Vector<sp<InputWindowHandle> >& inputWindowHandles);
   1.600 +    virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle);
   1.601 +
   1.602 +    virtual void setInputDispatchMode(bool enabled, bool frozen);
   1.603 +    virtual void setInputFilterEnabled(bool enabled) {}
   1.604 +    virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
   1.605 +            const sp<InputChannel>& toChannel) { return true; }
   1.606 +
   1.607 +    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
   1.608 +            const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
   1.609 +    virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
   1.610 +
   1.611 +
   1.612 +
   1.613 +protected:
   1.614 +    virtual ~GeckoInputDispatcher() {}
   1.615 +
   1.616 +private:
   1.617 +    // mQueueLock should generally be locked while using mEventQueue.
   1.618 +    // UserInputData is pushed on on the InputReaderThread and
   1.619 +    // popped and dispatched on the main thread.
   1.620 +    mozilla::Mutex mQueueLock;
   1.621 +    std::queue<UserInputData> mEventQueue;
   1.622 +    sp<EventHub> mEventHub;
   1.623 +
   1.624 +    int mTouchDownCount;
   1.625 +    int mKeyDownCount;
   1.626 +    bool mTouchEventsFiltered;
   1.627 +    bool mKeyEventsFiltered;
   1.628 +    BitSet32 mTouchDown;
   1.629 +};
   1.630 +
   1.631 +// GeckoInputReaderPolicy
   1.632 +void
   1.633 +GeckoInputReaderPolicy::setDisplayInfo()
   1.634 +{
   1.635 +    static_assert(nsIScreen::ROTATION_0_DEG ==
   1.636 +                  DISPLAY_ORIENTATION_0,
   1.637 +                  "Orientation enums not matched!");
   1.638 +    static_assert(nsIScreen::ROTATION_90_DEG ==
   1.639 +                  DISPLAY_ORIENTATION_90,
   1.640 +                  "Orientation enums not matched!");
   1.641 +    static_assert(nsIScreen::ROTATION_180_DEG ==
   1.642 +                  DISPLAY_ORIENTATION_180,
   1.643 +                  "Orientation enums not matched!");
   1.644 +    static_assert(nsIScreen::ROTATION_270_DEG ==
   1.645 +                  DISPLAY_ORIENTATION_270,
   1.646 +                  "Orientation enums not matched!");
   1.647 +
   1.648 +    DisplayViewport viewport;
   1.649 +    viewport.displayId = 0;
   1.650 +    viewport.orientation = nsScreenGonk::GetRotation();
   1.651 +    viewport.physicalRight = viewport.deviceWidth = gScreenBounds.width;
   1.652 +    viewport.physicalBottom = viewport.deviceHeight = gScreenBounds.height;
   1.653 +    if (viewport.orientation == DISPLAY_ORIENTATION_90 ||
   1.654 +        viewport.orientation == DISPLAY_ORIENTATION_270) {
   1.655 +        viewport.logicalRight = gScreenBounds.height;
   1.656 +        viewport.logicalBottom = gScreenBounds.width;
   1.657 +    } else {
   1.658 +        viewport.logicalRight = gScreenBounds.width;
   1.659 +        viewport.logicalBottom = gScreenBounds.height;
   1.660 +    }
   1.661 +    mConfig.setDisplayInfo(false, viewport);
   1.662 +}
   1.663 +
   1.664 +void GeckoInputReaderPolicy::getReaderConfiguration(InputReaderConfiguration* outConfig)
   1.665 +{
   1.666 +    *outConfig = mConfig;
   1.667 +}
   1.668 +
   1.669 +
   1.670 +// GeckoInputDispatcher
   1.671 +void
   1.672 +GeckoInputDispatcher::dump(String8& dump)
   1.673 +{
   1.674 +}
   1.675 +
   1.676 +static bool
   1.677 +isExpired(const UserInputData& data)
   1.678 +{
   1.679 +    uint64_t timeNowMs =
   1.680 +        nanosecsToMillisecs(systemTime(SYSTEM_TIME_MONOTONIC));
   1.681 +    return (timeNowMs - data.timeMs) > kInputExpirationThresholdMs;
   1.682 +}
   1.683 +
   1.684 +void
   1.685 +GeckoInputDispatcher::dispatchOnce()
   1.686 +{
   1.687 +    UserInputData data;
   1.688 +    {
   1.689 +        MutexAutoLock lock(mQueueLock);
   1.690 +        if (mEventQueue.empty())
   1.691 +            return;
   1.692 +        data = mEventQueue.front();
   1.693 +        mEventQueue.pop();
   1.694 +        if (!mEventQueue.empty())
   1.695 +            gAppShell->NotifyNativeEvent();
   1.696 +    }
   1.697 +
   1.698 +    switch (data.type) {
   1.699 +    case UserInputData::MOTION_DATA: {
   1.700 +        if (!mTouchDownCount) {
   1.701 +            // No pending events, the filter state can be updated.
   1.702 +            mTouchEventsFiltered = isExpired(data);
   1.703 +        }
   1.704 +
   1.705 +        int32_t action = data.action & AMOTION_EVENT_ACTION_MASK;
   1.706 +        int32_t index = data.action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK;
   1.707 +        index >>= AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
   1.708 +        switch (action) {
   1.709 +        case AMOTION_EVENT_ACTION_DOWN:
   1.710 +        case AMOTION_EVENT_ACTION_POINTER_DOWN:
   1.711 +            if (!mTouchDown.hasBit(index)) {
   1.712 +                mTouchDown.markBit(index);
   1.713 +                mTouchDownCount++;
   1.714 +            }
   1.715 +            break;
   1.716 +        case AMOTION_EVENT_ACTION_MOVE:
   1.717 +        case AMOTION_EVENT_ACTION_HOVER_MOVE:
   1.718 +            // No need to update the count on move.
   1.719 +            break;
   1.720 +        case AMOTION_EVENT_ACTION_UP:
   1.721 +        case AMOTION_EVENT_ACTION_POINTER_UP:
   1.722 +        case AMOTION_EVENT_ACTION_OUTSIDE:
   1.723 +        case AMOTION_EVENT_ACTION_CANCEL:
   1.724 +            if (mTouchDown.hasBit(index)) {
   1.725 +                mTouchDown.clearBit(index);
   1.726 +                mTouchDownCount--;
   1.727 +            }
   1.728 +            break;
   1.729 +        default:
   1.730 +            break;
   1.731 +        }
   1.732 +
   1.733 +        if (mTouchEventsFiltered) {
   1.734 +            return;
   1.735 +        }
   1.736 +
   1.737 +        nsEventStatus status = nsEventStatus_eIgnore;
   1.738 +        if (action != AMOTION_EVENT_ACTION_HOVER_MOVE) {
   1.739 +            bool captured;
   1.740 +            status = sendTouchEvent(data, &captured);
   1.741 +            if (captured) {
   1.742 +                return;
   1.743 +            }
   1.744 +        }
   1.745 +
   1.746 +        uint32_t msg;
   1.747 +        switch (action) {
   1.748 +        case AMOTION_EVENT_ACTION_DOWN:
   1.749 +            msg = NS_MOUSE_BUTTON_DOWN;
   1.750 +            break;
   1.751 +        case AMOTION_EVENT_ACTION_POINTER_DOWN:
   1.752 +        case AMOTION_EVENT_ACTION_POINTER_UP:
   1.753 +        case AMOTION_EVENT_ACTION_MOVE:
   1.754 +        case AMOTION_EVENT_ACTION_HOVER_MOVE:
   1.755 +            msg = NS_MOUSE_MOVE;
   1.756 +            break;
   1.757 +        case AMOTION_EVENT_ACTION_OUTSIDE:
   1.758 +        case AMOTION_EVENT_ACTION_CANCEL:
   1.759 +        case AMOTION_EVENT_ACTION_UP:
   1.760 +            msg = NS_MOUSE_BUTTON_UP;
   1.761 +            break;
   1.762 +        default:
   1.763 +            msg = NS_EVENT_NULL;
   1.764 +            break;
   1.765 +        }
   1.766 +        if (msg != NS_EVENT_NULL) {
   1.767 +            sendMouseEvent(msg, data, 
   1.768 +                           status != nsEventStatus_eConsumeNoDefault);
   1.769 +        }
   1.770 +        break;
   1.771 +    }
   1.772 +    case UserInputData::KEY_DATA: {
   1.773 +        if (!mKeyDownCount) {
   1.774 +            // No pending events, the filter state can be updated.
   1.775 +            mKeyEventsFiltered = isExpired(data);
   1.776 +        }
   1.777 +
   1.778 +        mKeyDownCount += (data.action == AKEY_EVENT_ACTION_DOWN) ? 1 : -1;
   1.779 +        if (mKeyEventsFiltered) {
   1.780 +            return;
   1.781 +        }
   1.782 +
   1.783 +        sp<KeyCharacterMap> kcm = mEventHub->getKeyCharacterMap(data.deviceId);
   1.784 +        KeyEventDispatcher dispatcher(data, kcm.get());
   1.785 +        dispatcher.Dispatch();
   1.786 +        break;
   1.787 +    }
   1.788 +    }
   1.789 +}
   1.790 +
   1.791 +void
   1.792 +GeckoInputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs*)
   1.793 +{
   1.794 +}
   1.795 +
   1.796 +void
   1.797 +GeckoInputDispatcher::notifyKey(const NotifyKeyArgs* args)
   1.798 +{
   1.799 +    UserInputData data;
   1.800 +    data.timeMs = nanosecsToMillisecs(args->eventTime);
   1.801 +    data.type = UserInputData::KEY_DATA;
   1.802 +    data.action = args->action;
   1.803 +    data.flags = args->flags;
   1.804 +    data.metaState = args->metaState;
   1.805 +    data.deviceId = args->deviceId;
   1.806 +    data.key.keyCode = args->keyCode;
   1.807 +    data.key.scanCode = args->scanCode;
   1.808 +    {
   1.809 +        MutexAutoLock lock(mQueueLock);
   1.810 +        mEventQueue.push(data);
   1.811 +    }
   1.812 +    gAppShell->NotifyNativeEvent();
   1.813 +}
   1.814 +
   1.815 +
   1.816 +void
   1.817 +GeckoInputDispatcher::notifyMotion(const NotifyMotionArgs* args)
   1.818 +{
   1.819 +    UserInputData data;
   1.820 +    data.timeMs = nanosecsToMillisecs(args->eventTime);
   1.821 +    data.type = UserInputData::MOTION_DATA;
   1.822 +    data.action = args->action;
   1.823 +    data.flags = args->flags;
   1.824 +    data.metaState = args->metaState;
   1.825 +    data.deviceId = args->deviceId;
   1.826 +    MOZ_ASSERT(args->pointerCount <= MAX_POINTERS);
   1.827 +    data.motion.touchCount = args->pointerCount;
   1.828 +    for (uint32_t i = 0; i < args->pointerCount; ++i) {
   1.829 +        ::Touch& touch = data.motion.touches[i];
   1.830 +        touch.id = args->pointerProperties[i].id;
   1.831 +        memcpy(&touch.coords, &args->pointerCoords[i], sizeof(*args->pointerCoords));
   1.832 +    }
   1.833 +    {
   1.834 +        MutexAutoLock lock(mQueueLock);
   1.835 +        if (!mEventQueue.empty() &&
   1.836 +             mEventQueue.back().type == UserInputData::MOTION_DATA &&
   1.837 +           ((mEventQueue.back().action & AMOTION_EVENT_ACTION_MASK) ==
   1.838 +             AMOTION_EVENT_ACTION_MOVE ||
   1.839 +            (mEventQueue.back().action & AMOTION_EVENT_ACTION_MASK) ==
   1.840 +             AMOTION_EVENT_ACTION_HOVER_MOVE))
   1.841 +            mEventQueue.back() = data;
   1.842 +        else
   1.843 +            mEventQueue.push(data);
   1.844 +    }
   1.845 +    gAppShell->NotifyNativeEvent();
   1.846 +}
   1.847 +
   1.848 +
   1.849 +
   1.850 +void GeckoInputDispatcher::notifySwitch(const NotifySwitchArgs* args)
   1.851 +{
   1.852 +    if (!sDevInputAudioJack)
   1.853 +        return;
   1.854 +
   1.855 +    bool needSwitchUpdate = false;
   1.856 +
   1.857 +    if (args->switchMask & (1 << SW_HEADPHONE_INSERT)) {
   1.858 +        sHeadphoneState = (args->switchValues & (1 << SW_HEADPHONE_INSERT)) ?
   1.859 +                          AKEY_STATE_DOWN : AKEY_STATE_UP;
   1.860 +        needSwitchUpdate = true;
   1.861 +    }
   1.862 +
   1.863 +    if (args->switchMask & (1 << SW_MICROPHONE_INSERT)) {
   1.864 +        sMicrophoneState = (args->switchValues & (1 << SW_MICROPHONE_INSERT)) ?
   1.865 +                           AKEY_STATE_DOWN : AKEY_STATE_UP;
   1.866 +        needSwitchUpdate = true;
   1.867 +    }
   1.868 +
   1.869 +    if (needSwitchUpdate)
   1.870 +        updateHeadphoneSwitch();
   1.871 +}
   1.872 +
   1.873 +void GeckoInputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args)
   1.874 +{
   1.875 +}
   1.876 +
   1.877 +int32_t GeckoInputDispatcher::injectInputEvent(
   1.878 +    const InputEvent* event,
   1.879 +    int32_t injectorPid, int32_t injectorUid, int32_t syncMode,
   1.880 +    int32_t timeoutMillis, uint32_t policyFlags)
   1.881 +{
   1.882 +    return INPUT_EVENT_INJECTION_SUCCEEDED;
   1.883 +}
   1.884 +
   1.885 +void
   1.886 +GeckoInputDispatcher::setInputWindows(const android::Vector<sp<InputWindowHandle> >& inputWindowHandles)
   1.887 +{
   1.888 +}
   1.889 +
   1.890 +void
   1.891 +GeckoInputDispatcher::setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle)
   1.892 +{
   1.893 +}
   1.894 +
   1.895 +void
   1.896 +GeckoInputDispatcher::setInputDispatchMode(bool enabled, bool frozen)
   1.897 +{
   1.898 +}
   1.899 +
   1.900 +status_t
   1.901 +GeckoInputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
   1.902 +                                           const sp<InputWindowHandle>& inputWindowHandle, bool monitor)
   1.903 +{
   1.904 +    return OK;
   1.905 +}
   1.906 +
   1.907 +status_t
   1.908 +GeckoInputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel)
   1.909 +{
   1.910 +    return OK;
   1.911 +}
   1.912 +
   1.913 +nsAppShell::nsAppShell()
   1.914 +    : mNativeCallbackRequest(false)
   1.915 +    , mEnableDraw(false)
   1.916 +    , mHandlers()
   1.917 +{
   1.918 +    gAppShell = this;
   1.919 +}
   1.920 +
   1.921 +nsAppShell::~nsAppShell()
   1.922 +{
   1.923 +    // mReaderThread and mEventHub will both be null if InitInputDevices
   1.924 +    // is not called.
   1.925 +    if (mReaderThread.get()) {
   1.926 +        // We separate requestExit() and join() here so we can wake the EventHub's
   1.927 +        // input loop, and stop it from polling for input events
   1.928 +        mReaderThread->requestExit();
   1.929 +        mEventHub->wake();
   1.930 +
   1.931 +        status_t result = mReaderThread->requestExitAndWait();
   1.932 +        if (result)
   1.933 +            LOG("Could not stop reader thread - %d", result);
   1.934 +    }
   1.935 +    gAppShell = nullptr;
   1.936 +}
   1.937 +
   1.938 +nsresult
   1.939 +nsAppShell::Init()
   1.940 +{
   1.941 +    nsresult rv = nsBaseAppShell::Init();
   1.942 +    NS_ENSURE_SUCCESS(rv, rv);
   1.943 +
   1.944 +    epollfd = epoll_create(16);
   1.945 +    NS_ENSURE_TRUE(epollfd >= 0, NS_ERROR_UNEXPECTED);
   1.946 +
   1.947 +    int ret = pipe2(signalfds, O_NONBLOCK);
   1.948 +    NS_ENSURE_FALSE(ret, NS_ERROR_UNEXPECTED);
   1.949 +
   1.950 +    rv = AddFdHandler(signalfds[0], pipeHandler, "");
   1.951 +    NS_ENSURE_SUCCESS(rv, rv);
   1.952 +
   1.953 +    InitGonkMemoryPressureMonitoring();
   1.954 +
   1.955 +    if (XRE_GetProcessType() == GeckoProcessType_Default) {
   1.956 +#ifdef MOZ_OMX_DECODER
   1.957 +        android::MediaResourceManagerService::instantiate();
   1.958 +#endif
   1.959 +#if ANDROID_VERSION >= 18 && (defined(MOZ_OMX_DECODER) || defined(MOZ_B2G_CAMERA))
   1.960 +        android::FakeSurfaceComposer::instantiate();
   1.961 +#endif
   1.962 +        GonkPermissionService::instantiate();
   1.963 +
   1.964 +        // Causes the kernel timezone to be set, which in turn causes the
   1.965 +        // timestamps on SD cards to have the local time rather than UTC time.
   1.966 +        hal::SetTimezone(hal::GetTimezone());
   1.967 +    }
   1.968 +
   1.969 +    nsCOMPtr<nsIObserverService> obsServ = GetObserverService();
   1.970 +    if (obsServ) {
   1.971 +        obsServ->AddObserver(this, "browser-ui-startup-complete", false);
   1.972 +        obsServ->AddObserver(this, "network-connection-state-changed", false);
   1.973 +    }
   1.974 +
   1.975 +#ifdef MOZ_NUWA_PROCESS
   1.976 +    // Make sure main thread was woken up after Nuwa fork.
   1.977 +    NuwaAddConstructor((void (*)(void *))&NotifyEvent, nullptr);
   1.978 +#endif
   1.979 +
   1.980 +    // Delay initializing input devices until the screen has been
   1.981 +    // initialized (and we know the resolution).
   1.982 +    return rv;
   1.983 +}
   1.984 +
   1.985 +NS_IMETHODIMP
   1.986 +nsAppShell::Observe(nsISupports* aSubject,
   1.987 +                    const char* aTopic,
   1.988 +                    const char16_t* aData)
   1.989 +{
   1.990 +    if (!strcmp(aTopic, "network-connection-state-changed")) {
   1.991 +        NS_ConvertUTF16toUTF8 type(aData);
   1.992 +        if (!type.IsEmpty()) {
   1.993 +            hal::NotifyNetworkChange(hal::NetworkInformation(atoi(type.get()), 0, 0));
   1.994 +        }
   1.995 +        return NS_OK;
   1.996 +    } else if (!strcmp(aTopic, "browser-ui-startup-complete")) {
   1.997 +        if (sDevInputAudioJack) {
   1.998 +            sHeadphoneState  = mReader->getSwitchState(-1, AINPUT_SOURCE_SWITCH, SW_HEADPHONE_INSERT);
   1.999 +            sMicrophoneState = mReader->getSwitchState(-1, AINPUT_SOURCE_SWITCH, SW_MICROPHONE_INSERT);
  1.1000 +            updateHeadphoneSwitch();
  1.1001 +        }
  1.1002 +        mEnableDraw = true;
  1.1003 +        NotifyEvent();
  1.1004 +        return NS_OK;
  1.1005 +    }
  1.1006 +
  1.1007 +    return nsBaseAppShell::Observe(aSubject, aTopic, aData);
  1.1008 +}
  1.1009 +
  1.1010 +NS_IMETHODIMP
  1.1011 +nsAppShell::Exit()
  1.1012 +{
  1.1013 +    OrientationObserver::ShutDown();
  1.1014 +    nsCOMPtr<nsIObserverService> obsServ = GetObserverService();
  1.1015 +    if (obsServ) {
  1.1016 +        obsServ->RemoveObserver(this, "browser-ui-startup-complete");
  1.1017 +        obsServ->RemoveObserver(this, "network-connection-state-changed");
  1.1018 +    }
  1.1019 +    return nsBaseAppShell::Exit();
  1.1020 +}
  1.1021 +
  1.1022 +void
  1.1023 +nsAppShell::InitInputDevices()
  1.1024 +{
  1.1025 +    char value[PROPERTY_VALUE_MAX];
  1.1026 +    property_get("ro.moz.devinputjack", value, "0");
  1.1027 +    sDevInputAudioJack = !strcmp(value, "1");
  1.1028 +    sHeadphoneState = AKEY_STATE_UNKNOWN;
  1.1029 +    sMicrophoneState = AKEY_STATE_UNKNOWN;
  1.1030 +
  1.1031 +    mEventHub = new EventHub();
  1.1032 +    mReaderPolicy = new GeckoInputReaderPolicy();
  1.1033 +    mReaderPolicy->setDisplayInfo();
  1.1034 +    mDispatcher = new GeckoInputDispatcher(mEventHub);
  1.1035 +
  1.1036 +    mReader = new InputReader(mEventHub, mReaderPolicy, mDispatcher);
  1.1037 +    mReaderThread = new InputReaderThread(mReader);
  1.1038 +
  1.1039 +    status_t result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
  1.1040 +    if (result) {
  1.1041 +        LOG("Failed to initialize InputReader thread, bad things are going to happen...");
  1.1042 +    }
  1.1043 +}
  1.1044 +
  1.1045 +nsresult
  1.1046 +nsAppShell::AddFdHandler(int fd, FdHandlerCallback handlerFunc,
  1.1047 +                         const char* deviceName)
  1.1048 +{
  1.1049 +    epoll_event event = {
  1.1050 +        EPOLLIN,
  1.1051 +        { 0 }
  1.1052 +    };
  1.1053 +
  1.1054 +    FdHandler *handler = mHandlers.AppendElement();
  1.1055 +    handler->fd = fd;
  1.1056 +    strncpy(handler->name, deviceName, sizeof(handler->name) - 1);
  1.1057 +    handler->func = handlerFunc;
  1.1058 +    event.data.u32 = mHandlers.Length() - 1;
  1.1059 +    return epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event) ?
  1.1060 +           NS_ERROR_UNEXPECTED : NS_OK;
  1.1061 +}
  1.1062 +
  1.1063 +void
  1.1064 +nsAppShell::ScheduleNativeEventCallback()
  1.1065 +{
  1.1066 +    mNativeCallbackRequest = true;
  1.1067 +    NotifyEvent();
  1.1068 +}
  1.1069 +
  1.1070 +bool
  1.1071 +nsAppShell::ProcessNextNativeEvent(bool mayWait)
  1.1072 +{
  1.1073 +    PROFILER_LABEL("nsAppShell", "ProcessNextNativeEvent");
  1.1074 +    epoll_event events[16] = {{ 0 }};
  1.1075 +
  1.1076 +    int event_count;
  1.1077 +    {
  1.1078 +        PROFILER_LABEL("nsAppShell", "ProcessNextNativeEvent::Wait");
  1.1079 +        if ((event_count = epoll_wait(epollfd, events, 16,  mayWait ? -1 : 0)) <= 0)
  1.1080 +            return true;
  1.1081 +    }
  1.1082 +
  1.1083 +    for (int i = 0; i < event_count; i++)
  1.1084 +        mHandlers[events[i].data.u32].run();
  1.1085 +
  1.1086 +    if (mDispatcher.get())
  1.1087 +        mDispatcher->dispatchOnce();
  1.1088 +
  1.1089 +    // NativeEventCallback always schedules more if it needs it
  1.1090 +    // so we can coalesce these.
  1.1091 +    // See the implementation in nsBaseAppShell.cpp for more info
  1.1092 +    if (mNativeCallbackRequest) {
  1.1093 +        mNativeCallbackRequest = false;
  1.1094 +        NativeEventCallback();
  1.1095 +    }
  1.1096 +
  1.1097 +    if (gDrawRequest && mEnableDraw) {
  1.1098 +        gDrawRequest = false;
  1.1099 +        nsWindow::DoDraw();
  1.1100 +    }
  1.1101 +
  1.1102 +    return true;
  1.1103 +}
  1.1104 +
  1.1105 +void
  1.1106 +nsAppShell::NotifyNativeEvent()
  1.1107 +{
  1.1108 +    write(signalfds[1], "w", 1);
  1.1109 +}
  1.1110 +
  1.1111 +/* static */ void
  1.1112 +nsAppShell::NotifyScreenInitialized()
  1.1113 +{
  1.1114 +    gAppShell->InitInputDevices();
  1.1115 +
  1.1116 +    // Getting the instance of OrientationObserver to initialize it.
  1.1117 +    OrientationObserver::GetInstance();
  1.1118 +}
  1.1119 +
  1.1120 +/* static */ void
  1.1121 +nsAppShell::NotifyScreenRotation()
  1.1122 +{
  1.1123 +    gAppShell->mReaderPolicy->setDisplayInfo();
  1.1124 +    gAppShell->mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
  1.1125 +
  1.1126 +    hal::NotifyScreenConfigurationChange(nsScreenGonk::GetConfiguration());
  1.1127 +}

mercurial