Commit 166ec042 authored by Bo Liu's avatar Bo Liu Committed by Chromium LUCI CQ

android: Recreating activity for orientation

ScreenOrientationProvider(Impl) is currently coded to assume the
embedding Activity handles (and thus is not destroyed and recreated) on
orientation change. All the API methods take WindowAndroid.

This does not work for embedder that recreates the Activity (and by
extension the WindowAndroid) on orientation change. This causes
orientation requests made in this transition time to be completely
dropped.

Fix this for cases for requests made from WebContents from native code.
If there is no WindowAndroid, add an observer to to wait until
WebContents gets a WindowAndroid to make the request.

Bug: 1159529
Change-Id: Iae177faffa67d3e4db58ea1e0d5a9df989d303a9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2603856
Commit-Queue: Bo <boliu@chromium.org>
Reviewed-by: default avatarMounir Lamouri <mlamouri@chromium.org>
Cr-Commit-Position: refs/heads/master@{#841606}
parent e2aa9036
...@@ -6,9 +6,8 @@ ...@@ -6,9 +6,8 @@
#include "base/android/scoped_java_ref.h" #include "base/android/scoped_java_ref.h"
#include "content/browser/screen_orientation/screen_orientation_provider.h" #include "content/browser/screen_orientation/screen_orientation_provider.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/android/content_jni_headers/ScreenOrientationProviderImpl_jni.h" #include "content/public/android/content_jni_headers/ScreenOrientationProviderImpl_jni.h"
#include "ui/android/window_android.h"
#include "ui/gfx/native_widget_types.h"
namespace content { namespace content {
...@@ -31,10 +30,9 @@ void ScreenOrientationDelegateAndroid::Lock( ...@@ -31,10 +30,9 @@ void ScreenOrientationDelegateAndroid::Lock(
base::android::ScopedJavaLocalRef<jobject> java_instance = base::android::ScopedJavaLocalRef<jobject> java_instance =
Java_ScreenOrientationProviderImpl_getInstance( Java_ScreenOrientationProviderImpl_getInstance(
base::android::AttachCurrentThread()); base::android::AttachCurrentThread());
gfx::NativeWindow window = web_contents->GetTopLevelNativeWindow(); Java_ScreenOrientationProviderImpl_lockOrientationForWebContents(
Java_ScreenOrientationProviderImpl_lockOrientation(
base::android::AttachCurrentThread(), java_instance, base::android::AttachCurrentThread(), java_instance,
window ? window->GetJavaObject() : nullptr, static_cast<WebContentsImpl*>(web_contents)->GetJavaWebContents(),
static_cast<jbyte>(lock_orientation)); static_cast<jbyte>(lock_orientation));
} }
...@@ -53,10 +51,9 @@ void ScreenOrientationDelegateAndroid::Unlock(WebContents* web_contents) { ...@@ -53,10 +51,9 @@ void ScreenOrientationDelegateAndroid::Unlock(WebContents* web_contents) {
base::android::ScopedJavaLocalRef<jobject> java_instance = base::android::ScopedJavaLocalRef<jobject> java_instance =
Java_ScreenOrientationProviderImpl_getInstance( Java_ScreenOrientationProviderImpl_getInstance(
base::android::AttachCurrentThread()); base::android::AttachCurrentThread());
gfx::NativeWindow window = web_contents->GetTopLevelNativeWindow(); Java_ScreenOrientationProviderImpl_unlockOrientationForWebContents(
Java_ScreenOrientationProviderImpl_unlockOrientation(
base::android::AttachCurrentThread(), java_instance, base::android::AttachCurrentThread(), java_instance,
window ? window->GetJavaObject() : nullptr); static_cast<WebContentsImpl*>(web_contents)->GetJavaWebContents());
} }
} // namespace content } // namespace content
...@@ -21,6 +21,7 @@ import org.chromium.base.annotations.CalledByNative; ...@@ -21,6 +21,7 @@ import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.JNINamespace;
import org.chromium.content_public.browser.ScreenOrientationDelegate; import org.chromium.content_public.browser.ScreenOrientationDelegate;
import org.chromium.content_public.browser.ScreenOrientationProvider; import org.chromium.content_public.browser.ScreenOrientationProvider;
import org.chromium.content_public.browser.WebContents;
import org.chromium.device.mojom.ScreenOrientationLockType; import org.chromium.device.mojom.ScreenOrientationLockType;
import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.display.DisplayAndroid; import org.chromium.ui.display.DisplayAndroid;
...@@ -41,6 +42,10 @@ public class ScreenOrientationProviderImpl ...@@ -41,6 +42,10 @@ public class ScreenOrientationProviderImpl
private static final String TAG = "ScreenOrientation"; private static final String TAG = "ScreenOrientation";
// More readable constants to be passed to |addPendingRequest|.
private static final boolean LOCK = true;
private static final boolean UNLOCK = false;
private ScreenOrientationDelegate mDelegate; private ScreenOrientationDelegate mDelegate;
/** /**
...@@ -60,6 +65,45 @@ public class ScreenOrientationProviderImpl ...@@ -60,6 +65,45 @@ public class ScreenOrientationProviderImpl
*/ */
private Map<Activity, Pair<Boolean, Integer>> mDelayedRequests = new WeakHashMap<>(); private Map<Activity, Pair<Boolean, Integer>> mDelayedRequests = new WeakHashMap<>();
private static final class PendingRequest implements WindowEventObserver {
private final ScreenOrientationProviderImpl mProvider;
private final WindowEventObserverManager mWindowEventManager;
private final boolean mLockOrUnlock;
private final byte mWebScreenOrientation;
private boolean mObserverRemoved;
public PendingRequest(ScreenOrientationProviderImpl provider,
WindowEventObserverManager windowEventManager, boolean lockOrUnlock,
byte webScreenOrientation) {
mProvider = provider;
mWindowEventManager = windowEventManager;
mLockOrUnlock = lockOrUnlock;
mWebScreenOrientation = webScreenOrientation;
mWindowEventManager.addObserver(this);
}
public void cancel() {
if (mObserverRemoved) return;
mWindowEventManager.removeObserver(this);
mObserverRemoved = true;
}
@Override
public void onWindowAndroidChanged(WindowAndroid newWindowAndroid) {
if (newWindowAndroid == null) return;
if (mLockOrUnlock) {
mProvider.lockOrientation(newWindowAndroid, mWebScreenOrientation);
} else {
mProvider.unlockOrientation(newWindowAndroid);
}
mWindowEventManager.removeObserver(this);
mObserverRemoved = true;
}
}
private final Map<WebContents, PendingRequest> mPendingRequests = new WeakHashMap<>();
@CalledByNative @CalledByNative
public static ScreenOrientationProviderImpl getInstance() { public static ScreenOrientationProviderImpl getInstance() {
return Holder.sInstance; return Holder.sInstance;
...@@ -114,7 +158,26 @@ public class ScreenOrientationProviderImpl ...@@ -114,7 +158,26 @@ public class ScreenOrientationProviderImpl
} }
} }
private void addPendingRequest(
WebContents webContents, boolean lockOrUnlock, byte webScreenOrientation) {
WindowEventObserverManager windowEventManager =
WindowEventObserverManager.from(webContents);
PendingRequest existingRequest = mPendingRequests.get(webContents);
if (existingRequest != null) existingRequest.cancel();
mPendingRequests.put(webContents,
new PendingRequest(this, windowEventManager, lockOrUnlock, webScreenOrientation));
}
@CalledByNative @CalledByNative
private void lockOrientationForWebContents(WebContents webContents, byte webScreenOrientation) {
WindowAndroid window = webContents.getTopLevelNativeWindow();
if (window == null) {
addPendingRequest(webContents, LOCK, webScreenOrientation);
} else {
lockOrientation(window, webScreenOrientation);
}
}
@Override @Override
public void lockOrientation(@Nullable WindowAndroid window, byte webScreenOrientation) { public void lockOrientation(@Nullable WindowAndroid window, byte webScreenOrientation) {
// WindowAndroid may be null if the tab is being reparented. // WindowAndroid may be null if the tab is being reparented.
...@@ -136,6 +199,15 @@ public class ScreenOrientationProviderImpl ...@@ -136,6 +199,15 @@ public class ScreenOrientationProviderImpl
} }
@CalledByNative @CalledByNative
private void unlockOrientationForWebContents(WebContents webContents) {
WindowAndroid window = webContents.getTopLevelNativeWindow();
if (window == null) {
addPendingRequest(webContents, UNLOCK, (byte) 0);
} else {
unlockOrientation(window);
}
}
@Override @Override
public void unlockOrientation(@Nullable WindowAndroid window) { public void unlockOrientation(@Nullable WindowAndroid window) {
// WindowAndroid may be null if the tab is being reparented. // WindowAndroid may be null if the tab is being reparented.
......
...@@ -11,6 +11,8 @@ import org.chromium.ui.base.WindowAndroid; ...@@ -11,6 +11,8 @@ import org.chromium.ui.base.WindowAndroid;
/** /**
* Interface providing the access to C++ ScreenOrientationProvider. * Interface providing the access to C++ ScreenOrientationProvider.
* TODO(boliu): This interface working with WindowAndroid does not support the use case
* when an Activity (and WindowAndroid) is recreated on rotation.
*/ */
public interface ScreenOrientationProvider { public interface ScreenOrientationProvider {
static ScreenOrientationProvider getInstance() { static ScreenOrientationProvider getInstance() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment