Wed, 31 Dec 2014 07:22:50 +0100
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 | } |