widget/gonk/OrientationObserver.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set sw=2 ts=8 et ft=cpp : */
     3 /* Copyright 2012 Mozilla Foundation and Mozilla contributors
     4  *
     5  * Licensed under the Apache License, Version 2.0 (the "License");
     6  * you may not use this file except in compliance with the License.
     7  * You may obtain a copy of the License at
     8  *
     9  *     http://www.apache.org/licenses/LICENSE-2.0
    10  *
    11  * Unless required by applicable law or agreed to in writing, software
    12  * distributed under the License is distributed on an "AS IS" BASIS,
    13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  * See the License for the specific language governing permissions and
    15  * limitations under the License.
    16  */
    18 #include "base/basictypes.h"
    19 #include "mozilla/ClearOnShutdown.h"
    20 #include "mozilla/StaticPtr.h"
    21 #include "mozilla/Hal.h"
    22 #include "nsIScreen.h"
    23 #include "nsIScreenManager.h"
    24 #include "OrientationObserver.h"
    25 #include "mozilla/HalSensor.h"
    26 #include "ProcessOrientation.h"
    27 #include "nsServiceManagerUtils.h"
    29 using namespace mozilla;
    30 using namespace dom;
    32 namespace {
    34 struct OrientationMapping {
    35   uint32_t mScreenRotation;
    36   ScreenOrientation mDomOrientation;
    37 };
    39 static OrientationMapping sOrientationMappings[] = {
    40   {nsIScreen::ROTATION_0_DEG,   eScreenOrientation_PortraitPrimary},
    41   {nsIScreen::ROTATION_180_DEG, eScreenOrientation_PortraitSecondary},
    42   {nsIScreen::ROTATION_90_DEG,  eScreenOrientation_LandscapePrimary},
    43   {nsIScreen::ROTATION_270_DEG, eScreenOrientation_LandscapeSecondary},
    44 };
    46 const static int sDefaultLandscape = 2;
    47 const static int sDefaultPortrait = 0;
    49 static uint32_t sOrientationOffset = 0;
    51 static already_AddRefed<nsIScreen>
    52 GetPrimaryScreen()
    53 {
    54   nsCOMPtr<nsIScreenManager> screenMgr =
    55     do_GetService("@mozilla.org/gfx/screenmanager;1");
    56   NS_ENSURE_TRUE(screenMgr, nullptr);
    58   nsCOMPtr<nsIScreen> screen;
    59   screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
    60   return screen.forget();
    61 }
    63 static void
    64 DetectDefaultOrientation()
    65 {
    66   nsCOMPtr<nsIScreen> screen = GetPrimaryScreen();
    67   if (!screen) {
    68     return;
    69   }
    71   int32_t left, top, width, height;
    72   if (NS_FAILED(screen->GetRect(&left, &top, &width, &height))) {
    73     return;
    74   }
    76   uint32_t rotation;
    77   if (NS_FAILED(screen->GetRotation(&rotation))) {
    78     return;
    79   }
    81   if (width < height) {
    82     if (rotation == nsIScreen::ROTATION_0_DEG ||
    83         rotation == nsIScreen::ROTATION_180_DEG) {
    84       sOrientationOffset = sDefaultPortrait;
    85     } else {
    86       sOrientationOffset = sDefaultLandscape;
    87     }
    88   } else {
    89     if (rotation == nsIScreen::ROTATION_0_DEG ||
    90         rotation == nsIScreen::ROTATION_180_DEG) {
    91       sOrientationOffset = sDefaultLandscape;
    92     } else {
    93       sOrientationOffset = sDefaultPortrait;
    94     }
    95   }
    96 }
    98 /**
    99  * Converts DOM orientation to nsIScreen rotation. Portrait and Landscape are
   100  * treated as PortraitPrimary and LandscapePrimary, respectively, during
   101  * conversion.
   102  *
   103  * @param aOrientation DOM orientation e.g.
   104  *        dom::eScreenOrientation_PortraitPrimary.
   105  * @param aResult output nsIScreen rotation e.g. nsIScreen::ROTATION_0_DEG.
   106  * @return NS_OK on success. NS_ILLEGAL_VALUE on failure.
   107  */
   108 static nsresult
   109 ConvertToScreenRotation(ScreenOrientation aOrientation, uint32_t *aResult)
   110 {
   111   for (int i = 0; i < ArrayLength(sOrientationMappings); i++) {
   112     if (aOrientation & sOrientationMappings[i].mDomOrientation) {
   113       // Shift the mappings in sOrientationMappings so devices with default
   114       // landscape orientation map landscape-primary to 0 degree and so forth.
   115       int adjusted = (i + sOrientationOffset) %
   116                      ArrayLength(sOrientationMappings);
   117       *aResult = sOrientationMappings[adjusted].mScreenRotation;
   118       return NS_OK;
   119     }
   120   }
   122   *aResult = nsIScreen::ROTATION_0_DEG;
   123   return NS_ERROR_ILLEGAL_VALUE;
   124 }
   126 /**
   127  * Converts nsIScreen rotation to DOM orientation.
   128  *
   129  * @param aRotation nsIScreen rotation e.g. nsIScreen::ROTATION_0_DEG.
   130  * @param aResult output DOM orientation e.g.
   131  *        dom::eScreenOrientation_PortraitPrimary.
   132  * @return NS_OK on success. NS_ILLEGAL_VALUE on failure.
   133  */
   134 nsresult
   135 ConvertToDomOrientation(uint32_t aRotation, ScreenOrientation *aResult)
   136 {
   137   for (int i = 0; i < ArrayLength(sOrientationMappings); i++) {
   138     if (aRotation == sOrientationMappings[i].mScreenRotation) {
   139       // Shift the mappings in sOrientationMappings so devices with default
   140       // landscape orientation map 0 degree to landscape-primary and so forth.
   141       int adjusted = (i + sOrientationOffset) %
   142                      ArrayLength(sOrientationMappings);
   143       *aResult = sOrientationMappings[adjusted].mDomOrientation;
   144       return NS_OK;
   145     }
   146   }
   148   *aResult = eScreenOrientation_None;
   149   return NS_ERROR_ILLEGAL_VALUE;
   150 }
   152 // Note that all operations with sOrientationSensorObserver
   153 // should be on the main thread.
   154 static StaticAutoPtr<OrientationObserver> sOrientationSensorObserver;
   156 } // Anonymous namespace
   158 OrientationObserver*
   159 OrientationObserver::GetInstance()
   160 {
   161   if (!sOrientationSensorObserver) {
   162     sOrientationSensorObserver = new OrientationObserver();
   163     ClearOnShutdown(&sOrientationSensorObserver);
   164   }
   166   return sOrientationSensorObserver;
   167 }
   169 OrientationObserver::OrientationObserver()
   170   : mAutoOrientationEnabled(false)
   171   , mAllowedOrientations(sDefaultOrientations)
   172   , mOrientation(new mozilla::ProcessOrientation())
   173 {
   174   DetectDefaultOrientation();
   176   EnableAutoOrientation();
   177 }
   179 OrientationObserver::~OrientationObserver()
   180 {
   181   if (mAutoOrientationEnabled) {
   182     DisableAutoOrientation();
   183   }
   184 }
   186 /* static */ void
   187 OrientationObserver::ShutDown()
   188 {
   189   if (!sOrientationSensorObserver) {
   190     return;
   191   }
   193   if (sOrientationSensorObserver->mAutoOrientationEnabled) {
   194     sOrientationSensorObserver->DisableAutoOrientation();
   195   }
   196 }
   198 void
   199 OrientationObserver::Notify(const hal::SensorData& aSensorData)
   200 {
   201   // Sensor will call us on the main thread.
   202   MOZ_ASSERT(NS_IsMainThread());
   203   MOZ_ASSERT(aSensorData.sensor() == hal::SensorType::SENSOR_ACCELERATION);
   205   nsCOMPtr<nsIScreen> screen = GetPrimaryScreen();
   206   if (!screen) {
   207     return;
   208   }
   210   uint32_t currRotation;
   211   if(NS_FAILED(screen->GetRotation(&currRotation))) {
   212     return;
   213   }
   215   int rotation = mOrientation->OnSensorChanged(aSensorData, static_cast<int>(currRotation));
   216   if (rotation < 0 || rotation == currRotation) {
   217     return;
   218   }
   220   ScreenOrientation orientation;
   221   if (NS_FAILED(ConvertToDomOrientation(rotation, &orientation))) {
   222     return;
   223   }
   225   if ((mAllowedOrientations & orientation) == eScreenOrientation_None) {
   226     // The orientation from sensor is not allowed.
   227     return;
   228   }
   230   if (NS_FAILED(screen->SetRotation(static_cast<uint32_t>(rotation)))) {
   231     // Don't notify dom on rotation failure.
   232     return;
   233   }
   234 }
   236 /**
   237  * Register the observer. Note that the observer shouldn't be registered.
   238  */
   239 void
   240 OrientationObserver::EnableAutoOrientation()
   241 {
   242   MOZ_ASSERT(NS_IsMainThread() && !mAutoOrientationEnabled);
   244   mOrientation->Reset();
   245   hal::RegisterSensorObserver(hal::SENSOR_ACCELERATION, this);
   246   mAutoOrientationEnabled = true;
   247 }
   249 /**
   250  * Unregister the observer. Note that the observer should already be registered.
   251  */
   252 void
   253 OrientationObserver::DisableAutoOrientation()
   254 {
   255   MOZ_ASSERT(NS_IsMainThread() && mAutoOrientationEnabled);
   257   hal::UnregisterSensorObserver(hal::SENSOR_ACCELERATION, this);
   258   mAutoOrientationEnabled = false;
   259 }
   261 bool
   262 OrientationObserver::LockScreenOrientation(ScreenOrientation aOrientation)
   263 {
   264   MOZ_ASSERT(aOrientation | (eScreenOrientation_PortraitPrimary |
   265                              eScreenOrientation_PortraitSecondary |
   266                              eScreenOrientation_LandscapePrimary |
   267                              eScreenOrientation_LandscapeSecondary |
   268                              eScreenOrientation_Default));
   270   if (aOrientation == eScreenOrientation_Default) {
   271     aOrientation = (sOrientationOffset == sDefaultPortrait) ?
   272                     eScreenOrientation_PortraitPrimary :
   273                     eScreenOrientation_LandscapePrimary;
   274   }
   276   // If there are multiple orientations allowed, we should enable the
   277   // auto-rotation.
   278   if (aOrientation != eScreenOrientation_LandscapePrimary &&
   279       aOrientation != eScreenOrientation_LandscapeSecondary &&
   280       aOrientation != eScreenOrientation_PortraitPrimary &&
   281       aOrientation != eScreenOrientation_PortraitSecondary) {
   282     if (!mAutoOrientationEnabled) {
   283       EnableAutoOrientation();
   284     }
   285   } else if (mAutoOrientationEnabled) {
   286     DisableAutoOrientation();
   287   }
   289   mAllowedOrientations = aOrientation;
   291   nsCOMPtr<nsIScreen> screen = GetPrimaryScreen();
   292   NS_ENSURE_TRUE(screen, false);
   294   uint32_t currRotation;
   295   nsresult rv = screen->GetRotation(&currRotation);
   296   NS_ENSURE_SUCCESS(rv, false);
   298   ScreenOrientation currOrientation = eScreenOrientation_None;
   299   rv = ConvertToDomOrientation(currRotation, &currOrientation);
   300   NS_ENSURE_SUCCESS(rv, false);
   302   // Don't rotate if the current orientation matches one of the
   303   // requested orientations.
   304   if (currOrientation & aOrientation) {
   305     return true;
   306   }
   308   // Return false on invalid orientation value.
   309   uint32_t rotation;
   310   rv = ConvertToScreenRotation(aOrientation, &rotation);
   311   NS_ENSURE_SUCCESS(rv, false);
   313   rv = screen->SetRotation(rotation);
   314   NS_ENSURE_SUCCESS(rv, false);
   316   // This conversion will disambiguate aOrientation.
   317   ScreenOrientation orientation;
   318   rv = ConvertToDomOrientation(rotation, &orientation);
   319   NS_ENSURE_SUCCESS(rv, false);
   321   return true;
   322 }
   324 void
   325 OrientationObserver::UnlockScreenOrientation()
   326 {
   327   if (!mAutoOrientationEnabled) {
   328     EnableAutoOrientation();
   329   }
   331   mAllowedOrientations = sDefaultOrientations;
   332 }

mercurial