1// Copyright 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package org.chromium.ui.gfx;
6
7import android.content.Context;
8import android.graphics.PixelFormat;
9import android.graphics.Point;
10import android.os.Build;
11import android.util.DisplayMetrics;
12import android.view.Display;
13import android.view.Surface;
14import android.view.WindowManager;
15
16import org.chromium.base.CalledByNative;
17import org.chromium.base.JNINamespace;
18
19/**
20 * This class facilitates access to android information typically only
21 * available using the Java SDK, including {@link Display} properties.
22 *
23 * Currently the information consists of very raw display information (height, width, DPI scale)
24 * regarding the main display.
25 */
26@JNINamespace("gfx")
27public class DeviceDisplayInfo {
28
29    private final Context mAppContext;
30    private final WindowManager mWinManager;
31    private Point mTempPoint = new Point();
32    private DisplayMetrics mTempMetrics = new DisplayMetrics();
33
34    private DeviceDisplayInfo(Context context) {
35        mAppContext = context.getApplicationContext();
36        mWinManager = (WindowManager) mAppContext.getSystemService(Context.WINDOW_SERVICE);
37    }
38
39    /**
40     * @return Display height in physical pixels.
41     */
42    @CalledByNative
43    public int getDisplayHeight() {
44        getDisplay().getSize(mTempPoint);
45        return mTempPoint.y;
46    }
47
48    /**
49     * @return Display width in physical pixels.
50     */
51    @CalledByNative
52    public int getDisplayWidth() {
53        getDisplay().getSize(mTempPoint);
54        return mTempPoint.x;
55    }
56
57    /**
58     * @return Real physical display height in physical pixels.
59     */
60    @CalledByNative
61    public int getPhysicalDisplayHeight() {
62        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
63            return 0;
64        }
65        getDisplay().getRealSize(mTempPoint);
66        return mTempPoint.y;
67    }
68
69    /**
70     * @return Real physical display width in physical pixels.
71     */
72    @CalledByNative
73    public int getPhysicalDisplayWidth() {
74        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
75            return 0;
76        }
77        getDisplay().getRealSize(mTempPoint);
78        return mTempPoint.x;
79    }
80
81    @SuppressWarnings("deprecation")
82    private int getPixelFormat() {
83        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
84            return getDisplay().getPixelFormat();
85        }
86        // JellyBean MR1 and later always uses RGBA_8888.
87        return PixelFormat.RGBA_8888;
88    }
89
90    /**
91     * @return Bits per pixel.
92     */
93    @CalledByNative
94    public int getBitsPerPixel() {
95        int format = getPixelFormat();
96        PixelFormat info = new PixelFormat();
97        PixelFormat.getPixelFormatInfo(format, info);
98        return info.bitsPerPixel;
99    }
100
101    /**
102     * @return Bits per component.
103     */
104    @SuppressWarnings("deprecation")
105    @CalledByNative
106    public int getBitsPerComponent() {
107        int format = getPixelFormat();
108        switch (format) {
109            case PixelFormat.RGBA_4444:
110                return 4;
111
112            case PixelFormat.RGBA_5551:
113                return 5;
114
115            case PixelFormat.RGBA_8888:
116            case PixelFormat.RGBX_8888:
117            case PixelFormat.RGB_888:
118                return 8;
119
120            case PixelFormat.RGB_332:
121                return 2;
122
123            case PixelFormat.RGB_565:
124                return 5;
125
126            // Non-RGB formats.
127            case PixelFormat.A_8:
128            case PixelFormat.LA_88:
129            case PixelFormat.L_8:
130                return 0;
131
132            // Unknown format. Use 8 as a sensible default.
133            default:
134                return 8;
135        }
136    }
137
138    /**
139     * @return A scaling factor for the Density Independent Pixel unit. 1.0 is
140     *         160dpi, 0.75 is 120dpi, 2.0 is 320dpi.
141     */
142    @CalledByNative
143    public double getDIPScale() {
144        getDisplay().getMetrics(mTempMetrics);
145        return mTempMetrics.density;
146    }
147
148    /**
149     * @return Smallest screen size in density-independent pixels that the
150     *         application will see, regardless of orientation.
151     */
152    @CalledByNative
153    private int getSmallestDIPWidth() {
154        return mAppContext.getResources().getConfiguration().smallestScreenWidthDp;
155    }
156
157    /**
158     * @return the screen's rotation angle from its 'natural' orientation.
159     * Expected values are one of { 0, 90, 180, 270 }.
160     * See http://developer.android.com/reference/android/view/Display.html#getRotation()
161     * for more information about Display.getRotation() behavior.
162     */
163    @CalledByNative
164    public int getRotationDegrees() {
165        switch (getDisplay().getRotation()) {
166            case Surface.ROTATION_0:
167                return 0;
168            case Surface.ROTATION_90:
169                return 90;
170            case Surface.ROTATION_180:
171                return 180;
172            case Surface.ROTATION_270:
173                return 270;
174        }
175
176        // This should not happen.
177        assert false;
178        return 0;
179    }
180
181    /**
182     * Inform the native implementation to update its cached representation of
183     * the DeviceDisplayInfo values.
184     */
185    public void updateNativeSharedDisplayInfo() {
186        nativeUpdateSharedDeviceDisplayInfo(
187                getDisplayHeight(), getDisplayWidth(),
188                getPhysicalDisplayHeight(), getPhysicalDisplayWidth(),
189                getBitsPerPixel(), getBitsPerComponent(),
190                getDIPScale(), getSmallestDIPWidth(), getRotationDegrees());
191    }
192
193    private Display getDisplay() {
194        return mWinManager.getDefaultDisplay();
195    }
196
197    /**
198     * Creates DeviceDisplayInfo for a given Context.
199     *
200     * @param context A context to use.
201     * @return DeviceDisplayInfo associated with a given Context.
202     */
203    @CalledByNative
204    public static DeviceDisplayInfo create(Context context) {
205        return new DeviceDisplayInfo(context);
206    }
207
208    private native void nativeUpdateSharedDeviceDisplayInfo(
209            int displayHeight, int displayWidth,
210            int physicalDisplayHeight, int physicalDisplayWidth,
211            int bitsPerPixel, int bitsPerComponent, double dipScale,
212            int smallestDIPWidth, int rotationDegrees);
213
214}
215