Home | History | Annotate | Download | only in screen_orientation
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/browser/screen_orientation/screen_orientation_provider_android.h"
      6 
      7 #include "content/browser/android/content_view_core_impl.h"
      8 #include "content/browser/web_contents/web_contents_impl.h"
      9 #include "content/public/browser/render_view_host.h"
     10 #include "content/public/browser/render_widget_host.h"
     11 #include "content/public/browser/screen_orientation_dispatcher_host.h"
     12 #include "jni/ScreenOrientationProvider_jni.h"
     13 #include "third_party/WebKit/public/platform/WebLockOrientationError.h"
     14 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
     15 
     16 namespace content {
     17 
     18 ScreenOrientationProviderAndroid::LockInformation::LockInformation(
     19     int request_id, blink::WebScreenOrientationLockType lock)
     20     : request_id(request_id), lock(lock) {}
     21 
     22 ScreenOrientationProviderAndroid::ScreenOrientationProviderAndroid(
     23     ScreenOrientationDispatcherHost* dispatcher,
     24     WebContents* web_contents)
     25     : ScreenOrientationProvider(),
     26       WebContentsObserver(web_contents),
     27       dispatcher_(dispatcher),
     28       lock_applied_(false),
     29       pending_lock_(NULL) {
     30 }
     31 
     32 ScreenOrientationProviderAndroid::~ScreenOrientationProviderAndroid() {
     33   if (pending_lock_)
     34     delete pending_lock_;
     35 }
     36 
     37 WebContentsImpl* ScreenOrientationProviderAndroid::web_contents_impl() {
     38   return static_cast<WebContentsImpl*>(web_contents());
     39 }
     40 
     41 // static
     42 bool ScreenOrientationProviderAndroid::Register(JNIEnv* env) {
     43   return RegisterNativesImpl(env);
     44 }
     45 
     46 void ScreenOrientationProviderAndroid::LockOrientation(
     47     int request_id,
     48     blink::WebScreenOrientationLockType lock_orientation) {
     49   ContentViewCoreImpl* cvc =
     50       ContentViewCoreImpl::FromWebContents(web_contents());
     51   bool fullscreen_required = cvc ? cvc->IsFullscreenRequiredForOrientationLock()
     52                                  : true;
     53 
     54   if (fullscreen_required &&
     55       !web_contents_impl()->IsFullscreenForCurrentTab()) {
     56     dispatcher_->NotifyLockError(
     57         request_id,
     58         blink::WebLockOrientationErrorFullScreenRequired);
     59     return;
     60   }
     61 
     62   if (lock_orientation == blink::WebScreenOrientationLockNatural) {
     63     lock_orientation = GetNaturalLockType();
     64     if (lock_orientation == blink::WebScreenOrientationLockDefault) {
     65       // We are in a broken state, let's pretend we got canceled.
     66       dispatcher_->NotifyLockError(request_id,
     67                                    blink::WebLockOrientationErrorCanceled);
     68       return;
     69     }
     70   }
     71 
     72   lock_applied_ = true;
     73   Java_ScreenOrientationProvider_lockOrientation(
     74       base::android::AttachCurrentThread(), lock_orientation);
     75 
     76   // If two calls happen close to each other, Android will ignore the first.
     77   if (pending_lock_) {
     78     delete pending_lock_;
     79     pending_lock_ = NULL;
     80   }
     81 
     82   // If the orientation we are locking to matches the current orientation, we
     83   // should succeed immediately.
     84   if (LockMatchesCurrentOrientation(lock_orientation)) {
     85     dispatcher_->NotifyLockSuccess(request_id);
     86     return;
     87   }
     88 
     89   pending_lock_ = new LockInformation(request_id, lock_orientation);
     90 }
     91 
     92 void ScreenOrientationProviderAndroid::UnlockOrientation() {
     93   if (!lock_applied_)
     94     return;
     95 
     96   Java_ScreenOrientationProvider_unlockOrientation(
     97       base::android::AttachCurrentThread());
     98   lock_applied_ = false;
     99 }
    100 
    101 void ScreenOrientationProviderAndroid::OnOrientationChange() {
    102   if (!pending_lock_)
    103     return;
    104 
    105   if (LockMatchesCurrentOrientation(pending_lock_->lock)) {
    106     dispatcher_->NotifyLockSuccess(pending_lock_->request_id);
    107     delete pending_lock_;
    108     pending_lock_ = NULL;
    109   }
    110 }
    111 
    112 void ScreenOrientationProviderAndroid::DidToggleFullscreenModeForTab(
    113     bool entered_fullscreen) {
    114   if (!lock_applied_)
    115     return;
    116 
    117   // If fullscreen is not required in order to lock orientation, don't unlock
    118   // when fullscreen state changes.
    119   ContentViewCoreImpl* cvc =
    120       ContentViewCoreImpl::FromWebContents(web_contents());
    121   if (cvc && !cvc->IsFullscreenRequiredForOrientationLock())
    122     return;
    123 
    124   DCHECK(!entered_fullscreen);
    125   UnlockOrientation();
    126 }
    127 
    128 bool ScreenOrientationProviderAndroid::LockMatchesCurrentOrientation(
    129     blink::WebScreenOrientationLockType lock_orientation) {
    130   if (!web_contents()->GetRenderViewHost())
    131     return false;
    132 
    133   RenderWidgetHost* rwh = web_contents()->GetRenderViewHost();
    134   blink::WebScreenInfo screen_info;
    135   rwh->GetWebScreenInfo(&screen_info);
    136 
    137   switch (lock_orientation) {
    138   case blink::WebScreenOrientationLockPortraitPrimary:
    139     return screen_info.orientationType ==
    140         blink::WebScreenOrientationPortraitPrimary;
    141   case blink::WebScreenOrientationLockPortraitSecondary:
    142     return screen_info.orientationType ==
    143         blink::WebScreenOrientationPortraitSecondary;
    144   case blink::WebScreenOrientationLockLandscapePrimary:
    145     return screen_info.orientationType ==
    146         blink::WebScreenOrientationLandscapePrimary;
    147   case blink::WebScreenOrientationLockLandscapeSecondary:
    148     return screen_info.orientationType ==
    149         blink::WebScreenOrientationLandscapeSecondary;
    150   case blink::WebScreenOrientationLockLandscape:
    151     return screen_info.orientationType ==
    152         blink::WebScreenOrientationLandscapePrimary ||
    153         screen_info.orientationType ==
    154         blink::WebScreenOrientationLandscapeSecondary;
    155   case blink::WebScreenOrientationLockPortrait:
    156     return screen_info.orientationType ==
    157         blink::WebScreenOrientationPortraitPrimary ||
    158         screen_info.orientationType ==
    159         blink::WebScreenOrientationPortraitSecondary;
    160   case blink::WebScreenOrientationLockAny:
    161     return true;
    162   case blink::WebScreenOrientationLockNatural:
    163   case blink::WebScreenOrientationLockDefault:
    164     NOTREACHED();
    165     return false;
    166   }
    167 
    168   NOTREACHED();
    169   return false;
    170 }
    171 
    172 blink::WebScreenOrientationLockType
    173 ScreenOrientationProviderAndroid::GetNaturalLockType() const {
    174   if (!web_contents()->GetRenderViewHost())
    175     return blink::WebScreenOrientationLockDefault;
    176 
    177   RenderWidgetHost* rwh = web_contents()->GetRenderViewHost();
    178   blink::WebScreenInfo screen_info;
    179   rwh->GetWebScreenInfo(&screen_info);
    180 
    181   switch (screen_info.orientationType) {
    182   case blink::WebScreenOrientationPortraitPrimary:
    183   case blink::WebScreenOrientationPortraitSecondary:
    184     if (screen_info.orientationAngle == 0 ||
    185         screen_info.orientationAngle == 180) {
    186       return blink::WebScreenOrientationLockPortraitPrimary;
    187     }
    188     return blink::WebScreenOrientationLockLandscapePrimary;
    189   case blink::WebScreenOrientationLandscapePrimary:
    190   case blink::WebScreenOrientationLandscapeSecondary:
    191     if (screen_info.orientationAngle == 0 ||
    192         screen_info.orientationAngle == 180) {
    193       return blink::WebScreenOrientationLockLandscapePrimary;
    194     }
    195     return blink::WebScreenOrientationLockPortraitPrimary;
    196   case blink::WebScreenOrientationUndefined:
    197     NOTREACHED();
    198     return blink::WebScreenOrientationLockDefault;
    199   }
    200 
    201   NOTREACHED();
    202   return blink::WebScreenOrientationLockDefault;
    203 }
    204 
    205 // static
    206 void ScreenOrientationProviderAndroid::StartAccurateListening() {
    207   Java_ScreenOrientationProvider_startAccurateListening(
    208       base::android::AttachCurrentThread());
    209 }
    210 
    211 // static
    212 void ScreenOrientationProviderAndroid::StopAccurateListening() {
    213   Java_ScreenOrientationProvider_stopAccurateListening(
    214       base::android::AttachCurrentThread());
    215 }
    216 
    217 // static
    218 ScreenOrientationProvider* ScreenOrientationProvider::Create(
    219     ScreenOrientationDispatcherHost* dispatcher,
    220     WebContents* web_contents) {
    221   return new ScreenOrientationProviderAndroid(dispatcher, web_contents);
    222 }
    223 
    224 } // namespace content
    225