widget/gonk/nsAppShell.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

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

mercurial