Chromium Code Reviews| 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(); |
| + } |
| +} |