Index: ui/android/java/src/org/chromium/ui/base/DIPScaleListener.java |
diff --git a/ui/android/java/src/org/chromium/ui/base/DIPScaleListener.java b/ui/android/java/src/org/chromium/ui/base/DIPScaleListener.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8bad59294dbfeece451e3474d9f562a11e9141a2 |
--- /dev/null |
+++ b/ui/android/java/src/org/chromium/ui/base/DIPScaleListener.java |
@@ -0,0 +1,206 @@ |
+// 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.base; |
+ |
+import android.annotation.SuppressLint; |
+import android.content.Context; |
+import android.hardware.display.DisplayManager; |
+import android.os.Build; |
+ |
+import org.chromium.base.Log; |
+import org.chromium.base.ObserverList; |
+import org.chromium.base.ThreadUtils; |
+import org.chromium.ui.gfx.DeviceDisplayInfo; |
+ |
+/** |
+ * Listens to changes in screen orientation. |
+ */ |
+public interface DIPScaleListener { |
boliu
2016/09/14 04:35:33
Just call it DisplayObserver. We might hook up oth
Tima Vaisburd
2016/09/15 00:05:04
Done.
|
+ /** |
+ * Called whenever the DIP scale changes. |
+ * |
+ * @param dipScale Density Independent Pixel scale (display density). |
+ */ |
+ void onDIPScaleChanged(float dipScale); |
+} |
+ |
+/** |
+ * DIPScaleMonitor is a class that informs its listeners when the |
+ * density independent pixel (DIP) scale changes. |
+ * |
+ * This class is meant to monitor changes for one window, which belongs to one display. |
+ */ |
+class DIPScaleMonitor { |
+ /** |
+ * DisplayListener receives configuration change signal from the system. |
+ */ |
+ @SuppressLint("NewApi") |
+ private class DisplayListener implements DisplayManager.DisplayListener { |
boliu
2016/09/14 04:35:33
you could merge this with the Monitor class, and t
Tima Vaisburd
2016/09/15 00:05:04
kept here because of "NewApi". Because of this I d
|
+ @Override |
+ public void onDisplayAdded(int displayId) {} |
+ |
+ @Override |
+ public void onDisplayChanged(int displayId) { |
+ updateDIPScale(displayId); |
+ } |
+ |
+ @Override |
+ public void onDisplayRemoved(int displayId) {} |
+ } |
+ |
+ private static final String TAG = "cr_DIPScaleMonitor"; |
+ |
+ // A small value for floating point comparison between DIP scales. |
+ // On a modern device at the time of writing the values may be |
+ // 2.975, 3.5, 3.825, 4.1625, 4.5. |
+ private static final float EPS = 0.0001f; |
+ |
+ // List of observers. |
+ private ObserverList<DIPScaleListener> mObservers = new ObserverList<DIPScaleListener>(); |
+ |
+ // DisplayListener receives notifications from the system. |
+ private DisplayListener mDisplayListener = null; |
boliu
2016/09/14 04:35:33
remove = null;
Tima Vaisburd
2016/09/15 00:05:04
Done.
|
+ |
+ // Current display density. |
+ private float mDIPScale = 0; |
boliu
2016/09/14 04:35:33
remove = 0
Tima Vaisburd
2016/09/15 00:05:04
Done.
|
+ |
+ // WindowAndroid we are attached to. |
+ private WindowAndroid mWindowAndroid; |
+ |
+ // DisplayManager used to start listening. |
+ private DisplayManager mDisplayManager; |
+ |
+ public DIPScaleMonitor(WindowAndroid windowAndroid) { |
+ ThreadUtils.assertOnUiThread(); |
boliu
2016/09/14 04:35:33
if you want to add thread asserts, then add them t
Tima Vaisburd
2016/09/15 00:05:04
I think the only public method I missed was getDIP
|
+ |
+ mWindowAndroid = windowAndroid; |
+ } |
+ |
+ /** |
+ * Shutdown procedure. To be called when associated WindowAndroid is destroyed. |
+ */ |
+ public void onDestroy() { |
boliu
2016/09/14 04:35:33
this method is totally useless.. remove it
Tima Vaisburd
2016/09/15 00:05:04
Done.
|
+ // All observers should have been removed. |
+ assert mDisplayManager == null; |
+ mWindowAndroid = null; |
+ } |
+ |
+ /** |
+ * Returns current device scale factor for the window. |
+ */ |
+ public float getDIPScale() { |
+ // This method guarantees the up to date value only while we are monitoring, which happens |
+ // only when there is at least one observer. In practice we use this method to set initial |
+ // DIP scale which can be overwritten by observer any time, thus this is not a real |
+ // restriction. |
+ if (mDIPScale <= 0) { |
+ DeviceDisplayInfo displayInfo = |
+ DeviceDisplayInfo.create(getDisplayContext(mWindowAndroid)); |
boliu
2016/09/14 04:35:33
I guess this is ok for now.. but it would be bette
Tima Vaisburd
2016/09/15 00:05:04
Do you mean just renaming DeviceDisplayInfo -> Dis
boliu
2016/09/15 05:27:41
Haven't looked into detail yet. But that whole Dis
|
+ mDIPScale = (float) displayInfo.getDIPScale(); |
+ } |
+ return mDIPScale; |
+ } |
+ |
+ /** |
+ * Adds |observer| in the DIPScaleListener observer list. |
+ * |
+ * @param listener The observer that will get notified. |
+ * @param context The context associated with this observer. |
+ * @return The DIP scale. |
+ */ |
+ public void addObserver(DIPScaleListener listener) { |
+ ThreadUtils.assertOnUiThread(); |
+ |
+ final boolean noPriorObserver = mObservers.isEmpty(); |
+ |
+ // Prevent notifying an already attached observer. |
+ if (!mObservers.addObserver(listener)) return; |
boliu
2016/09/14 04:35:33
don't bother with this check, seems the client sho
Tima Vaisburd
2016/09/15 00:05:04
Why to remove this functionality? Right now you ca
boliu
2016/09/15 05:27:41
You can remove this check and everything will stil
Tima Vaisburd
2016/09/16 23:59:25
Thew IllegalArgumentException.
|
+ |
+ if (noPriorObserver) { |
+ // Added first observer. |
+ assert mObservers.size() == 1; |
boliu
2016/09/14 04:35:33
asserts are useless
Tima Vaisburd
2016/09/15 00:05:04
Removed in this file, I saw lots of them in WebVie
boliu
2016/09/15 05:27:41
asserts don't do anything after some android versi
|
+ |
+ // Update cached DIP scale. |
+ Context displayContext = getDisplayContext(mWindowAndroid); |
+ mDIPScale = (float) DeviceDisplayInfo.create(displayContext).getDIPScale(); |
boliu
2016/09/14 04:35:33
just call getDIPScale
Tima Vaisburd
2016/09/15 00:05:04
I wanted to refresh. getDIPScale() could have been
boliu
2016/09/15 05:27:41
Sounds like you need an updateDIPScale in addition
Tima Vaisburd
2016/09/16 23:59:25
Added private getDIPScale(Context) which removed t
|
+ |
+ startListening(displayContext); |
+ } |
+ |
+ listener.onDIPScaleChanged(mDIPScale); |
+ } |
+ |
+ /** |
+ * Removes the |observer| from the DIPScaleListener observer list. |
+ * |
+ * @param listener The observer that will no longer receive notification. |
+ */ |
+ public void removeObserver(DIPScaleListener listener) { |
+ ThreadUtils.assertOnUiThread(); |
+ |
+ final boolean wasRemoved = mObservers.removeObserver(listener); |
+ if (wasRemoved && mObservers.isEmpty()) { |
+ // Last observer is gone. |
+ stopListening(); |
+ } |
+ } |
+ |
+ /** |
+ * Helper methods |
+ */ |
+ |
+ @SuppressLint("NewApi") |
+ private void startListening(Context displayContext) { |
+ Log.v(TAG, "startListening"); |
boliu
2016/09/14 04:35:33
these seem like debug logs that should just be rem
Tima Vaisburd
2016/09/15 00:05:04
Is DEBUG acceptable? I put |if (DEBUG) Log.v();|
boliu
2016/09/15 05:27:41
how often is someone going to want to turn those o
Tima Vaisburd
2016/09/16 23:59:25
Just removed the logs.
|
+ |
+ // DisplayManager is available at API level 17. |
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) return; |
+ |
+ if (mDisplayListener == null) mDisplayListener = new DisplayListener(); |
+ |
+ assert mDisplayManager == null; |
+ |
+ mDisplayManager = (DisplayManager) displayContext.getSystemService(Context.DISPLAY_SERVICE); |
+ mDisplayManager.registerDisplayListener(mDisplayListener, null); |
+ } |
+ |
+ @SuppressLint("NewApi") |
+ private void stopListening() { |
+ Log.v(TAG, "stopListening"); |
+ |
+ // DisplayManager is available at API level 17. |
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) return; |
+ |
+ mDisplayManager.unregisterDisplayListener(mDisplayListener); |
+ mDisplayManager = null; |
+ } |
+ |
+ // Get current DIP scale and notify observers if necessary. |
+ private void updateDIPScale(int displayId) { |
boliu
2016/09/14 17:28:21
is it possible to save the display id of the curre
Tima Vaisburd
2016/09/14 17:38:19
The only way I found was
window -> context -> wi
Tima Vaisburd
2016/09/15 00:05:04
Did in startListening().
|
+ Log.v(TAG, "updateDIPScale displayId:" + displayId); |
+ |
+ ThreadUtils.assertOnUiThread(); |
+ |
+ if (mWindowAndroid == null) return; |
+ |
+ DeviceDisplayInfo displayInfo = DeviceDisplayInfo.create(getDisplayContext(mWindowAndroid)); |
+ float newDIPScale = (float) displayInfo.getDIPScale(); |
boliu
2016/09/14 04:35:32
call getDIPScale
Tima Vaisburd
2016/09/15 00:05:04
Same consideration that I need to get the new valu
|
+ |
+ if (Math.abs(newDIPScale - mDIPScale) > EPS) { |
boliu
2016/09/14 04:35:33
I think actually equality is fine. It's not like t
Tima Vaisburd
2016/09/15 00:05:04
Yes. Silly me. Added a comment why floating point
|
+ Log.v(TAG, "DIP scale changed, new DIP scale:" + newDIPScale); |
+ mDIPScale = newDIPScale; |
+ displayInfo.updateNativeSharedDisplayInfo(); |
+ |
+ for (DIPScaleListener listener : mObservers) listener.onDIPScaleChanged(newDIPScale); |
+ } |
+ } |
+ |
+ private Context getDisplayContext(WindowAndroid windowAndroid) { |
+ Context displayContext = windowAndroid.getContext().get(); |
+ // If displayContext does not exist the activity got destroyed and we do not care about |
boliu
2016/09/14 04:35:33
s/and/, /
Tima Vaisburd
2016/09/15 00:05:04
Done.
|
+ // DIP scale any more. Use an application context as the simplest way to prevent a crash. |
+ return displayContext != null ? displayContext : windowAndroid.getApplicationContext(); |
+ } |
+} |