// -*- mode: java; c-basic-offset: 2; -*- // Copyright 2009-2015 Google, All Rights reserved // Copyright 2011-2015 MIT, All rights reserved // Released under the Apache License, Version 2.0 // http://www.apache.org/licenses/LICENSE-2.0 package com.google.appinventor.components.runtime.util; import android.content.Context; import android.graphics.Point; import android.util.DisplayMetrics; import android.util.Log; import android.view.Display; import android.view.WindowManager; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * Helper methods for computing scaled sizes for screen compatibility mode * */ public final class ScreenDensityUtil { private static final String LOG_TAG = "ScreenDensityUtil"; // Much of this compatibility scaling code/constant is taken // from the Android source code. public static final int DEFAULT_NORMAL_SHORT_DIMENSION = 320; public static final float MAXIMUM_ASPECT_RATIO = (854f/480f); private ScreenDensityUtil() { } /** * Compute the scaling for applications runs under compatibility mode. * This code is partially taken from CompatibilityInfo.java from the Android 5.0 source * * @param context Context in the screen to get the density of * @return Returns the scaling factor for the window. */ public static float computeCompatibleScaling(Context context) { DisplayMetrics dm = context.getResources().getDisplayMetrics(); Point rawDims = new Point(); getRawScreenDim(context, rawDims); int width = rawDims.x; int height = rawDims.y; int shortSize, longSize; if (width < height) { shortSize = width; longSize = height; } else { shortSize = height; longSize = width; } int newShortSize = (int)(DEFAULT_NORMAL_SHORT_DIMENSION * dm.density + 0.5f); float aspect = ((float)longSize) / shortSize; if (aspect > MAXIMUM_ASPECT_RATIO) { aspect = MAXIMUM_ASPECT_RATIO; } int newLongSize = (int)(newShortSize * aspect + 0.5f); int newWidth, newHeight; if (width < height) { newWidth = newShortSize; newHeight = newLongSize; } else { newWidth = newLongSize; newHeight = newShortSize; } float sw = width/(float)newWidth; float sh = height/(float)newHeight; float scale = sw < sh ? sw : sh; if (scale < 1) { scale = 1; } return scale; } /** * Determine the actual size of the screen in pixels. * Inspired by http://stackoverflow.com/a/17512853/135135 * * @param context context to get screen size of. * @param outSize Set to the real size of the display. */ public static void getRawScreenDim(Context context, Point outSize) { final DisplayMetrics metrics = new DisplayMetrics(); final WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); int sdkLevel = SdkLevel.getLevel(); if (sdkLevel >= SdkLevel.LEVEL_JELLYBEAN_MR1) { // On API level 17, a public method was added to get the actual sizes JellybeanUtil.getRealSize(display, outSize); } else if ( sdkLevel > SdkLevel.LEVEL_GINGERBREAD_MR1){ // Before API level 17, the realsize method did not exist // We use reflection instead to access some hidden methods // Does not work for 3.x, will just error try { Method getRawH = Display.class.getMethod("getRawHeight"); Method getRawW = Display.class.getMethod("getRawWidth"); try { outSize.x = (Integer) getRawW.invoke(display); outSize.y = (Integer) getRawH.invoke(display); } catch (IllegalArgumentException e) { Log.e(LOG_TAG, "Error reading raw screen size", e); } catch (IllegalAccessException e) { Log.e(LOG_TAG, "Error reading raw screen size", e); } catch (InvocationTargetException e) { Log.e(LOG_TAG, "Error reading raw screen size", e); } } catch (NoSuchMethodException e) { Log.e(LOG_TAG, "Error reading raw screen size", e); } } else { // The raw height and width functions were added after verison 10 // Before that, the methods actually returned the raw values outSize.x = display.getWidth(); outSize.y = display.getHeight(); } } }