blob: a99a0b5a7a9094c08946b02a12f6e24de78ab016 [file] [log] [blame]
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.content.res;
18
Mathew Inwood5c0d3542018-08-14 13:54:31 +010019import android.annotation.UnsupportedAppUsage;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070020import android.content.pm.ApplicationInfo;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070021import android.graphics.Canvas;
Christopher Tatea53146c2010-09-07 11:57:52 -070022import android.graphics.PointF;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070023import android.graphics.Rect;
24import android.graphics.Region;
Jason Monkbd60e5b2017-03-02 12:55:00 -050025import android.os.Build;
26import android.os.Build.VERSION_CODES;
Dianne Hackborne2515ee2011-04-27 18:52:56 -040027import android.os.Parcel;
28import android.os.Parcelable;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070029import android.util.DisplayMetrics;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070030import android.view.MotionEvent;
31import android.view.WindowManager;
32import android.view.WindowManager.LayoutParams;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070033
34/**
35 * CompatibilityInfo class keeps the information about compatibility mode that the application is
36 * running under.
37 *
38 * {@hide}
39 */
Dianne Hackborne2515ee2011-04-27 18:52:56 -040040public class CompatibilityInfo implements Parcelable {
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070041 /** default compatibility info object for compatible applications */
Mathew Inwood5c0d3542018-08-14 13:54:31 +010042 @UnsupportedAppUsage
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -070043 public static final CompatibilityInfo DEFAULT_COMPATIBILITY_INFO = new CompatibilityInfo() {
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -070044 };
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070045
46 /**
Dianne Hackborne2515ee2011-04-27 18:52:56 -040047 * This is the number of pixels we would like to have along the
48 * short axis of an app that needs to run on a normal size screen.
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070049 */
Dianne Hackborne2515ee2011-04-27 18:52:56 -040050 public static final int DEFAULT_NORMAL_SHORT_DIMENSION = 320;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070051
52 /**
Dianne Hackborne2515ee2011-04-27 18:52:56 -040053 * This is the maximum aspect ratio we will allow while keeping
54 * applications in a compatible screen size.
55 */
56 public static final float MAXIMUM_ASPECT_RATIO = (854f/480f);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070057
58 /**
Mitsuru Oshima64f59342009-06-21 00:03:11 -070059 * A compatibility flags
60 */
Dianne Hackborne2515ee2011-04-27 18:52:56 -040061 private final int mCompatibilityFlags;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070062
63 /**
64 * A flag mask to tell if the application needs scaling (when mApplicationScale != 1.0f)
65 * {@see compatibilityFlag}
66 */
67 private static final int SCALING_REQUIRED = 1;
68
69 /**
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -070070 * Application must always run in compatibility mode?
71 */
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -070072 private static final int ALWAYS_NEEDS_COMPAT = 2;
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -070073
74 /**
75 * Application never should run in compatibility mode?
76 */
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -070077 private static final int NEVER_NEEDS_COMPAT = 4;
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -070078
79 /**
Dianne Hackborne2515ee2011-04-27 18:52:56 -040080 * Set if the application needs to run in screen size compatibility mode.
Dianne Hackborn14cee9f2010-04-23 17:51:26 -070081 */
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -070082 private static final int NEEDS_SCREEN_COMPAT = 8;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070083
84 /**
Jason Monkbd60e5b2017-03-02 12:55:00 -050085 * Set if the application needs to run in with compat resources.
86 */
87 private static final int NEEDS_COMPAT_RES = 16;
88
89 /**
Dianne Hackborn2784ff02009-07-18 17:13:29 -070090 * The effective screen density we have selected for this application.
91 */
92 public final int applicationDensity;
93
94 /**
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070095 * Application's scale.
96 */
Mathew Inwood5c0d3542018-08-14 13:54:31 +010097 @UnsupportedAppUsage
Mitsuru Oshima64f59342009-06-21 00:03:11 -070098 public final float applicationScale;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070099
100 /**
101 * Application's inverted scale.
102 */
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700103 public final float applicationInvertedScale;
104
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100105 @UnsupportedAppUsage
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700106 public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw,
107 boolean forceCompat) {
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400108 int compatFlags = 0;
109
Jason Monkbd60e5b2017-03-02 12:55:00 -0500110 if (appInfo.targetSdkVersion < VERSION_CODES.O) {
111 compatFlags |= NEEDS_COMPAT_RES;
112 }
Dianne Hackborn2762ff32011-06-01 21:27:05 -0700113 if (appInfo.requiresSmallestWidthDp != 0 || appInfo.compatibleWidthLimitDp != 0
114 || appInfo.largestWidthLimitDp != 0) {
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700115 // New style screen requirements spec.
116 int required = appInfo.requiresSmallestWidthDp != 0
117 ? appInfo.requiresSmallestWidthDp
118 : appInfo.compatibleWidthLimitDp;
Dianne Hackborn2762ff32011-06-01 21:27:05 -0700119 if (required == 0) {
120 required = appInfo.largestWidthLimitDp;
121 }
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700122 int compat = appInfo.compatibleWidthLimitDp != 0
Dianne Hackborn2762ff32011-06-01 21:27:05 -0700123 ? appInfo.compatibleWidthLimitDp : required;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700124 if (compat < required) {
125 compat = required;
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400126 }
Dianne Hackborn2762ff32011-06-01 21:27:05 -0700127 int largest = appInfo.largestWidthLimitDp;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700128
Dianne Hackborn2762ff32011-06-01 21:27:05 -0700129 if (required > DEFAULT_NORMAL_SHORT_DIMENSION) {
130 // For now -- if they require a size larger than the only
131 // size we can do in compatibility mode, then don't ever
132 // allow the app to go in to compat mode. Trying to run
133 // it at a smaller size it can handle will make it far more
134 // broken than running at a larger size than it wants or
135 // thinks it can handle.
136 compatFlags |= NEVER_NEEDS_COMPAT;
137 } else if (largest != 0 && sw > largest) {
138 // If the screen size is larger than the largest size the
139 // app thinks it can work with, then always force it in to
140 // compatibility mode.
141 compatFlags |= NEEDS_SCREEN_COMPAT | ALWAYS_NEEDS_COMPAT;
142 } else if (compat >= sw) {
143 // The screen size is something the app says it was designed
144 // for, so never do compatibility mode.
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700145 compatFlags |= NEVER_NEEDS_COMPAT;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700146 } else if (forceCompat) {
Dianne Hackborn2762ff32011-06-01 21:27:05 -0700147 // The app may work better with or without compatibility mode.
148 // Let the user decide.
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700149 compatFlags |= NEEDS_SCREEN_COMPAT;
Dianne Hackborn36cd41f2011-05-25 21:00:46 -0700150 }
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700151
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700152 // Modern apps always support densities.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700153 applicationDensity = DisplayMetrics.DENSITY_DEVICE;
154 applicationScale = 1.0f;
155 applicationInvertedScale = 1.0f;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700156
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700157 } else {
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700158 /**
159 * Has the application said that its UI is expandable? Based on the
160 * <supports-screen> android:expandible in the manifest.
161 */
162 final int EXPANDABLE = 2;
163
164 /**
165 * Has the application said that its UI supports large screens? Based on the
166 * <supports-screen> android:largeScreens in the manifest.
167 */
168 final int LARGE_SCREENS = 8;
169
170 /**
171 * Has the application said that its UI supports xlarge screens? Based on the
172 * <supports-screen> android:xlargeScreens in the manifest.
173 */
174 final int XLARGE_SCREENS = 32;
175
176 int sizeInfo = 0;
177
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700178 // We can't rely on the application always setting
179 // FLAG_RESIZEABLE_FOR_SCREENS so will compute it based on various input.
180 boolean anyResizeable = false;
181
182 if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700183 sizeInfo |= LARGE_SCREENS;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700184 anyResizeable = true;
185 if (!forceCompat) {
186 // If we aren't forcing the app into compatibility mode, then
187 // assume if it supports large screens that we should allow it
188 // to use the full space of an xlarge screen as well.
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700189 sizeInfo |= XLARGE_SCREENS | EXPANDABLE;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700190 }
191 }
192 if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
193 anyResizeable = true;
194 if (!forceCompat) {
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700195 sizeInfo |= XLARGE_SCREENS | EXPANDABLE;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700196 }
197 }
198 if ((appInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
199 anyResizeable = true;
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700200 sizeInfo |= EXPANDABLE;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700201 }
202
203 if (forceCompat) {
204 // If we are forcing compatibility mode, then ignore an app that
205 // just says it is resizable for screens. We'll only have it fill
206 // the screen if it explicitly says it supports the screen size we
207 // are running in.
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700208 sizeInfo &= ~EXPANDABLE;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700209 }
210
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700211 compatFlags |= NEEDS_SCREEN_COMPAT;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700212 switch (screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK) {
213 case Configuration.SCREENLAYOUT_SIZE_XLARGE:
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700214 if ((sizeInfo&XLARGE_SCREENS) != 0) {
215 compatFlags &= ~NEEDS_SCREEN_COMPAT;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700216 }
217 if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700218 compatFlags |= NEVER_NEEDS_COMPAT;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700219 }
220 break;
221 case Configuration.SCREENLAYOUT_SIZE_LARGE:
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700222 if ((sizeInfo&LARGE_SCREENS) != 0) {
223 compatFlags &= ~NEEDS_SCREEN_COMPAT;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700224 }
225 if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700226 compatFlags |= NEVER_NEEDS_COMPAT;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700227 }
228 break;
229 }
230
231 if ((screenLayout&Configuration.SCREENLAYOUT_COMPAT_NEEDED) != 0) {
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700232 if ((sizeInfo&EXPANDABLE) != 0) {
233 compatFlags &= ~NEEDS_SCREEN_COMPAT;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700234 } else if (!anyResizeable) {
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700235 compatFlags |= ALWAYS_NEEDS_COMPAT;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700236 }
Dianne Hackborn39ec8fb92011-06-01 12:42:55 -0700237 } else {
238 compatFlags &= ~NEEDS_SCREEN_COMPAT;
239 compatFlags |= NEVER_NEEDS_COMPAT;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700240 }
241
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700242 if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
243 applicationDensity = DisplayMetrics.DENSITY_DEVICE;
244 applicationScale = 1.0f;
245 applicationInvertedScale = 1.0f;
246 } else {
247 applicationDensity = DisplayMetrics.DENSITY_DEFAULT;
248 applicationScale = DisplayMetrics.DENSITY_DEVICE
249 / (float) DisplayMetrics.DENSITY_DEFAULT;
250 applicationInvertedScale = 1.0f / applicationScale;
251 compatFlags |= SCALING_REQUIRED;
252 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700253 }
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400254
255 mCompatibilityFlags = compatFlags;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700256 }
257
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400258 private CompatibilityInfo(int compFlags,
Dianne Hackborn2784ff02009-07-18 17:13:29 -0700259 int dens, float scale, float invertedScale) {
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700260 mCompatibilityFlags = compFlags;
Dianne Hackborn2784ff02009-07-18 17:13:29 -0700261 applicationDensity = dens;
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700262 applicationScale = scale;
263 applicationInvertedScale = invertedScale;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700264 }
265
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100266 @UnsupportedAppUsage
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700267 private CompatibilityInfo() {
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700268 this(NEVER_NEEDS_COMPAT, DisplayMetrics.DENSITY_DEVICE,
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700269 1.0f,
270 1.0f);
271 }
272
273 /**
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700274 * @return true if the scaling is required
275 */
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100276 @UnsupportedAppUsage
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700277 public boolean isScalingRequired() {
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700278 return (mCompatibilityFlags&SCALING_REQUIRED) != 0;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700279 }
280
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100281 @UnsupportedAppUsage
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700282 public boolean supportsScreen() {
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400283 return (mCompatibilityFlags&NEEDS_SCREEN_COMPAT) == 0;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700284 }
285
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -0700286 public boolean neverSupportsScreen() {
Dianne Hackborn2f0b1752011-05-31 17:59:49 -0700287 return (mCompatibilityFlags&ALWAYS_NEEDS_COMPAT) != 0;
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -0700288 }
289
290 public boolean alwaysSupportsScreen() {
Dianne Hackborn2f0b1752011-05-31 17:59:49 -0700291 return (mCompatibilityFlags&NEVER_NEEDS_COMPAT) != 0;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700292 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700293
Jason Monkbd60e5b2017-03-02 12:55:00 -0500294 public boolean needsCompatResources() {
295 return (mCompatibilityFlags&NEEDS_COMPAT_RES) != 0;
296 }
297
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700298 /**
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700299 * Returns the translator which translates the coordinates in compatibility mode.
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700300 * @param params the window's parameter
301 */
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100302 @UnsupportedAppUsage
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700303 public Translator getTranslator() {
304 return isScalingRequired() ? new Translator() : null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700305 }
306
307 /**
308 * A helper object to translate the screen and window coordinates back and forth.
309 * @hide
310 */
311 public class Translator {
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100312 @UnsupportedAppUsage
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700313 final public float applicationScale;
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100314 @UnsupportedAppUsage
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700315 final public float applicationInvertedScale;
316
317 private Rect mContentInsetsBuffer = null;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700318 private Rect mVisibleInsetsBuffer = null;
Jeff Brownfbf09772011-01-16 14:06:57 -0800319 private Region mTouchableAreaBuffer = null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700320
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700321 Translator(float applicationScale, float applicationInvertedScale) {
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700322 this.applicationScale = applicationScale;
323 this.applicationInvertedScale = applicationInvertedScale;
324 }
325
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700326 Translator() {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700327 this(CompatibilityInfo.this.applicationScale,
328 CompatibilityInfo.this.applicationInvertedScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700329 }
330
331 /**
332 * Translate the screen rect to the application frame.
333 */
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100334 @UnsupportedAppUsage
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700335 public void translateRectInScreenToAppWinFrame(Rect rect) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700336 rect.scale(applicationInvertedScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700337 }
338
339 /**
340 * Translate the region in window to screen.
341 */
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100342 @UnsupportedAppUsage
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700343 public void translateRegionInWindowToScreen(Region transparentRegion) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700344 transparentRegion.scale(applicationScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700345 }
346
347 /**
348 * Apply translation to the canvas that is necessary to draw the content.
349 */
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100350 @UnsupportedAppUsage
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700351 public void translateCanvas(Canvas canvas) {
Mike Reedb5c17a62009-09-21 20:51:27 -0400352 if (applicationScale == 1.5f) {
353 /* When we scale for compatibility, we can put our stretched
354 bitmaps and ninepatches on exacty 1/2 pixel boundaries,
355 which can give us inconsistent drawing due to imperfect
356 float precision in the graphics engine's inverse matrix.
357
358 As a work-around, we translate by a tiny amount to avoid
359 landing on exact pixel centers and boundaries, giving us
360 the slop we need to draw consistently.
361
362 This constant is meant to resolve to 1/255 after it is
363 scaled by 1.5 (applicationScale). Note, this is just a guess
364 as to what is small enough not to create its own artifacts,
365 and big enough to avoid the precision problems. Feel free
366 to experiment with smaller values as you choose.
367 */
368 final float tinyOffset = 2.0f / (3 * 255);
369 canvas.translate(tinyOffset, tinyOffset);
370 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700371 canvas.scale(applicationScale, applicationScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700372 }
373
374 /**
375 * Translate the motion event captured on screen to the application's window.
376 */
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100377 @UnsupportedAppUsage
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700378 public void translateEventInScreenToAppWindow(MotionEvent event) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700379 event.scale(applicationInvertedScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700380 }
381
382 /**
383 * Translate the window's layout parameter, from application's view to
384 * Screen's view.
385 */
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100386 @UnsupportedAppUsage
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700387 public void translateWindowLayout(WindowManager.LayoutParams params) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700388 params.scale(applicationScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700389 }
390
391 /**
392 * Translate a Rect in application's window to screen.
393 */
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100394 @UnsupportedAppUsage
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700395 public void translateRectInAppWindowToScreen(Rect rect) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700396 rect.scale(applicationScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700397 }
398
399 /**
400 * Translate a Rect in screen coordinates into the app window's coordinates.
401 */
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100402 @UnsupportedAppUsage
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700403 public void translateRectInScreenToAppWindow(Rect rect) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700404 rect.scale(applicationInvertedScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700405 }
406
407 /**
Christopher Tatea53146c2010-09-07 11:57:52 -0700408 * Translate a Point in screen coordinates into the app window's coordinates.
409 */
410 public void translatePointInScreenToAppWindow(PointF point) {
411 final float scale = applicationInvertedScale;
412 if (scale != 1.0f) {
413 point.x *= scale;
414 point.y *= scale;
415 }
416 }
417
418 /**
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700419 * Translate the location of the sub window.
420 * @param params
421 */
422 public void translateLayoutParamsInAppWindowToScreen(LayoutParams params) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700423 params.scale(applicationScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700424 }
425
426 /**
427 * Translate the content insets in application window to Screen. This uses
428 * the internal buffer for content insets to avoid extra object allocation.
429 */
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100430 @UnsupportedAppUsage
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700431 public Rect getTranslatedContentInsets(Rect contentInsets) {
432 if (mContentInsetsBuffer == null) mContentInsetsBuffer = new Rect();
433 mContentInsetsBuffer.set(contentInsets);
434 translateRectInAppWindowToScreen(mContentInsetsBuffer);
435 return mContentInsetsBuffer;
436 }
437
438 /**
439 * Translate the visible insets in application window to Screen. This uses
Jeff Brownfbf09772011-01-16 14:06:57 -0800440 * the internal buffer for visible insets to avoid extra object allocation.
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700441 */
Jeff Brownfbf09772011-01-16 14:06:57 -0800442 public Rect getTranslatedVisibleInsets(Rect visibleInsets) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700443 if (mVisibleInsetsBuffer == null) mVisibleInsetsBuffer = new Rect();
444 mVisibleInsetsBuffer.set(visibleInsets);
445 translateRectInAppWindowToScreen(mVisibleInsetsBuffer);
446 return mVisibleInsetsBuffer;
447 }
Jeff Brownfbf09772011-01-16 14:06:57 -0800448
449 /**
450 * Translate the touchable area in application window to Screen. This uses
451 * the internal buffer for touchable area to avoid extra object allocation.
452 */
453 public Region getTranslatedTouchableArea(Region touchableArea) {
454 if (mTouchableAreaBuffer == null) mTouchableAreaBuffer = new Region();
455 mTouchableAreaBuffer.set(touchableArea);
456 mTouchableAreaBuffer.scale(applicationScale);
457 return mTouchableAreaBuffer;
458 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700459 }
460
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400461 public void applyToDisplayMetrics(DisplayMetrics inoutDm) {
462 if (!supportsScreen()) {
463 // This is a larger screen device and the app is not
464 // compatible with large screens, so diddle it.
Dianne Hackborn2f0b1752011-05-31 17:59:49 -0700465 CompatibilityInfo.computeCompatibleScaling(inoutDm, inoutDm);
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700466 } else {
Dianne Hackborn2b31d532011-06-23 11:58:50 -0700467 inoutDm.widthPixels = inoutDm.noncompatWidthPixels;
468 inoutDm.heightPixels = inoutDm.noncompatHeightPixels;
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400469 }
470
471 if (isScalingRequired()) {
472 float invertedRatio = applicationInvertedScale;
Dianne Hackborn2b31d532011-06-23 11:58:50 -0700473 inoutDm.density = inoutDm.noncompatDensity * invertedRatio;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700474 inoutDm.densityDpi = (int)((inoutDm.noncompatDensityDpi * invertedRatio) + .5f);
Dianne Hackborn2b31d532011-06-23 11:58:50 -0700475 inoutDm.scaledDensity = inoutDm.noncompatScaledDensity * invertedRatio;
476 inoutDm.xdpi = inoutDm.noncompatXdpi * invertedRatio;
477 inoutDm.ydpi = inoutDm.noncompatYdpi * invertedRatio;
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400478 inoutDm.widthPixels = (int) (inoutDm.widthPixels * invertedRatio + 0.5f);
479 inoutDm.heightPixels = (int) (inoutDm.heightPixels * invertedRatio + 0.5f);
480 }
481 }
482
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700483 public void applyToConfiguration(int displayDensity, Configuration inoutConfig) {
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400484 if (!supportsScreen()) {
485 // This is a larger screen device and the app is not
486 // compatible with large screens, so we are forcing it to
487 // run as if the screen is normal size.
488 inoutConfig.screenLayout =
489 (inoutConfig.screenLayout&~Configuration.SCREENLAYOUT_SIZE_MASK)
490 | Configuration.SCREENLAYOUT_SIZE_NORMAL;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700491 inoutConfig.screenWidthDp = inoutConfig.compatScreenWidthDp;
492 inoutConfig.screenHeightDp = inoutConfig.compatScreenHeightDp;
493 inoutConfig.smallestScreenWidthDp = inoutConfig.compatSmallestScreenWidthDp;
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400494 }
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700495 inoutConfig.densityDpi = displayDensity;
496 if (isScalingRequired()) {
497 float invertedRatio = applicationInvertedScale;
498 inoutConfig.densityDpi = (int)((inoutConfig.densityDpi * invertedRatio) + .5f);
499 }
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400500 }
501
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700502 /**
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400503 * Compute the frame Rect for applications runs under compatibility mode.
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700504 *
505 * @param dm the display metrics used to compute the frame size.
Craig Mautner48d0d182013-06-11 07:53:06 -0700506 * @param outDm If non-null the width and height will be set to their scaled values.
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400507 * @return Returns the scaling factor for the window.
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700508 */
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100509 @UnsupportedAppUsage
Dianne Hackborn2f0b1752011-05-31 17:59:49 -0700510 public static float computeCompatibleScaling(DisplayMetrics dm, DisplayMetrics outDm) {
Dianne Hackborn2b31d532011-06-23 11:58:50 -0700511 final int width = dm.noncompatWidthPixels;
512 final int height = dm.noncompatHeightPixels;
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400513 int shortSize, longSize;
514 if (width < height) {
515 shortSize = width;
516 longSize = height;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700517 } else {
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400518 shortSize = height;
519 longSize = width;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700520 }
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400521 int newShortSize = (int)(DEFAULT_NORMAL_SHORT_DIMENSION * dm.density + 0.5f);
522 float aspect = ((float)longSize) / shortSize;
523 if (aspect > MAXIMUM_ASPECT_RATIO) {
524 aspect = MAXIMUM_ASPECT_RATIO;
525 }
526 int newLongSize = (int)(newShortSize * aspect + 0.5f);
527 int newWidth, newHeight;
528 if (width < height) {
529 newWidth = newShortSize;
530 newHeight = newLongSize;
531 } else {
532 newWidth = newLongSize;
533 newHeight = newShortSize;
534 }
535
536 float sw = width/(float)newWidth;
537 float sh = height/(float)newHeight;
538 float scale = sw < sh ? sw : sh;
539 if (scale < 1) {
540 scale = 1;
541 }
542
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400543 if (outDm != null) {
544 outDm.widthPixels = newWidth;
545 outDm.heightPixels = newHeight;
546 }
547
548 return scale;
549 }
550
551 @Override
552 public boolean equals(Object o) {
Craig Mautner48d0d182013-06-11 07:53:06 -0700553 if (this == o) {
554 return true;
555 }
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400556 try {
557 CompatibilityInfo oc = (CompatibilityInfo)o;
558 if (mCompatibilityFlags != oc.mCompatibilityFlags) return false;
559 if (applicationDensity != oc.applicationDensity) return false;
560 if (applicationScale != oc.applicationScale) return false;
561 if (applicationInvertedScale != oc.applicationInvertedScale) return false;
562 return true;
563 } catch (ClassCastException e) {
564 return false;
565 }
566 }
567
568 @Override
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700569 public String toString() {
570 StringBuilder sb = new StringBuilder(128);
571 sb.append("{");
572 sb.append(applicationDensity);
573 sb.append("dpi");
574 if (isScalingRequired()) {
Dianne Hackborn2b31d532011-06-23 11:58:50 -0700575 sb.append(" ");
576 sb.append(applicationScale);
577 sb.append("x");
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700578 }
579 if (!supportsScreen()) {
580 sb.append(" resizing");
581 }
582 if (neverSupportsScreen()) {
583 sb.append(" never-compat");
584 }
585 if (alwaysSupportsScreen()) {
586 sb.append(" always-compat");
587 }
588 sb.append("}");
589 return sb.toString();
590 }
591
592 @Override
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400593 public int hashCode() {
594 int result = 17;
595 result = 31 * result + mCompatibilityFlags;
596 result = 31 * result + applicationDensity;
597 result = 31 * result + Float.floatToIntBits(applicationScale);
598 result = 31 * result + Float.floatToIntBits(applicationInvertedScale);
599 return result;
600 }
601
602 @Override
603 public int describeContents() {
604 return 0;
605 }
606
607 @Override
608 public void writeToParcel(Parcel dest, int flags) {
609 dest.writeInt(mCompatibilityFlags);
610 dest.writeInt(applicationDensity);
611 dest.writeFloat(applicationScale);
612 dest.writeFloat(applicationInvertedScale);
613 }
614
Mathew Inwood31755f92018-12-20 13:53:36 +0000615 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700616 public static final @android.annotation.NonNull Parcelable.Creator<CompatibilityInfo> CREATOR
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400617 = new Parcelable.Creator<CompatibilityInfo>() {
Craig Mautner48d0d182013-06-11 07:53:06 -0700618 @Override
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400619 public CompatibilityInfo createFromParcel(Parcel source) {
620 return new CompatibilityInfo(source);
621 }
622
Craig Mautner48d0d182013-06-11 07:53:06 -0700623 @Override
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400624 public CompatibilityInfo[] newArray(int size) {
625 return new CompatibilityInfo[size];
626 }
627 };
628
629 private CompatibilityInfo(Parcel source) {
630 mCompatibilityFlags = source.readInt();
631 applicationDensity = source.readInt();
632 applicationScale = source.readFloat();
633 applicationInvertedScale = source.readFloat();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700634 }
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700635}