Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1065)

Unified Diff: ui/android/java/src/org/chromium/ui/display/DisplayAndroidManager.java

Issue 2361633002: android: Introduce DisplayAndroid (Closed)
Patch Set: test comments Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/android/java/src/org/chromium/ui/display/DisplayAndroidManager.java
diff --git a/ui/android/java/src/org/chromium/ui/display/DisplayAndroidManager.java b/ui/android/java/src/org/chromium/ui/display/DisplayAndroidManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..96a310dfd809a8616fdf2aeb53aaad408eb5e5b6
--- /dev/null
+++ b/ui/android/java/src/org/chromium/ui/display/DisplayAndroidManager.java
@@ -0,0 +1,237 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.ui.display;
+
+import android.annotation.SuppressLint;
+import android.content.ComponentCallbacks;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
+import android.os.Build;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.WindowManager;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.base.ThreadUtils;
+import org.chromium.ui.gfx.DeviceDisplayInfo;
+
+/**
+ * DisplayAndroidManager is a class that informs its observers Display changes.
+ */
+/* package */ class DisplayAndroidManager {
+ /**
+ * DisplayListenerBackend is an interface that abstract the mechanism used for the actual
+ * display update listening. The reason being that from Android API Level 17 DisplayListener
+ * will be used. Before that, an unreliable solution based on onConfigurationChanged has to be
+ * used.
+ */
+ private interface DisplayListenerBackend {
+
+ /**
+ * Starts to listen for display changes. This will be called
+ * when the first observer is added.
+ */
+ void startListening();
+
+ /**
+ * Toggle the accurate mode if it wasn't already doing so. The backend
+ * will keep track of the number of times this has been called.
+ */
+ void startAccurateListening();
+
+ /**
+ * Request to stop the accurate mode. It will effectively be stopped
+ * only if this method is called as many times as
+ * startAccurateListening().
+ */
+ void stopAccurateListening();
+ }
+
+ /**
+ * DisplayListenerAPI16 implements DisplayListenerBackend
+ * to use ComponentCallbacks in order to listen for display
+ * changes.
+ *
+ * This method is known to not correctly detect 180 degrees changes but it
+ * is the only method that will work before API Level 17 (excluding polling).
+ * When toggleAccurateMode() is called, it will start polling in order to
+ * find out if the display has changed.
+ */
+ private class DisplayListenerAPI16
+ implements DisplayListenerBackend, ComponentCallbacks {
+
+ private static final long POLLING_DELAY = 500;
+
+ private int mMainSdkDisplayId;
+ private int mAccurateCount;
+
+ public DisplayListenerAPI16(int sdkDisplayId) {
+ mMainSdkDisplayId = sdkDisplayId;
+ }
+
+ // DisplayListenerBackend implementation:
+
+ @Override
+ public void startListening() {
+ getContext().registerComponentCallbacks(this);
+ }
+
+ @Override
+ public void startAccurateListening() {
+ ++mAccurateCount;
+
+ if (mAccurateCount > 1) return;
+
+ // Start polling if we went from 0 to 1. The polling will
+ // automatically stop when mAccurateCount reaches 0.
+ final DisplayListenerAPI16 self = this;
+ ThreadUtils.postOnUiThreadDelayed(new Runnable() {
+ @Override
+ public void run() {
+ self.onConfigurationChanged(null);
+
+ if (self.mAccurateCount < 1) return;
+
+ ThreadUtils.postOnUiThreadDelayed(this,
+ DisplayListenerAPI16.POLLING_DELAY);
+ }
+ }, POLLING_DELAY);
+ }
+
+ @Override
+ public void stopAccurateListening() {
+ --mAccurateCount;
+ assert mAccurateCount >= 0;
+ }
+
+ // ComponentCallbacks implementation:
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ updateDeviceDisplayInfo();
+ mIdMap.get(mMainSdkDisplayId).updateFromDisplay(getDisplayFromContext(getContext()));
+ }
+
+ @Override
+ public void onLowMemory() {
+ }
+ }
+
+ /**
+ * DisplayListenerBackendImpl implements DisplayListenerBackend
+ * to use DisplayListener in order to listen for display changes.
+ *
+ * This method is reliable but DisplayListener is only available for API Level 17+.
+ */
+ @SuppressLint("NewApi")
+ private class DisplayListenerBackendImpl
+ implements DisplayListenerBackend, DisplayListener {
+
+ // DisplayListenerBackend implementation:
+
+ @Override
+ public void startListening() {
+ getDisplayManager().registerDisplayListener(this, null);
+ }
+
+ @Override
+ public void startAccurateListening() {
+ // Always accurate. Do nothing.
+ }
+
+ @Override
+ public void stopAccurateListening() {
+ // Always accurate. Do nothing.
+ }
+
+ // DisplayListener implementation:
+
+ @Override
+ public void onDisplayAdded(int sdkDisplayId) {
+ addDisplay(getDisplayManager().getDisplay(sdkDisplayId));
+ }
+
+ @Override
+ public void onDisplayRemoved(int sdkDisplayId) {
+ mIdMap.remove(sdkDisplayId);
+ }
+
+ @Override
+ public void onDisplayChanged(int sdkDisplayId) {
+ updateDeviceDisplayInfo();
+ mIdMap.get(sdkDisplayId)
+ .updateFromDisplay(getDisplayManager().getDisplay(sdkDisplayId));
+ }
+ }
+
+ private static DisplayAndroidManager sDisplayAndroidManager;
+
+ private SparseArray<DisplayAndroid> mIdMap;
+ private final DisplayListenerBackend mBackend;
+
+ /* package */ static DisplayAndroidManager getInstance() {
+ if (sDisplayAndroidManager == null) {
+ sDisplayAndroidManager = new DisplayAndroidManager();
+ }
+ return sDisplayAndroidManager;
+ }
+
+ /* package */ static Display getDisplayFromContext(Context context) {
+ WindowManager windowManager =
+ (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ return windowManager.getDefaultDisplay();
+ }
+
+ private static Context getContext() {
+ // Using the global application context is probably ok.
+ // The DisplayManager API observers all display updates, so in theory it should not matter
+ // which context is used to obtain it. If this turns out not to be true in practice, it's
+ // possible register from all context used though quite complex.
+ return ContextUtils.getApplicationContext();
+ }
+
+ private static DisplayManager getDisplayManager() {
+ return (DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
+ }
+
+ private static void updateDeviceDisplayInfo() {
+ DeviceDisplayInfo.create(getContext()).updateNativeSharedDisplayInfo();
+ }
+
+ private DisplayAndroidManager() {
+ mIdMap = new SparseArray<>();
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ mBackend = new DisplayListenerBackendImpl();
+ for (Display display : getDisplayManager().getDisplays()) {
+ addDisplay(display);
+ }
+ } else {
+ Display display = getDisplayFromContext(getContext());
+ mBackend = new DisplayListenerAPI16(display.getDisplayId());
+ addDisplay(display); // Note this display is never removed.
+ }
+ mBackend.startListening();
+ }
+
+ /* package */ DisplayAndroid getDisplayAndroid(int sdkDisplayId) {
+ return mIdMap.get(sdkDisplayId);
+ }
+
+ /* package */ void startAccurateListening() {
+ mBackend.startAccurateListening();
+ }
+
+ /* package */ void stopAccurateListening() {
+ mBackend.stopAccurateListening();
+ }
+
+ private void addDisplay(Display display) {
+ int sdkDisplayId = display.getDisplayId();
+ mIdMap.put(sdkDisplayId, new DisplayAndroid(display));
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698