blob: 8d725cd8f28b55b0ca41da098b7808a10704a9b5 [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 Hackborne2515ee2011-04-27 18:52:56 -040066 * Has the application said that its UI is expandable? Based on the
67 * <supports-screen> android:expandible in the manifest.
Mitsuru Oshima64f59342009-06-21 00:03:11 -070068 */
69 private static final int EXPANDABLE = 2;
70
71 /**
Dianne Hackborne2515ee2011-04-27 18:52:56 -040072 * Has the application said that its UI supports large screens? Based on the
73 * <supports-screen> android:largeScreens in the manifest.
Dianne Hackbornc4db95c2009-07-21 17:46:02 -070074 */
75 private static final int LARGE_SCREENS = 8;
76
77 /**
Dianne Hackborne2515ee2011-04-27 18:52:56 -040078 * Has the application said that its UI supports xlarge screens? Based on the
79 * <supports-screen> android:xlargeScreens in the manifest.
Dianne Hackborn14cee9f2010-04-23 17:51:26 -070080 */
81 private static final int XLARGE_SCREENS = 32;
82
83 /**
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -070084 * Application must always run in compatibility mode?
85 */
86 private static final int ALWAYS_COMPAT = 64;
87
88 /**
89 * Application never should run in compatibility mode?
90 */
91 private static final int NEVER_COMPAT = 128;
92
93 /**
Dianne Hackborne2515ee2011-04-27 18:52:56 -040094 * Set if the application needs to run in screen size compatibility mode.
Dianne Hackborn14cee9f2010-04-23 17:51:26 -070095 */
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -070096 private static final int NEEDS_SCREEN_COMPAT = 256;
Mitsuru Oshima64f59342009-06-21 00:03:11 -070097
98 /**
Dianne Hackborn2784ff02009-07-18 17:13:29 -070099 * The effective screen density we have selected for this application.
100 */
101 public final int applicationDensity;
102
103 /**
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700104 * Application's scale.
105 */
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700106 public final float applicationScale;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700107
108 /**
109 * Application's inverted scale.
110 */
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700111 public final float applicationInvertedScale;
112
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400113 public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, boolean forceCompat) {
114 int compatFlags = 0;
115
Dianne Hackborn36cd41f2011-05-25 21:00:46 -0700116 // We can't rely on the application always setting
117 // FLAG_RESIZEABLE_FOR_SCREENS so will compute it based on various input.
118 boolean anyResizeable = false;
119
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700120 if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400121 compatFlags |= LARGE_SCREENS;
Dianne Hackborn36cd41f2011-05-25 21:00:46 -0700122 anyResizeable = true;
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400123 if (!forceCompat) {
124 // If we aren't forcing the app into compatibility mode, then
125 // assume if it supports large screens that we should allow it
126 // to use the full space of an xlarge screen as well.
127 compatFlags |= XLARGE_SCREENS | EXPANDABLE;
128 }
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700129 }
Dianne Hackborn14cee9f2010-04-23 17:51:26 -0700130 if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
Dianne Hackborn36cd41f2011-05-25 21:00:46 -0700131 anyResizeable = true;
132 if (!forceCompat) {
133 compatFlags |= XLARGE_SCREENS | EXPANDABLE;
134 }
Dianne Hackborn14cee9f2010-04-23 17:51:26 -0700135 }
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700136 if ((appInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
Dianne Hackborn36cd41f2011-05-25 21:00:46 -0700137 anyResizeable = true;
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700138 compatFlags |= EXPANDABLE;
139 }
140
141 if (forceCompat) {
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400142 // If we are forcing compatibility mode, then ignore an app that
143 // just says it is resizable for screens. We'll only have it fill
144 // the screen if it explicitly says it supports the screen size we
145 // are running in.
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700146 compatFlags &= ~EXPANDABLE;
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400147 }
148
149 boolean supportsScreen = false;
150 switch (screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK) {
151 case Configuration.SCREENLAYOUT_SIZE_XLARGE:
152 if ((compatFlags&XLARGE_SCREENS) != 0) {
153 supportsScreen = true;
154 }
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -0700155 if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
156 compatFlags |= NEVER_COMPAT;
157 }
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400158 break;
159 case Configuration.SCREENLAYOUT_SIZE_LARGE:
160 if ((compatFlags&LARGE_SCREENS) != 0) {
161 supportsScreen = true;
162 }
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -0700163 if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
164 compatFlags |= NEVER_COMPAT;
165 }
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400166 break;
167 }
168
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700169 if ((screenLayout&Configuration.SCREENLAYOUT_COMPAT_NEEDED) != 0) {
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400170 if ((compatFlags&EXPANDABLE) != 0) {
171 supportsScreen = true;
Dianne Hackborn36cd41f2011-05-25 21:00:46 -0700172 } else if (!anyResizeable) {
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -0700173 compatFlags |= ALWAYS_COMPAT;
174 }
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400175 }
176
177 if (supportsScreen) {
178 compatFlags &= ~NEEDS_SCREEN_COMPAT;
179 } else {
180 compatFlags |= NEEDS_SCREEN_COMPAT;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700181 }
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700182
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700183 if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
184 applicationDensity = DisplayMetrics.DENSITY_DEVICE;
185 applicationScale = 1.0f;
186 applicationInvertedScale = 1.0f;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700187 } else {
Dianne Hackborn2784ff02009-07-18 17:13:29 -0700188 applicationDensity = DisplayMetrics.DENSITY_DEFAULT;
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700189 applicationScale = DisplayMetrics.DENSITY_DEVICE
190 / (float) DisplayMetrics.DENSITY_DEFAULT;
191 applicationInvertedScale = 1.0f / applicationScale;
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400192 compatFlags |= SCALING_REQUIRED;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700193 }
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400194
195 mCompatibilityFlags = compatFlags;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700196 }
197
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400198 private CompatibilityInfo(int compFlags,
Dianne Hackborn2784ff02009-07-18 17:13:29 -0700199 int dens, float scale, float invertedScale) {
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700200 mCompatibilityFlags = compFlags;
Dianne Hackborn2784ff02009-07-18 17:13:29 -0700201 applicationDensity = dens;
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700202 applicationScale = scale;
203 applicationInvertedScale = invertedScale;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700204 }
205
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700206 private CompatibilityInfo() {
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400207 this(XLARGE_SCREENS | LARGE_SCREENS | EXPANDABLE,
Dianne Hackborn2784ff02009-07-18 17:13:29 -0700208 DisplayMetrics.DENSITY_DEVICE,
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700209 1.0f,
210 1.0f);
211 }
212
213 /**
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700214 * @return true if the scaling is required
215 */
216 public boolean isScalingRequired() {
Dianne Hackborn723738c2009-06-25 19:48:04 -0700217 return (mCompatibilityFlags & SCALING_REQUIRED) != 0;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700218 }
219
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700220 public boolean supportsScreen() {
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400221 return (mCompatibilityFlags&NEEDS_SCREEN_COMPAT) == 0;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700222 }
223
Dianne Hackborn0f1de9a2011-05-11 17:34:49 -0700224 public boolean neverSupportsScreen() {
225 return (mCompatibilityFlags&NEVER_COMPAT) != 0;
226 }
227
228 public boolean alwaysSupportsScreen() {
229 return (mCompatibilityFlags&ALWAYS_COMPAT) != 0;
230 }
231
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700232 @Override
233 public String toString() {
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400234 return "CompatibilityInfo{scale=" + applicationScale + "}";
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700235 }
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700236
237 /**
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700238 * Returns the translator which translates the coordinates in compatibility mode.
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700239 * @param params the window's parameter
240 */
Mitsuru Oshima589cebe2009-07-22 20:38:58 -0700241 public Translator getTranslator() {
242 return isScalingRequired() ? new Translator() : null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700243 }
244
245 /**
246 * A helper object to translate the screen and window coordinates back and forth.
247 * @hide
248 */
249 public class Translator {
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700250 final public float applicationScale;
251 final public float applicationInvertedScale;
252
253 private Rect mContentInsetsBuffer = null;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700254 private Rect mVisibleInsetsBuffer = null;
Jeff Brownfbf09772011-01-16 14:06:57 -0800255 private Region mTouchableAreaBuffer = null;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700256
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700257 Translator(float applicationScale, float applicationInvertedScale) {
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700258 this.applicationScale = applicationScale;
259 this.applicationInvertedScale = applicationInvertedScale;
260 }
261
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700262 Translator() {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700263 this(CompatibilityInfo.this.applicationScale,
264 CompatibilityInfo.this.applicationInvertedScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700265 }
266
267 /**
268 * Translate the screen rect to the application frame.
269 */
270 public void translateRectInScreenToAppWinFrame(Rect rect) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700271 rect.scale(applicationInvertedScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700272 }
273
274 /**
275 * Translate the region in window to screen.
276 */
277 public void translateRegionInWindowToScreen(Region transparentRegion) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700278 transparentRegion.scale(applicationScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700279 }
280
281 /**
282 * Apply translation to the canvas that is necessary to draw the content.
283 */
284 public void translateCanvas(Canvas canvas) {
Mike Reedb5c17a62009-09-21 20:51:27 -0400285 if (applicationScale == 1.5f) {
286 /* When we scale for compatibility, we can put our stretched
287 bitmaps and ninepatches on exacty 1/2 pixel boundaries,
288 which can give us inconsistent drawing due to imperfect
289 float precision in the graphics engine's inverse matrix.
290
291 As a work-around, we translate by a tiny amount to avoid
292 landing on exact pixel centers and boundaries, giving us
293 the slop we need to draw consistently.
294
295 This constant is meant to resolve to 1/255 after it is
296 scaled by 1.5 (applicationScale). Note, this is just a guess
297 as to what is small enough not to create its own artifacts,
298 and big enough to avoid the precision problems. Feel free
299 to experiment with smaller values as you choose.
300 */
301 final float tinyOffset = 2.0f / (3 * 255);
302 canvas.translate(tinyOffset, tinyOffset);
303 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700304 canvas.scale(applicationScale, applicationScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700305 }
306
307 /**
308 * Translate the motion event captured on screen to the application's window.
309 */
310 public void translateEventInScreenToAppWindow(MotionEvent event) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700311 event.scale(applicationInvertedScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700312 }
313
314 /**
315 * Translate the window's layout parameter, from application's view to
316 * Screen's view.
317 */
318 public void translateWindowLayout(WindowManager.LayoutParams params) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700319 params.scale(applicationScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700320 }
321
322 /**
323 * Translate a Rect in application's window to screen.
324 */
325 public void translateRectInAppWindowToScreen(Rect rect) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700326 rect.scale(applicationScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700327 }
328
329 /**
330 * Translate a Rect in screen coordinates into the app window's coordinates.
331 */
332 public void translateRectInScreenToAppWindow(Rect rect) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700333 rect.scale(applicationInvertedScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700334 }
335
336 /**
Christopher Tatea53146c2010-09-07 11:57:52 -0700337 * Translate a Point in screen coordinates into the app window's coordinates.
338 */
339 public void translatePointInScreenToAppWindow(PointF point) {
340 final float scale = applicationInvertedScale;
341 if (scale != 1.0f) {
342 point.x *= scale;
343 point.y *= scale;
344 }
345 }
346
347 /**
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700348 * Translate the location of the sub window.
349 * @param params
350 */
351 public void translateLayoutParamsInAppWindowToScreen(LayoutParams params) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700352 params.scale(applicationScale);
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700353 }
354
355 /**
356 * Translate the content insets in application window to Screen. This uses
357 * the internal buffer for content insets to avoid extra object allocation.
358 */
359 public Rect getTranslatedContentInsets(Rect contentInsets) {
360 if (mContentInsetsBuffer == null) mContentInsetsBuffer = new Rect();
361 mContentInsetsBuffer.set(contentInsets);
362 translateRectInAppWindowToScreen(mContentInsetsBuffer);
363 return mContentInsetsBuffer;
364 }
365
366 /**
367 * Translate the visible insets in application window to Screen. This uses
Jeff Brownfbf09772011-01-16 14:06:57 -0800368 * the internal buffer for visible insets to avoid extra object allocation.
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700369 */
Jeff Brownfbf09772011-01-16 14:06:57 -0800370 public Rect getTranslatedVisibleInsets(Rect visibleInsets) {
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700371 if (mVisibleInsetsBuffer == null) mVisibleInsetsBuffer = new Rect();
372 mVisibleInsetsBuffer.set(visibleInsets);
373 translateRectInAppWindowToScreen(mVisibleInsetsBuffer);
374 return mVisibleInsetsBuffer;
375 }
Jeff Brownfbf09772011-01-16 14:06:57 -0800376
377 /**
378 * Translate the touchable area in application window to Screen. This uses
379 * the internal buffer for touchable area to avoid extra object allocation.
380 */
381 public Region getTranslatedTouchableArea(Region touchableArea) {
382 if (mTouchableAreaBuffer == null) mTouchableAreaBuffer = new Region();
383 mTouchableAreaBuffer.set(touchableArea);
384 mTouchableAreaBuffer.scale(applicationScale);
385 return mTouchableAreaBuffer;
386 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700387 }
388
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400389 public void applyToDisplayMetrics(DisplayMetrics inoutDm) {
390 if (!supportsScreen()) {
391 // This is a larger screen device and the app is not
392 // compatible with large screens, so diddle it.
393 CompatibilityInfo.updateCompatibleScreenFrame(inoutDm, null, inoutDm);
Dianne Hackborn5be8de32011-05-24 18:11:57 -0700394 } else {
Dianne Hackborn81e56d52011-05-26 00:55:58 -0700395 inoutDm.widthPixels = inoutDm.unscaledWidthPixels;
396 inoutDm.heightPixels = inoutDm.unscaledHeightPixels;
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400397 }
398
399 if (isScalingRequired()) {
400 float invertedRatio = applicationInvertedScale;
401 inoutDm.density *= invertedRatio;
402 inoutDm.densityDpi = (int)((inoutDm.density*DisplayMetrics.DENSITY_DEFAULT)+.5f);
403 inoutDm.scaledDensity *= invertedRatio;
404 inoutDm.xdpi *= invertedRatio;
405 inoutDm.ydpi *= invertedRatio;
406 inoutDm.widthPixels = (int) (inoutDm.widthPixels * invertedRatio + 0.5f);
407 inoutDm.heightPixels = (int) (inoutDm.heightPixels * invertedRatio + 0.5f);
408 }
409 }
410
411 public void applyToConfiguration(Configuration inoutConfig) {
412 if (!supportsScreen()) {
413 // This is a larger screen device and the app is not
414 // compatible with large screens, so we are forcing it to
415 // run as if the screen is normal size.
416 inoutConfig.screenLayout =
417 (inoutConfig.screenLayout&~Configuration.SCREENLAYOUT_SIZE_MASK)
418 | Configuration.SCREENLAYOUT_SIZE_NORMAL;
419 }
420 }
421
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700422 /**
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400423 * Compute the frame Rect for applications runs under compatibility mode.
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700424 *
425 * @param dm the display metrics used to compute the frame size.
426 * @param orientation the orientation of the screen.
427 * @param outRect the output parameter which will contain the result.
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400428 * @return Returns the scaling factor for the window.
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700429 */
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400430 public static float updateCompatibleScreenFrame(DisplayMetrics dm,
431 Rect outRect, DisplayMetrics outDm) {
Dianne Hackborn81e56d52011-05-26 00:55:58 -0700432 final int width = dm.unscaledWidthPixels;
433 final int height = dm.unscaledHeightPixels;
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400434 int shortSize, longSize;
435 if (width < height) {
436 shortSize = width;
437 longSize = height;
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -0700438 } else {
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400439 shortSize = height;
440 longSize = width;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700441 }
Dianne Hackborne2515ee2011-04-27 18:52:56 -0400442 int newShortSize = (int)(DEFAULT_NORMAL_SHORT_DIMENSION * dm.density + 0.5f);
443 float aspect = ((float)longSize) / shortSize;
444 if (aspect > MAXIMUM_ASPECT_RATIO) {
445 aspect = MAXIMUM_ASPECT_RATIO;
446 }
447 int newLongSize = (int)(newShortSize * aspect + 0.5f);
448 int newWidth, newHeight;
449 if (width < height) {
450 newWidth = newShortSize;
451 newHeight = newLongSize;
452 } else {
453 newWidth = newLongSize;
454 newHeight = newShortSize;
455 }
456
457 float sw = width/(float)newWidth;
458 float sh = height/(float)newHeight;
459 float scale = sw < sh ? sw : sh;
460 if (scale < 1) {
461 scale = 1;
462 }
463
464 if (outRect != null) {
465 final int left = (int)((width-(newWidth*scale))/2);
466 final int top = (int)((height-(newHeight*scale))/2);
467 outRect.set(left, top, left+newWidth, top+newHeight);
468 }
469
470 if (outDm != null) {
471 outDm.widthPixels = newWidth;
472 outDm.heightPixels = newHeight;
473 }
474
475 return scale;
476 }
477
478 @Override
479 public boolean equals(Object o) {
480 try {
481 CompatibilityInfo oc = (CompatibilityInfo)o;
482 if (mCompatibilityFlags != oc.mCompatibilityFlags) return false;
483 if (applicationDensity != oc.applicationDensity) return false;
484 if (applicationScale != oc.applicationScale) return false;
485 if (applicationInvertedScale != oc.applicationInvertedScale) return false;
486 return true;
487 } catch (ClassCastException e) {
488 return false;
489 }
490 }
491
492 @Override
493 public int hashCode() {
494 int result = 17;
495 result = 31 * result + mCompatibilityFlags;
496 result = 31 * result + applicationDensity;
497 result = 31 * result + Float.floatToIntBits(applicationScale);
498 result = 31 * result + Float.floatToIntBits(applicationInvertedScale);
499 return result;
500 }
501
502 @Override
503 public int describeContents() {
504 return 0;
505 }
506
507 @Override
508 public void writeToParcel(Parcel dest, int flags) {
509 dest.writeInt(mCompatibilityFlags);
510 dest.writeInt(applicationDensity);
511 dest.writeFloat(applicationScale);
512 dest.writeFloat(applicationInvertedScale);
513 }
514
515 public static final Parcelable.Creator<CompatibilityInfo> CREATOR
516 = new Parcelable.Creator<CompatibilityInfo>() {
517 public CompatibilityInfo createFromParcel(Parcel source) {
518 return new CompatibilityInfo(source);
519 }
520
521 public CompatibilityInfo[] newArray(int size) {
522 return new CompatibilityInfo[size];
523 }
524 };
525
526 private CompatibilityInfo(Parcel source) {
527 mCompatibilityFlags = source.readInt();
528 applicationDensity = source.readInt();
529 applicationScale = source.readFloat();
530 applicationInvertedScale = source.readFloat();
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700531 }
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700532}