blob: 28c751c373fe744e8bd720c5df41da681c676271 [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
19import android.content.pm.ApplicationInfo;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070020import android.graphics.Canvas;
Christopher Tatea53146c2010-09-07 11:57:52 -070021import android.graphics.PointF;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070022import android.graphics.Rect;
23import android.graphics.Region;
Dianne Hackborne2515ee2011-04-27 18:52:56 -040024import android.os.Parcel;
25import android.os.Parcelable;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070026import android.util.DisplayMetrics;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070027import android.view.MotionEvent;
28import android.view.WindowManager;
29import android.view.WindowManager.LayoutParams;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070030
31/**
32 * CompatibilityInfo class keeps the information about compatibility mode that the application is
33 * running under.
34 *
35 * {@hide}
36 */
Dianne Hackborne2515ee2011-04-27 18:52:56 -040037public class CompatibilityInfo implements Parcelable {
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070038 /** default compatibility info object for compatible applications */
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -070039 public static final CompatibilityInfo DEFAULT_COMPATIBILITY_INFO = new CompatibilityInfo() {
Mitsuru Oshima5a2b91d2009-07-16 16:30:02 -070040 };
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070041
42 /**
Dianne Hackborne2515ee2011-04-27 18:52:56 -040043 * This is the number of pixels we would like to have along the
44 * short axis of an app that needs to run on a normal size screen.
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070045 */
Dianne Hackborne2515ee2011-04-27 18:52:56 -040046 public static final int DEFAULT_NORMAL_SHORT_DIMENSION = 320;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070047
48 /**
Dianne Hackborne2515ee2011-04-27 18:52:56 -040049 * This is the maximum aspect ratio we will allow while keeping
50 * applications in a compatible screen size.
51 */
52 public static final float MAXIMUM_ASPECT_RATIO = (854f/480f);
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070053
54 /**
Mitsuru Oshima64f59342009-06-21 00:03:11 -070055 * A compatibility flags
56 */
Dianne Hackborne2515ee2011-04-27 18:52:56 -040057 private final int mCompatibilityFlags;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070058
59 /**
60 * A flag mask to tell if the application needs scaling (when mApplicationScale != 1.0f)
61 * {@see compatibilityFlag}
62 */
63 private static final int SCALING_REQUIRED = 1;
64
65 /**
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -070066 * Application must always run in compatibility mode?
67 */
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -070068 private static final int ALWAYS_NEEDS_COMPAT = 2;
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -070069
70 /**
71 * Application never should run in compatibility mode?
72 */
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -070073 private static final int NEVER_NEEDS_COMPAT = 4;
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -070074
75 /**
Dianne Hackborne2515ee2011-04-27 18:52:56 -040076 * Set if the application needs to run in screen size compatibility mode.
Dianne Hackborn14cee9f2010-04-23 17:51:26 -070077 */
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -070078 private static final int NEEDS_SCREEN_COMPAT = 8;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070079
80 /**
Dianne Hackborn2784ff02009-07-18 17:13:29 -070081 * The effective screen density we have selected for this application.
82 */
83 public final int applicationDensity;
84
85 /**
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070086 * Application's scale.
87 */
Mitsuru Oshima64f59342009-06-21 00:03:11 -070088 public final float applicationScale;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070089
90 /**
91 * Application's inverted scale.
92 */
Mitsuru Oshima64f59342009-06-21 00:03:11 -070093 public final float applicationInvertedScale;
94
Dianne Hackborndf6e9802011-05-26 14:20:23 -070095 public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw,
96 boolean forceCompat) {
Dianne Hackborne2515ee2011-04-27 18:52:56 -040097 int compatFlags = 0;
98
Dianne Hackborn2762ff32011-06-01 21:27:05 -070099 if (appInfo.requiresSmallestWidthDp != 0 || appInfo.compatibleWidthLimitDp != 0
100 || appInfo.largestWidthLimitDp != 0) {
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700101 // New style screen requirements spec.
102 int required = appInfo.requiresSmallestWidthDp != 0
103 ? appInfo.requiresSmallestWidthDp
104 : appInfo.compatibleWidthLimitDp;
Dianne Hackborn2762ff32011-06-01 21:27:05 -0700105 if (required == 0) {
106 required = appInfo.largestWidthLimitDp;
107 }
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700108 int compat = appInfo.compatibleWidthLimitDp != 0
Dianne Hackborn2762ff32011-06-01 21:27:05 -0700109 ? appInfo.compatibleWidthLimitDp : required;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700110 if (compat < required) {
111 compat = required;
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400112 }
Dianne Hackborn2762ff32011-06-01 21:27:05 -0700113 int largest = appInfo.largestWidthLimitDp;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700114
Dianne Hackborn2762ff32011-06-01 21:27:05 -0700115 if (required > DEFAULT_NORMAL_SHORT_DIMENSION) {
116 // For now -- if they require a size larger than the only
117 // size we can do in compatibility mode, then don't ever
118 // allow the app to go in to compat mode. Trying to run
119 // it at a smaller size it can handle will make it far more
120 // broken than running at a larger size than it wants or
121 // thinks it can handle.
122 compatFlags |= NEVER_NEEDS_COMPAT;
123 } else if (largest != 0 && sw > largest) {
124 // If the screen size is larger than the largest size the
125 // app thinks it can work with, then always force it in to
126 // compatibility mode.
127 compatFlags |= NEEDS_SCREEN_COMPAT | ALWAYS_NEEDS_COMPAT;
128 } else if (compat >= sw) {
129 // The screen size is something the app says it was designed
130 // for, so never do compatibility mode.
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700131 compatFlags |= NEVER_NEEDS_COMPAT;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700132 } else if (forceCompat) {
Dianne Hackborn2762ff32011-06-01 21:27:05 -0700133 // The app may work better with or without compatibility mode.
134 // Let the user decide.
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700135 compatFlags |= NEEDS_SCREEN_COMPAT;
Dianne Hackborn36cd41f2011-05-25 21:00:46 -0700136 }
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700137
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700138 // Modern apps always support densities.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700139 applicationDensity = DisplayMetrics.DENSITY_DEVICE;
140 applicationScale = 1.0f;
141 applicationInvertedScale = 1.0f;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700142
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700143 } else {
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700144 /**
145 * Has the application said that its UI is expandable? Based on the
146 * <supports-screen> android:expandible in the manifest.
147 */
148 final int EXPANDABLE = 2;
149
150 /**
151 * Has the application said that its UI supports large screens? Based on the
152 * <supports-screen> android:largeScreens in the manifest.
153 */
154 final int LARGE_SCREENS = 8;
155
156 /**
157 * Has the application said that its UI supports xlarge screens? Based on the
158 * <supports-screen> android:xlargeScreens in the manifest.
159 */
160 final int XLARGE_SCREENS = 32;
161
162 int sizeInfo = 0;
163
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700164 // We can't rely on the application always setting
165 // FLAG_RESIZEABLE_FOR_SCREENS so will compute it based on various input.
166 boolean anyResizeable = false;
167
168 if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700169 sizeInfo |= LARGE_SCREENS;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700170 anyResizeable = true;
171 if (!forceCompat) {
172 // If we aren't forcing the app into compatibility mode, then
173 // assume if it supports large screens that we should allow it
174 // to use the full space of an xlarge screen as well.
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700175 sizeInfo |= XLARGE_SCREENS | EXPANDABLE;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700176 }
177 }
178 if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
179 anyResizeable = true;
180 if (!forceCompat) {
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700181 sizeInfo |= XLARGE_SCREENS | EXPANDABLE;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700182 }
183 }
184 if ((appInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
185 anyResizeable = true;
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700186 sizeInfo |= EXPANDABLE;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700187 }
188
189 if (forceCompat) {
190 // If we are forcing compatibility mode, then ignore an app that
191 // just says it is resizable for screens. We'll only have it fill
192 // the screen if it explicitly says it supports the screen size we
193 // are running in.
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700194 sizeInfo &= ~EXPANDABLE;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700195 }
196
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700197 compatFlags |= NEEDS_SCREEN_COMPAT;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700198 switch (screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK) {
199 case Configuration.SCREENLAYOUT_SIZE_XLARGE:
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700200 if ((sizeInfo&XLARGE_SCREENS) != 0) {
201 compatFlags &= ~NEEDS_SCREEN_COMPAT;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700202 }
203 if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700204 compatFlags |= NEVER_NEEDS_COMPAT;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700205 }
206 break;
207 case Configuration.SCREENLAYOUT_SIZE_LARGE:
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700208 if ((sizeInfo&LARGE_SCREENS) != 0) {
209 compatFlags &= ~NEEDS_SCREEN_COMPAT;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700210 }
211 if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700212 compatFlags |= NEVER_NEEDS_COMPAT;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700213 }
214 break;
215 }
216
217 if ((screenLayout&Configuration.SCREENLAYOUT_COMPAT_NEEDED) != 0) {
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700218 if ((sizeInfo&EXPANDABLE) != 0) {
219 compatFlags &= ~NEEDS_SCREEN_COMPAT;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700220 } else if (!anyResizeable) {
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700221 compatFlags |= ALWAYS_NEEDS_COMPAT;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700222 }
Dianne Hackborn39ec8fb92011-06-01 12:42:55 -0700223 } else {
224 compatFlags &= ~NEEDS_SCREEN_COMPAT;
225 compatFlags |= NEVER_NEEDS_COMPAT;
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700226 }
227
Dianne Hackborndf6e9802011-05-26 14:20:23 -0700228 if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
229 applicationDensity = DisplayMetrics.DENSITY_DEVICE;
230 applicationScale = 1.0f;
231 applicationInvertedScale = 1.0f;
232 } else {
233 applicationDensity = DisplayMetrics.DENSITY_DEFAULT;
234 applicationScale = DisplayMetrics.DENSITY_DEVICE
235 / (float) DisplayMetrics.DENSITY_DEFAULT;
236 applicationInvertedScale = 1.0f / applicationScale;
237 compatFlags |= SCALING_REQUIRED;
238 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700239 }
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400240
241 mCompatibilityFlags = compatFlags;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700242 }
243
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400244 private CompatibilityInfo(int compFlags,
Dianne Hackborn2784ff02009-07-18 17:13:29 -0700245 int dens, float scale, float invertedScale) {
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700246 mCompatibilityFlags = compFlags;
Dianne Hackborn2784ff02009-07-18 17:13:29 -0700247 applicationDensity = dens;
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700248 applicationScale = scale;
249 applicationInvertedScale = invertedScale;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700250 }
251
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700252 private CompatibilityInfo() {
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700253 this(NEVER_NEEDS_COMPAT, DisplayMetrics.DENSITY_DEVICE,
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700254 1.0f,
255 1.0f);
256 }
257
258 /**
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700259 * @return true if the scaling is required
260 */
261 public boolean isScalingRequired() {
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700262 return (mCompatibilityFlags&SCALING_REQUIRED) != 0;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700263 }
264
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700265 public boolean supportsScreen() {
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400266 return (mCompatibilityFlags&NEEDS_SCREEN_COMPAT) == 0;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700267 }
268
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -0700269 public boolean neverSupportsScreen() {
Dianne Hackborn2f0b1752011-05-31 17:59:49 -0700270 return (mCompatibilityFlags&ALWAYS_NEEDS_COMPAT) != 0;
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -0700271 }
272
273 public boolean alwaysSupportsScreen() {
Dianne Hackborn2f0b1752011-05-31 17:59:49 -0700274 return (mCompatibilityFlags&NEVER_NEEDS_COMPAT) != 0;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700275 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700276
277 /**
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700278 * Returns the translator which translates the coordinates in compatibility mode.
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700279 * @param params the window's parameter
280 */
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700281 public Translator getTranslator() {
282 return isScalingRequired() ? new Translator() : null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700283 }
284
285 /**
286 * A helper object to translate the screen and window coordinates back and forth.
287 * @hide
288 */
289 public class Translator {
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700290 final public float applicationScale;
291 final public float applicationInvertedScale;
292
293 private Rect mContentInsetsBuffer = null;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700294 private Rect mVisibleInsetsBuffer = null;
Jeff Brownfbf09772011-01-16 14:06:57 -0800295 private Region mTouchableAreaBuffer = null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700296
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700297 Translator(float applicationScale, float applicationInvertedScale) {
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700298 this.applicationScale = applicationScale;
299 this.applicationInvertedScale = applicationInvertedScale;
300 }
301
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700302 Translator() {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700303 this(CompatibilityInfo.this.applicationScale,
304 CompatibilityInfo.this.applicationInvertedScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700305 }
306
307 /**
308 * Translate the screen rect to the application frame.
309 */
310 public void translateRectInScreenToAppWinFrame(Rect rect) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700311 rect.scale(applicationInvertedScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700312 }
313
314 /**
315 * Translate the region in window to screen.
316 */
317 public void translateRegionInWindowToScreen(Region transparentRegion) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700318 transparentRegion.scale(applicationScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700319 }
320
321 /**
322 * Apply translation to the canvas that is necessary to draw the content.
323 */
324 public void translateCanvas(Canvas canvas) {
Mike Reedb5c17a62009-09-21 20:51:27 -0400325 if (applicationScale == 1.5f) {
326 /* When we scale for compatibility, we can put our stretched
327 bitmaps and ninepatches on exacty 1/2 pixel boundaries,
328 which can give us inconsistent drawing due to imperfect
329 float precision in the graphics engine's inverse matrix.
330
331 As a work-around, we translate by a tiny amount to avoid
332 landing on exact pixel centers and boundaries, giving us
333 the slop we need to draw consistently.
334
335 This constant is meant to resolve to 1/255 after it is
336 scaled by 1.5 (applicationScale). Note, this is just a guess
337 as to what is small enough not to create its own artifacts,
338 and big enough to avoid the precision problems. Feel free
339 to experiment with smaller values as you choose.
340 */
341 final float tinyOffset = 2.0f / (3 * 255);
342 canvas.translate(tinyOffset, tinyOffset);
343 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700344 canvas.scale(applicationScale, applicationScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700345 }
346
347 /**
348 * Translate the motion event captured on screen to the application's window.
349 */
350 public void translateEventInScreenToAppWindow(MotionEvent event) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700351 event.scale(applicationInvertedScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700352 }
353
354 /**
355 * Translate the window's layout parameter, from application's view to
356 * Screen's view.
357 */
358 public void translateWindowLayout(WindowManager.LayoutParams params) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700359 params.scale(applicationScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700360 }
361
362 /**
363 * Translate a Rect in application's window to screen.
364 */
365 public void translateRectInAppWindowToScreen(Rect rect) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700366 rect.scale(applicationScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700367 }
368
369 /**
370 * Translate a Rect in screen coordinates into the app window's coordinates.
371 */
372 public void translateRectInScreenToAppWindow(Rect rect) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700373 rect.scale(applicationInvertedScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700374 }
375
376 /**
Christopher Tatea53146c2010-09-07 11:57:52 -0700377 * Translate a Point in screen coordinates into the app window's coordinates.
378 */
379 public void translatePointInScreenToAppWindow(PointF point) {
380 final float scale = applicationInvertedScale;
381 if (scale != 1.0f) {
382 point.x *= scale;
383 point.y *= scale;
384 }
385 }
386
387 /**
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700388 * Translate the location of the sub window.
389 * @param params
390 */
391 public void translateLayoutParamsInAppWindowToScreen(LayoutParams params) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700392 params.scale(applicationScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700393 }
394
395 /**
396 * Translate the content insets in application window to Screen. This uses
397 * the internal buffer for content insets to avoid extra object allocation.
398 */
399 public Rect getTranslatedContentInsets(Rect contentInsets) {
400 if (mContentInsetsBuffer == null) mContentInsetsBuffer = new Rect();
401 mContentInsetsBuffer.set(contentInsets);
402 translateRectInAppWindowToScreen(mContentInsetsBuffer);
403 return mContentInsetsBuffer;
404 }
405
406 /**
407 * Translate the visible insets in application window to Screen. This uses
Jeff Brownfbf09772011-01-16 14:06:57 -0800408 * the internal buffer for visible insets to avoid extra object allocation.
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700409 */
Jeff Brownfbf09772011-01-16 14:06:57 -0800410 public Rect getTranslatedVisibleInsets(Rect visibleInsets) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700411 if (mVisibleInsetsBuffer == null) mVisibleInsetsBuffer = new Rect();
412 mVisibleInsetsBuffer.set(visibleInsets);
413 translateRectInAppWindowToScreen(mVisibleInsetsBuffer);
414 return mVisibleInsetsBuffer;
415 }
Jeff Brownfbf09772011-01-16 14:06:57 -0800416
417 /**
418 * Translate the touchable area in application window to Screen. This uses
419 * the internal buffer for touchable area to avoid extra object allocation.
420 */
421 public Region getTranslatedTouchableArea(Region touchableArea) {
422 if (mTouchableAreaBuffer == null) mTouchableAreaBuffer = new Region();
423 mTouchableAreaBuffer.set(touchableArea);
424 mTouchableAreaBuffer.scale(applicationScale);
425 return mTouchableAreaBuffer;
426 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700427 }
428
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400429 public void applyToDisplayMetrics(DisplayMetrics inoutDm) {
430 if (!supportsScreen()) {
431 // This is a larger screen device and the app is not
432 // compatible with large screens, so diddle it.
Dianne Hackborn2f0b1752011-05-31 17:59:49 -0700433 CompatibilityInfo.computeCompatibleScaling(inoutDm, inoutDm);
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700434 } else {
Dianne Hackborn2b31d532011-06-23 11:58:50 -0700435 inoutDm.widthPixels = inoutDm.noncompatWidthPixels;
436 inoutDm.heightPixels = inoutDm.noncompatHeightPixels;
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400437 }
438
439 if (isScalingRequired()) {
440 float invertedRatio = applicationInvertedScale;
Dianne Hackborn2b31d532011-06-23 11:58:50 -0700441 inoutDm.density = inoutDm.noncompatDensity * invertedRatio;
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700442 inoutDm.densityDpi = (int)((inoutDm.noncompatDensityDpi * invertedRatio) + .5f);
Dianne Hackborn2b31d532011-06-23 11:58:50 -0700443 inoutDm.scaledDensity = inoutDm.noncompatScaledDensity * invertedRatio;
444 inoutDm.xdpi = inoutDm.noncompatXdpi * invertedRatio;
445 inoutDm.ydpi = inoutDm.noncompatYdpi * invertedRatio;
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400446 inoutDm.widthPixels = (int) (inoutDm.widthPixels * invertedRatio + 0.5f);
447 inoutDm.heightPixels = (int) (inoutDm.heightPixels * invertedRatio + 0.5f);
448 }
449 }
450
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700451 public void applyToConfiguration(int displayDensity, Configuration inoutConfig) {
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400452 if (!supportsScreen()) {
453 // This is a larger screen device and the app is not
454 // compatible with large screens, so we are forcing it to
455 // run as if the screen is normal size.
456 inoutConfig.screenLayout =
457 (inoutConfig.screenLayout&~Configuration.SCREENLAYOUT_SIZE_MASK)
458 | Configuration.SCREENLAYOUT_SIZE_NORMAL;
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700459 inoutConfig.screenWidthDp = inoutConfig.compatScreenWidthDp;
460 inoutConfig.screenHeightDp = inoutConfig.compatScreenHeightDp;
461 inoutConfig.smallestScreenWidthDp = inoutConfig.compatSmallestScreenWidthDp;
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400462 }
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700463 inoutConfig.densityDpi = displayDensity;
464 if (isScalingRequired()) {
465 float invertedRatio = applicationInvertedScale;
466 inoutConfig.densityDpi = (int)((inoutConfig.densityDpi * invertedRatio) + .5f);
467 }
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400468 }
469
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700470 /**
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400471 * Compute the frame Rect for applications runs under compatibility mode.
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700472 *
473 * @param dm the display metrics used to compute the frame size.
474 * @param orientation the orientation of the screen.
475 * @param outRect the output parameter which will contain the result.
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400476 * @return Returns the scaling factor for the window.
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700477 */
Dianne Hackborn2f0b1752011-05-31 17:59:49 -0700478 public static float computeCompatibleScaling(DisplayMetrics dm, DisplayMetrics outDm) {
Dianne Hackborn2b31d532011-06-23 11:58:50 -0700479 final int width = dm.noncompatWidthPixels;
480 final int height = dm.noncompatHeightPixels;
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400481 int shortSize, longSize;
482 if (width < height) {
483 shortSize = width;
484 longSize = height;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700485 } else {
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400486 shortSize = height;
487 longSize = width;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700488 }
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400489 int newShortSize = (int)(DEFAULT_NORMAL_SHORT_DIMENSION * dm.density + 0.5f);
490 float aspect = ((float)longSize) / shortSize;
491 if (aspect > MAXIMUM_ASPECT_RATIO) {
492 aspect = MAXIMUM_ASPECT_RATIO;
493 }
494 int newLongSize = (int)(newShortSize * aspect + 0.5f);
495 int newWidth, newHeight;
496 if (width < height) {
497 newWidth = newShortSize;
498 newHeight = newLongSize;
499 } else {
500 newWidth = newLongSize;
501 newHeight = newShortSize;
502 }
503
504 float sw = width/(float)newWidth;
505 float sh = height/(float)newHeight;
506 float scale = sw < sh ? sw : sh;
507 if (scale < 1) {
508 scale = 1;
509 }
510
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400511 if (outDm != null) {
512 outDm.widthPixels = newWidth;
513 outDm.heightPixels = newHeight;
514 }
515
516 return scale;
517 }
518
519 @Override
520 public boolean equals(Object o) {
521 try {
522 CompatibilityInfo oc = (CompatibilityInfo)o;
523 if (mCompatibilityFlags != oc.mCompatibilityFlags) return false;
524 if (applicationDensity != oc.applicationDensity) return false;
525 if (applicationScale != oc.applicationScale) return false;
526 if (applicationInvertedScale != oc.applicationInvertedScale) return false;
527 return true;
528 } catch (ClassCastException e) {
529 return false;
530 }
531 }
532
533 @Override
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700534 public String toString() {
535 StringBuilder sb = new StringBuilder(128);
536 sb.append("{");
537 sb.append(applicationDensity);
538 sb.append("dpi");
539 if (isScalingRequired()) {
Dianne Hackborn2b31d532011-06-23 11:58:50 -0700540 sb.append(" ");
541 sb.append(applicationScale);
542 sb.append("x");
Dianne Hackborn8ea5e1d2011-05-27 16:45:31 -0700543 }
544 if (!supportsScreen()) {
545 sb.append(" resizing");
546 }
547 if (neverSupportsScreen()) {
548 sb.append(" never-compat");
549 }
550 if (alwaysSupportsScreen()) {
551 sb.append(" always-compat");
552 }
553 sb.append("}");
554 return sb.toString();
555 }
556
557 @Override
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400558 public int hashCode() {
559 int result = 17;
560 result = 31 * result + mCompatibilityFlags;
561 result = 31 * result + applicationDensity;
562 result = 31 * result + Float.floatToIntBits(applicationScale);
563 result = 31 * result + Float.floatToIntBits(applicationInvertedScale);
564 return result;
565 }
566
567 @Override
568 public int describeContents() {
569 return 0;
570 }
571
572 @Override
573 public void writeToParcel(Parcel dest, int flags) {
574 dest.writeInt(mCompatibilityFlags);
575 dest.writeInt(applicationDensity);
576 dest.writeFloat(applicationScale);
577 dest.writeFloat(applicationInvertedScale);
578 }
579
580 public static final Parcelable.Creator<CompatibilityInfo> CREATOR
581 = new Parcelable.Creator<CompatibilityInfo>() {
582 public CompatibilityInfo createFromParcel(Parcel source) {
583 return new CompatibilityInfo(source);
584 }
585
586 public CompatibilityInfo[] newArray(int size) {
587 return new CompatibilityInfo[size];
588 }
589 };
590
591 private CompatibilityInfo(Parcel source) {
592 mCompatibilityFlags = source.readInt();
593 applicationDensity = source.readInt();
594 applicationScale = source.readFloat();
595 applicationInvertedScale = source.readFloat();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700596 }
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700597}