widget/gonk/OrientationObserver.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: 2 -*- */
michael@0 2 /* vim: set sw=2 ts=8 et ft=cpp : */
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 #include "base/basictypes.h"
michael@0 19 #include "mozilla/ClearOnShutdown.h"
michael@0 20 #include "mozilla/StaticPtr.h"
michael@0 21 #include "mozilla/Hal.h"
michael@0 22 #include "nsIScreen.h"
michael@0 23 #include "nsIScreenManager.h"
michael@0 24 #include "OrientationObserver.h"
michael@0 25 #include "mozilla/HalSensor.h"
michael@0 26 #include "ProcessOrientation.h"
michael@0 27 #include "nsServiceManagerUtils.h"
michael@0 28
michael@0 29 using namespace mozilla;
michael@0 30 using namespace dom;
michael@0 31
michael@0 32 namespace {
michael@0 33
michael@0 34 struct OrientationMapping {
michael@0 35 uint32_t mScreenRotation;
michael@0 36 ScreenOrientation mDomOrientation;
michael@0 37 };
michael@0 38
michael@0 39 static OrientationMapping sOrientationMappings[] = {
michael@0 40 {nsIScreen::ROTATION_0_DEG, eScreenOrientation_PortraitPrimary},
michael@0 41 {nsIScreen::ROTATION_180_DEG, eScreenOrientation_PortraitSecondary},
michael@0 42 {nsIScreen::ROTATION_90_DEG, eScreenOrientation_LandscapePrimary},
michael@0 43 {nsIScreen::ROTATION_270_DEG, eScreenOrientation_LandscapeSecondary},
michael@0 44 };
michael@0 45
michael@0 46 const static int sDefaultLandscape = 2;
michael@0 47 const static int sDefaultPortrait = 0;
michael@0 48
michael@0 49 static uint32_t sOrientationOffset = 0;
michael@0 50
michael@0 51 static already_AddRefed<nsIScreen>
michael@0 52 GetPrimaryScreen()
michael@0 53 {
michael@0 54 nsCOMPtr<nsIScreenManager> screenMgr =
michael@0 55 do_GetService("@mozilla.org/gfx/screenmanager;1");
michael@0 56 NS_ENSURE_TRUE(screenMgr, nullptr);
michael@0 57
michael@0 58 nsCOMPtr<nsIScreen> screen;
michael@0 59 screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
michael@0 60 return screen.forget();
michael@0 61 }
michael@0 62
michael@0 63 static void
michael@0 64 DetectDefaultOrientation()
michael@0 65 {
michael@0 66 nsCOMPtr<nsIScreen> screen = GetPrimaryScreen();
michael@0 67 if (!screen) {
michael@0 68 return;
michael@0 69 }
michael@0 70
michael@0 71 int32_t left, top, width, height;
michael@0 72 if (NS_FAILED(screen->GetRect(&left, &top, &width, &height))) {
michael@0 73 return;
michael@0 74 }
michael@0 75
michael@0 76 uint32_t rotation;
michael@0 77 if (NS_FAILED(screen->GetRotation(&rotation))) {
michael@0 78 return;
michael@0 79 }
michael@0 80
michael@0 81 if (width < height) {
michael@0 82 if (rotation == nsIScreen::ROTATION_0_DEG ||
michael@0 83 rotation == nsIScreen::ROTATION_180_DEG) {
michael@0 84 sOrientationOffset = sDefaultPortrait;
michael@0 85 } else {
michael@0 86 sOrientationOffset = sDefaultLandscape;
michael@0 87 }
michael@0 88 } else {
michael@0 89 if (rotation == nsIScreen::ROTATION_0_DEG ||
michael@0 90 rotation == nsIScreen::ROTATION_180_DEG) {
michael@0 91 sOrientationOffset = sDefaultLandscape;
michael@0 92 } else {
michael@0 93 sOrientationOffset = sDefaultPortrait;
michael@0 94 }
michael@0 95 }
michael@0 96 }
michael@0 97
michael@0 98 /**
michael@0 99 * Converts DOM orientation to nsIScreen rotation. Portrait and Landscape are
michael@0 100 * treated as PortraitPrimary and LandscapePrimary, respectively, during
michael@0 101 * conversion.
michael@0 102 *
michael@0 103 * @param aOrientation DOM orientation e.g.
michael@0 104 * dom::eScreenOrientation_PortraitPrimary.
michael@0 105 * @param aResult output nsIScreen rotation e.g. nsIScreen::ROTATION_0_DEG.
michael@0 106 * @return NS_OK on success. NS_ILLEGAL_VALUE on failure.
michael@0 107 */
michael@0 108 static nsresult
michael@0 109 ConvertToScreenRotation(ScreenOrientation aOrientation, uint32_t *aResult)
michael@0 110 {
michael@0 111 for (int i = 0; i < ArrayLength(sOrientationMappings); i++) {
michael@0 112 if (aOrientation & sOrientationMappings[i].mDomOrientation) {
michael@0 113 // Shift the mappings in sOrientationMappings so devices with default
michael@0 114 // landscape orientation map landscape-primary to 0 degree and so forth.
michael@0 115 int adjusted = (i + sOrientationOffset) %
michael@0 116 ArrayLength(sOrientationMappings);
michael@0 117 *aResult = sOrientationMappings[adjusted].mScreenRotation;
michael@0 118 return NS_OK;
michael@0 119 }
michael@0 120 }
michael@0 121
michael@0 122 *aResult = nsIScreen::ROTATION_0_DEG;
michael@0 123 return NS_ERROR_ILLEGAL_VALUE;
michael@0 124 }
michael@0 125
michael@0 126 /**
michael@0 127 * Converts nsIScreen rotation to DOM orientation.
michael@0 128 *
michael@0 129 * @param aRotation nsIScreen rotation e.g. nsIScreen::ROTATION_0_DEG.
michael@0 130 * @param aResult output DOM orientation e.g.
michael@0 131 * dom::eScreenOrientation_PortraitPrimary.
michael@0 132 * @return NS_OK on success. NS_ILLEGAL_VALUE on failure.
michael@0 133 */
michael@0 134 nsresult
michael@0 135 ConvertToDomOrientation(uint32_t aRotation, ScreenOrientation *aResult)
michael@0 136 {
michael@0 137 for (int i = 0; i < ArrayLength(sOrientationMappings); i++) {
michael@0 138 if (aRotation == sOrientationMappings[i].mScreenRotation) {
michael@0 139 // Shift the mappings in sOrientationMappings so devices with default
michael@0 140 // landscape orientation map 0 degree to landscape-primary and so forth.
michael@0 141 int adjusted = (i + sOrientationOffset) %
michael@0 142 ArrayLength(sOrientationMappings);
michael@0 143 *aResult = sOrientationMappings[adjusted].mDomOrientation;
michael@0 144 return NS_OK;
michael@0 145 }
michael@0 146 }
michael@0 147
michael@0 148 *aResult = eScreenOrientation_None;
michael@0 149 return NS_ERROR_ILLEGAL_VALUE;
michael@0 150 }
michael@0 151
michael@0 152 // Note that all operations with sOrientationSensorObserver
michael@0 153 // should be on the main thread.
michael@0 154 static StaticAutoPtr<OrientationObserver> sOrientationSensorObserver;
michael@0 155
michael@0 156 } // Anonymous namespace
michael@0 157
michael@0 158 OrientationObserver*
michael@0 159 OrientationObserver::GetInstance()
michael@0 160 {
michael@0 161 if (!sOrientationSensorObserver) {
michael@0 162 sOrientationSensorObserver = new OrientationObserver();
michael@0 163 ClearOnShutdown(&sOrientationSensorObserver);
michael@0 164 }
michael@0 165
michael@0 166 return sOrientationSensorObserver;
michael@0 167 }
michael@0 168
michael@0 169 OrientationObserver::OrientationObserver()
michael@0 170 : mAutoOrientationEnabled(false)
michael@0 171 , mAllowedOrientations(sDefaultOrientations)
michael@0 172 , mOrientation(new mozilla::ProcessOrientation())
michael@0 173 {
michael@0 174 DetectDefaultOrientation();
michael@0 175
michael@0 176 EnableAutoOrientation();
michael@0 177 }
michael@0 178
michael@0 179 OrientationObserver::~OrientationObserver()
michael@0 180 {
michael@0 181 if (mAutoOrientationEnabled) {
michael@0 182 DisableAutoOrientation();
michael@0 183 }
michael@0 184 }
michael@0 185
michael@0 186 /* static */ void
michael@0 187 OrientationObserver::ShutDown()
michael@0 188 {
michael@0 189 if (!sOrientationSensorObserver) {
michael@0 190 return;
michael@0 191 }
michael@0 192
michael@0 193 if (sOrientationSensorObserver->mAutoOrientationEnabled) {
michael@0 194 sOrientationSensorObserver->DisableAutoOrientation();
michael@0 195 }
michael@0 196 }
michael@0 197
michael@0 198 void
michael@0 199 OrientationObserver::Notify(const hal::SensorData& aSensorData)
michael@0 200 {
michael@0 201 // Sensor will call us on the main thread.
michael@0 202 MOZ_ASSERT(NS_IsMainThread());
michael@0 203 MOZ_ASSERT(aSensorData.sensor() == hal::SensorType::SENSOR_ACCELERATION);
michael@0 204
michael@0 205 nsCOMPtr<nsIScreen> screen = GetPrimaryScreen();
michael@0 206 if (!screen) {
michael@0 207 return;
michael@0 208 }
michael@0 209
michael@0 210 uint32_t currRotation;
michael@0 211 if(NS_FAILED(screen->GetRotation(&currRotation))) {
michael@0 212 return;
michael@0 213 }
michael@0 214
michael@0 215 int rotation = mOrientation->OnSensorChanged(aSensorData, static_cast<int>(currRotation));
michael@0 216 if (rotation < 0 || rotation == currRotation) {
michael@0 217 return;
michael@0 218 }
michael@0 219
michael@0 220 ScreenOrientation orientation;
michael@0 221 if (NS_FAILED(ConvertToDomOrientation(rotation, &orientation))) {
michael@0 222 return;
michael@0 223 }
michael@0 224
michael@0 225 if ((mAllowedOrientations & orientation) == eScreenOrientation_None) {
michael@0 226 // The orientation from sensor is not allowed.
michael@0 227 return;
michael@0 228 }
michael@0 229
michael@0 230 if (NS_FAILED(screen->SetRotation(static_cast<uint32_t>(rotation)))) {
michael@0 231 // Don't notify dom on rotation failure.
michael@0 232 return;
michael@0 233 }
michael@0 234 }
michael@0 235
michael@0 236 /**
michael@0 237 * Register the observer. Note that the observer shouldn't be registered.
michael@0 238 */
michael@0 239 void
michael@0 240 OrientationObserver::EnableAutoOrientation()
michael@0 241 {
michael@0 242 MOZ_ASSERT(NS_IsMainThread() && !mAutoOrientationEnabled);
michael@0 243
michael@0 244 mOrientation->Reset();
michael@0 245 hal::RegisterSensorObserver(hal::SENSOR_ACCELERATION, this);
michael@0 246 mAutoOrientationEnabled = true;
michael@0 247 }
michael@0 248
michael@0 249 /**
michael@0 250 * Unregister the observer. Note that the observer should already be registered.
michael@0 251 */
michael@0 252 void
michael@0 253 OrientationObserver::DisableAutoOrientation()
michael@0 254 {
michael@0 255 MOZ_ASSERT(NS_IsMainThread() && mAutoOrientationEnabled);
michael@0 256
michael@0 257 hal::UnregisterSensorObserver(hal::SENSOR_ACCELERATION, this);
michael@0 258 mAutoOrientationEnabled = false;
michael@0 259 }
michael@0 260
michael@0 261 bool
michael@0 262 OrientationObserver::LockScreenOrientation(ScreenOrientation aOrientation)
michael@0 263 {
michael@0 264 MOZ_ASSERT(aOrientation | (eScreenOrientation_PortraitPrimary |
michael@0 265 eScreenOrientation_PortraitSecondary |
michael@0 266 eScreenOrientation_LandscapePrimary |
michael@0 267 eScreenOrientation_LandscapeSecondary |
michael@0 268 eScreenOrientation_Default));
michael@0 269
michael@0 270 if (aOrientation == eScreenOrientation_Default) {
michael@0 271 aOrientation = (sOrientationOffset == sDefaultPortrait) ?
michael@0 272 eScreenOrientation_PortraitPrimary :
michael@0 273 eScreenOrientation_LandscapePrimary;
michael@0 274 }
michael@0 275
michael@0 276 // If there are multiple orientations allowed, we should enable the
michael@0 277 // auto-rotation.
michael@0 278 if (aOrientation != eScreenOrientation_LandscapePrimary &&
michael@0 279 aOrientation != eScreenOrientation_LandscapeSecondary &&
michael@0 280 aOrientation != eScreenOrientation_PortraitPrimary &&
michael@0 281 aOrientation != eScreenOrientation_PortraitSecondary) {
michael@0 282 if (!mAutoOrientationEnabled) {
michael@0 283 EnableAutoOrientation();
michael@0 284 }
michael@0 285 } else if (mAutoOrientationEnabled) {
michael@0 286 DisableAutoOrientation();
michael@0 287 }
michael@0 288
michael@0 289 mAllowedOrientations = aOrientation;
michael@0 290
michael@0 291 nsCOMPtr<nsIScreen> screen = GetPrimaryScreen();
michael@0 292 NS_ENSURE_TRUE(screen, false);
michael@0 293
michael@0 294 uint32_t currRotation;
michael@0 295 nsresult rv = screen->GetRotation(&currRotation);
michael@0 296 NS_ENSURE_SUCCESS(rv, false);
michael@0 297
michael@0 298 ScreenOrientation currOrientation = eScreenOrientation_None;
michael@0 299 rv = ConvertToDomOrientation(currRotation, &currOrientation);
michael@0 300 NS_ENSURE_SUCCESS(rv, false);
michael@0 301
michael@0 302 // Don't rotate if the current orientation matches one of the
michael@0 303 // requested orientations.
michael@0 304 if (currOrientation & aOrientation) {
michael@0 305 return true;
michael@0 306 }
michael@0 307
michael@0 308 // Return false on invalid orientation value.
michael@0 309 uint32_t rotation;
michael@0 310 rv = ConvertToScreenRotation(aOrientation, &rotation);
michael@0 311 NS_ENSURE_SUCCESS(rv, false);
michael@0 312
michael@0 313 rv = screen->SetRotation(rotation);
michael@0 314 NS_ENSURE_SUCCESS(rv, false);
michael@0 315
michael@0 316 // This conversion will disambiguate aOrientation.
michael@0 317 ScreenOrientation orientation;
michael@0 318 rv = ConvertToDomOrientation(rotation, &orientation);
michael@0 319 NS_ENSURE_SUCCESS(rv, false);
michael@0 320
michael@0 321 return true;
michael@0 322 }
michael@0 323
michael@0 324 void
michael@0 325 OrientationObserver::UnlockScreenOrientation()
michael@0 326 {
michael@0 327 if (!mAutoOrientationEnabled) {
michael@0 328 EnableAutoOrientation();
michael@0 329 }
michael@0 330
michael@0 331 mAllowedOrientations = sDefaultOrientations;
michael@0 332 }

mercurial