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

Side by Side Diff: ui/android/java/src/org/chromium/ui/display/DisplayAndroid.java

Issue 2523273002: Implement Virtual Display class for Android. (Closed)
Patch Set: Created 4 years 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 unified diff | Download patch
OLDNEW
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698