| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.ui.display; | 5 package org.chromium.ui.display; |
| 6 | 6 |
| 7 import android.annotation.TargetApi; | |
| 8 import android.content.Context; | 7 import android.content.Context; |
| 9 import android.graphics.PixelFormat; | |
| 10 import android.graphics.Point; | |
| 11 import android.os.Build; | |
| 12 import android.util.DisplayMetrics; | |
| 13 import android.view.Display; | 8 import android.view.Display; |
| 14 import android.view.Surface; | 9 import android.view.Surface; |
| 15 | 10 |
| 16 import org.chromium.base.CommandLine; | |
| 17 import org.chromium.base.Log; | |
| 18 | |
| 19 import java.util.WeakHashMap; | 11 import java.util.WeakHashMap; |
| 20 | 12 |
| 21 /** | 13 /** |
| 22 * Chromium's object for android.view.Display. Instances of this object should b
e obtained | 14 * Chromium's object for android.view.Display. Instances of this object should b
e obtained |
| 23 * from WindowAndroid. | 15 * from WindowAndroid. |
| 24 * This class is designed to avoid leaks. It is ok to hold a strong ref of this
class from | 16 * This class is designed to avoid leaks. It is ok to hold a strong ref of this
class from |
| 25 * anywhere, as long as the corresponding WindowAndroids are destroyed. The obse
rvers are | 17 * anywhere, as long as the corresponding WindowAndroids are destroyed. The obse
rvers are |
| 26 * held weakly so to not lead to leaks. | 18 * held weakly so to not lead to leaks. |
| 27 */ | 19 */ |
| 28 public class DisplayAndroid { | 20 public abstract class DisplayAndroid { |
| 29 /** | 21 /** |
| 30 * DisplayAndroidObserver interface for changes to this Display. | 22 * DisplayAndroidObserver interface for changes to this Display. |
| 31 */ | 23 */ |
| 32 public interface DisplayAndroidObserver { | 24 public interface DisplayAndroidObserver { |
| 33 /** | 25 /** |
| 34 * Called whenever the screen orientation changes. | 26 * Called whenever the screen orientation changes. |
| 35 * | 27 * |
| 36 * @param orientation One of Surface.ROTATION_* values. | 28 * @param orientation One of Surface.ROTATION_* values. |
| 37 */ | 29 */ |
| 38 void onRotationChanged(int rotation); | 30 void onRotationChanged(int rotation); |
| 39 | 31 |
| 40 /** | 32 /** |
| 41 * Called whenever the screen density changes. | 33 * Called whenever the screen density changes. |
| 42 * | 34 * |
| 43 * @param screen density, aka Density Independent Pixel scale. | 35 * @param screen density, aka Density Independent Pixel scale. |
| 44 */ | 36 */ |
| 45 void onDIPScaleChanged(float dipScale); | 37 void onDIPScaleChanged(float dipScale); |
| 46 } | 38 } |
| 47 | 39 |
| 48 private static final String TAG = "DisplayAndroid"; | |
| 49 | |
| 50 private static final DisplayAndroidObserver[] EMPTY_OBSERVER_ARRAY = | 40 private static final DisplayAndroidObserver[] EMPTY_OBSERVER_ARRAY = |
| 51 new DisplayAndroidObserver[0]; | 41 new DisplayAndroidObserver[0]; |
| 52 | 42 |
| 53 private final int mSdkDisplayId; | |
| 54 private final WeakHashMap<DisplayAndroidObserver, Object /* null */> mObserv
ers; | 43 private final WeakHashMap<DisplayAndroidObserver, Object /* null */> mObserv
ers; |
| 55 // Do NOT add strong references to objects with potentially complex lifetime
, like Context. | 44 // Do NOT add strong references to objects with potentially complex lifetime
, like Context. |
| 56 | 45 |
| 57 // Updated by updateFromDisplay. | 46 protected static DisplayAndroidManager getManager() { |
| 58 private final Point mSize; | |
| 59 private final Point mPhysicalSize; | |
| 60 private final DisplayMetrics mDisplayMetrics; | |
| 61 private final PixelFormat mPixelFormatInfo; | |
| 62 private int mPixelFormatId; | |
| 63 private int mRotation; | |
| 64 | |
| 65 // When this object exists, a positive value means that the forced DIP scale
is set and | |
| 66 // the zero means it is not. The non existing object (i.e. null reference) m
eans that | |
| 67 // the existence and value of the forced DIP scale has not yet been determin
ed. | |
| 68 private static Float sForcedDIPScale; | |
| 69 | |
| 70 private static boolean hasForcedDIPScale() { | |
| 71 if (sForcedDIPScale == null) { | |
| 72 String forcedScaleAsString = CommandLine.getInstance().getSwitchValu
e( | |
| 73 DisplaySwitches.FORCE_DEVICE_SCALE_FACTOR); | |
| 74 if (forcedScaleAsString == null) { | |
| 75 sForcedDIPScale = Float.valueOf(0.0f); | |
| 76 } else { | |
| 77 boolean isInvalid = false; | |
| 78 try { | |
| 79 sForcedDIPScale = Float.valueOf(forcedScaleAsString); | |
| 80 // Negative values are discarded. | |
| 81 if (sForcedDIPScale.floatValue() <= 0.0f) isInvalid = true; | |
| 82 } catch (NumberFormatException e) { | |
| 83 // Strings that do not represent numbers are discarded. | |
| 84 isInvalid = true; | |
| 85 } | |
| 86 | |
| 87 if (isInvalid) { | |
| 88 Log.w(TAG, "Ignoring invalid forced DIP scale '" + forcedSca
leAsString + "'"); | |
| 89 sForcedDIPScale = Float.valueOf(0.0f); | |
| 90 } | |
| 91 } | |
| 92 } | |
| 93 return sForcedDIPScale.floatValue() > 0; | |
| 94 } | |
| 95 | |
| 96 private static DisplayAndroidManager getManager() { | |
| 97 return DisplayAndroidManager.getInstance(); | 47 return DisplayAndroidManager.getInstance(); |
| 98 } | 48 } |
| 99 | 49 |
| 100 /** | 50 /** |
| 101 * Get the non-multi-display DisplayAndroid for the given context. It's safe
to call this with | 51 * Get the non-multi-display DisplayAndroid for the given context. It's safe
to call this with |
| 102 * any type of context, including the Application. | 52 * any type of context, including the Application. |
| 103 * | 53 * |
| 104 * To support multi-display, obtain DisplayAndroid from WindowAndroid instea
d. | 54 * To support multi-display, obtain DisplayAndroid from WindowAndroid instea
d. |
| 105 * | 55 * |
| 106 * This function is intended to be analogous to GetPrimaryDisplay() for othe
r platforms. | 56 * This function is intended to be analogous to GetPrimaryDisplay() for othe
r platforms. |
| 107 * However, Android has historically had no real concept of a Primary Displa
y, and instead uses | 57 * However, Android has historically had no real concept of a Primary Displa
y, and instead uses |
| 108 * the notion of a default display for an Activity. Under normal circumstanc
es, this function, | 58 * the notion of a default display for an Activity. Under normal circumstanc
es, this function, |
| 109 * called with the correct context, will return the expected display for an
Activity. However, | 59 * called with the correct context, will return the expected display for an
Activity. However, |
| 110 * virtual, or "fake", displays that are not associated with any context may
be used in special | 60 * virtual, or "fake", displays that are not associated with any context may
be used in special |
| 111 * cases, like Virtual Reality, and will lead to this function returning the
incorrect display. | 61 * cases, like Virtual Reality, and will lead to this function returning the
incorrect display. |
| 112 * | 62 * |
| 113 * @return What the Android WindowManager considers to be the default displa
y for this context. | 63 * @return What the Android WindowManager considers to be the default displa
y for this context. |
| 114 */ | 64 */ |
| 115 public static DisplayAndroid getNonMultiDisplay(Context context) { | 65 public static DisplayAndroid getNonMultiDisplay(Context context) { |
| 116 Display display = DisplayAndroidManager.getDefaultDisplayForContext(cont
ext); | 66 Display display = DisplayAndroidManager.getDefaultDisplayForContext(cont
ext); |
| 117 return getManager().getDisplayAndroid(display); | 67 return getManager().getDisplayAndroid(display); |
| 118 } | 68 } |
| 119 | 69 |
| 120 /** | 70 /** |
| 121 * @return Display id as defined in Android's Display. | 71 * @return Display id as defined in Android's Display. |
| 122 */ | 72 */ |
| 123 public int getSdkDisplayId() { | 73 public abstract int getSdkDisplayId(); |
| 124 return mSdkDisplayId; | |
| 125 } | |
| 126 | 74 |
| 127 /** | 75 /** |
| 128 * @return Display height in physical pixels. | 76 * @return Display height in physical pixels. |
| 129 */ | 77 */ |
| 130 public int getDisplayHeight() { | 78 public abstract int getDisplayHeight(); |
| 131 return mSize.y; | |
| 132 } | |
| 133 | 79 |
| 134 /** | 80 /** |
| 135 * @return Display width in physical pixels. | 81 * @return Display width in physical pixels. |
| 136 */ | 82 */ |
| 137 public int getDisplayWidth() { | 83 public abstract int getDisplayWidth(); |
| 138 return mSize.x; | |
| 139 } | |
| 140 | 84 |
| 141 /** | 85 /** |
| 142 * @return Real physical display height in physical pixels. Or 0 if not supp
orted. | 86 * @return Real physical display height in physical pixels. Or 0 if not supp
orted. |
| 143 */ | 87 */ |
| 144 public int getPhysicalDisplayHeight() { | 88 public abstract int getPhysicalDisplayHeight(); |
| 145 return mPhysicalSize.y; | |
| 146 } | |
| 147 | 89 |
| 148 /** | 90 /** |
| 149 * @return Real physical display width in physical pixels. Or 0 if not suppo
rted. | 91 * @return Real physical display width in physical pixels. Or 0 if not suppo
rted. |
| 150 */ | 92 */ |
| 151 public int getPhysicalDisplayWidth() { | 93 public abstract int getPhysicalDisplayWidth(); |
| 152 return mPhysicalSize.x; | |
| 153 } | |
| 154 | 94 |
| 155 /** | 95 /** |
| 156 * @return current orientation. One of Surface.ORIENTATION_* values. | 96 * @return current orientation. One of Surface.ORIENTATION_* values. |
| 157 */ | 97 */ |
| 158 public int getRotation() { | 98 public abstract int getRotation(); |
| 159 return mRotation; | |
| 160 } | |
| 161 | 99 |
| 162 /** | 100 /** |
| 163 * @return current orientation in degrees. One of the values 0, 90, 180, 270
. | 101 * @return current orientation in degrees. One of the values 0, 90, 180, 270
. |
| 164 */ | 102 */ |
| 165 /* package */ int getRotationDegrees() { | 103 /* package */ int getRotationDegrees() { |
| 166 switch (mRotation) { | 104 switch (getRotation()) { |
| 167 case Surface.ROTATION_0: | 105 case Surface.ROTATION_0: |
| 168 return 0; | 106 return 0; |
| 169 case Surface.ROTATION_90: | 107 case Surface.ROTATION_90: |
| 170 return 90; | 108 return 90; |
| 171 case Surface.ROTATION_180: | 109 case Surface.ROTATION_180: |
| 172 return 180; | 110 return 180; |
| 173 case Surface.ROTATION_270: | 111 case Surface.ROTATION_270: |
| 174 return 270; | 112 return 270; |
| 175 } | 113 } |
| 176 | 114 |
| 177 // This should not happen. | 115 // This should not happen. |
| 178 assert false; | 116 assert false; |
| 179 return 0; | 117 return 0; |
| 180 } | 118 } |
| 181 | 119 |
| 182 /** | 120 /** |
| 183 * @return A scaling factor for the Density Independent Pixel unit. | 121 * @return A scaling factor for the Density Independent Pixel unit. |
| 184 */ | 122 */ |
| 185 public float getDipScale() { | 123 public abstract float getDipScale(); |
| 186 return mDisplayMetrics.density; | |
| 187 } | |
| 188 | 124 |
| 189 /** | 125 /** |
| 190 * @return Number of bits per pixel. | 126 * @return Number of bits per pixel. |
| 191 */ | 127 */ |
| 192 /* package */ int getBitsPerPixel() { | 128 /* package */ abstract int getBitsPerPixel(); |
| 193 return mPixelFormatInfo.bitsPerPixel; | |
| 194 } | |
| 195 | 129 |
| 196 /** | 130 /** |
| 197 * @return Number of bits per each color component. | 131 * @return Number of bits per each color component. |
| 198 */ | 132 */ |
| 199 @SuppressWarnings("deprecation") | 133 @SuppressWarnings("deprecation") |
| 200 /* package */ int getBitsPerComponent() { | 134 /* package */ abstract int getBitsPerComponent(); |
| 201 switch (mPixelFormatId) { | |
| 202 case PixelFormat.RGBA_4444: | |
| 203 return 4; | |
| 204 | |
| 205 case PixelFormat.RGBA_5551: | |
| 206 return 5; | |
| 207 | |
| 208 case PixelFormat.RGBA_8888: | |
| 209 case PixelFormat.RGBX_8888: | |
| 210 case PixelFormat.RGB_888: | |
| 211 return 8; | |
| 212 | |
| 213 case PixelFormat.RGB_332: | |
| 214 return 2; | |
| 215 | |
| 216 case PixelFormat.RGB_565: | |
| 217 return 5; | |
| 218 | |
| 219 // Non-RGB formats. | |
| 220 case PixelFormat.A_8: | |
| 221 case PixelFormat.LA_88: | |
| 222 case PixelFormat.L_8: | |
| 223 return 0; | |
| 224 | |
| 225 // Unknown format. Use 8 as a sensible default. | |
| 226 default: | |
| 227 return 8; | |
| 228 } | |
| 229 } | |
| 230 | 135 |
| 231 /** | 136 /** |
| 232 * Add observer. Note repeat observers will be called only one. | 137 * Add observer. Note repeat observers will be called only one. |
| 233 * Observers are held only weakly by Display. | 138 * Observers are held only weakly by Display. |
| 234 */ | 139 */ |
| 235 public void addObserver(DisplayAndroidObserver observer) { | 140 public void addObserver(DisplayAndroidObserver observer) { |
| 236 mObservers.put(observer, null); | 141 mObservers.put(observer, null); |
| 237 } | 142 } |
| 238 | 143 |
| 239 /** | 144 /** |
| (...skipping 12 matching lines...) Expand all Loading... |
| 252 } | 157 } |
| 253 | 158 |
| 254 /** | 159 /** |
| 255 * Request to stop the accurate mode. It will effectively be stopped only if | 160 * Request to stop the accurate mode. It will effectively be stopped only if |
| 256 * this method is called as many times as startAccurateListening(). | 161 * this method is called as many times as startAccurateListening(). |
| 257 */ | 162 */ |
| 258 public static void stopAccurateListening() { | 163 public static void stopAccurateListening() { |
| 259 getManager().startAccurateListening(); | 164 getManager().startAccurateListening(); |
| 260 } | 165 } |
| 261 | 166 |
| 262 /* package */ DisplayAndroid(Display display) { | 167 public DisplayAndroid() { |
| 263 mSdkDisplayId = display.getDisplayId(); | |
| 264 mObservers = new WeakHashMap<>(); | 168 mObservers = new WeakHashMap<>(); |
| 265 mSize = new Point(); | |
| 266 mPhysicalSize = new Point(); | |
| 267 mDisplayMetrics = new DisplayMetrics(); | |
| 268 mPixelFormatInfo = new PixelFormat(); | |
| 269 } | 169 } |
| 270 | 170 |
| 271 @SuppressWarnings("deprecation") | 171 protected DisplayAndroidObserver[] getObservers() { |
| 272 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) | |
| 273 /* package */ void updateFromDisplay(Display display) { | |
| 274 final Point oldSize = new Point(mSize); | |
| 275 final Point oldPhysicalSize = new Point(mPhysicalSize); | |
| 276 final float oldDensity = mDisplayMetrics.density; | |
| 277 final int oldPixelFormatId = mPixelFormatId; | |
| 278 final int oldRotation = mRotation; | |
| 279 | |
| 280 display.getSize(mSize); | |
| 281 display.getMetrics(mDisplayMetrics); | |
| 282 | |
| 283 if (hasForcedDIPScale()) mDisplayMetrics.density = sForcedDIPScale.float
Value(); | |
| 284 | |
| 285 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { | |
| 286 display.getRealSize(mPhysicalSize); | |
| 287 } | |
| 288 | |
| 289 // JellyBean MR1 and later always uses RGBA_8888. | |
| 290 mPixelFormatId = (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN
_MR1) | |
| 291 ? display.getPixelFormat() | |
| 292 : PixelFormat.RGBA_8888; | |
| 293 if (oldPixelFormatId != mPixelFormatId) { | |
| 294 PixelFormat.getPixelFormatInfo(mPixelFormatId, mPixelFormatInfo); | |
| 295 } | |
| 296 | |
| 297 mRotation = display.getRotation(); | |
| 298 | |
| 299 final boolean noChanges = oldSize.equals(mSize) && oldPhysicalSize.equal
s(mPhysicalSize) | |
| 300 && oldDensity == mDisplayMetrics.density && oldPixelFormatId ==
mPixelFormatId | |
| 301 && oldRotation == mRotation; | |
| 302 if (noChanges) return; | |
| 303 | |
| 304 getManager().updateDisplayOnNativeSide(this); | |
| 305 | |
| 306 if (oldRotation != mRotation) { | |
| 307 DisplayAndroidObserver[] observers = getObservers(); | |
| 308 for (DisplayAndroidObserver o : observers) { | |
| 309 o.onRotationChanged(mRotation); | |
| 310 } | |
| 311 } | |
| 312 | |
| 313 // Intentional comparison of floats: we assume that if scales differ, | |
| 314 // they differ significantly. | |
| 315 boolean dipScaleChanged = oldDensity != mDisplayMetrics.density; | |
| 316 if (dipScaleChanged) { | |
| 317 DisplayAndroidObserver[] observers = getObservers(); | |
| 318 for (DisplayAndroidObserver o : observers) { | |
| 319 o.onDIPScaleChanged(mDisplayMetrics.density); | |
| 320 } | |
| 321 } | |
| 322 } | |
| 323 | |
| 324 private DisplayAndroidObserver[] getObservers() { | |
| 325 // Makes a copy to allow concurrent edit. | 172 // Makes a copy to allow concurrent edit. |
| 326 return mObservers.keySet().toArray(EMPTY_OBSERVER_ARRAY); | 173 return mObservers.keySet().toArray(EMPTY_OBSERVER_ARRAY); |
| 327 } | 174 } |
| 328 } | 175 } |
| OLD | NEW |