1 // Copyright 2014 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 5 package org.chromium.ui.base; 6 7 import android.content.Context; 8 9 import androidx.annotation.UiThread; 10 11 import org.chromium.base.ContextUtils; 12 import org.chromium.base.ThreadUtils; 13 import org.chromium.base.annotations.CalledByNative; 14 import org.chromium.ui.R; 15 import org.chromium.ui.display.DisplayAndroid; 16 import org.chromium.ui.display.DisplayUtil; 17 18 /** 19 * UI utilities for accessing form factor information. 20 */ 21 public class DeviceFormFactor { 22 /** 23 * Miniumum screen size in dp to be considered a tablet. Matches the value 24 * used by res/ directories. E.g.: res/values-sw600dp/values.xml 25 */ 26 public static final int MINIMUM_TABLET_WIDTH_DP = 600; 27 28 /** 29 * Matches the value set in res/values-sw600dp/values.xml 30 */ 31 private static final int SCREEN_BUCKET_TABLET = 2; 32 33 /** 34 * Matches the value set in res/values-sw720dp/values.xml 35 */ 36 private static final int SCREEN_BUCKET_LARGET_TABLET = 3; 37 38 /** 39 * Each activity could be on a different display, and this will just tell you whether the 40 * display associated with the application context is "tablet sized". 41 * Use {@link #isNonMultiDisplayContextOnTablet} or {@link #isWindowOnTablet} instead. 42 */ 43 @CalledByNative 44 @Deprecated isTablet()45 public static boolean isTablet() { 46 return detectScreenWidthBucket(ContextUtils.getApplicationContext()) 47 >= SCREEN_BUCKET_TABLET; 48 } 49 50 /** 51 * See {@link DisplayAndroid#getNonMultiDisplay}} for what "NonMultiDisplay" means. 52 * When possible, it is generally more correct to use {@link #isWindowOnTablet}. 53 * Only Activity instances and Contexts that wrap Activities are meaningfully associated with 54 * displays, so care should be taken to pass a context that makes sense. 55 * 56 * @return Whether the display associated with the given context is large enough to be 57 * considered a tablet and will thus load tablet-specific resources (those in the config 58 * -sw600). 59 * Not affected by Android N multi-window, but can change for external displays. 60 * E.g. http://developer.samsung.com/samsung-dex/testing 61 */ isNonMultiDisplayContextOnTablet(Context context)62 public static boolean isNonMultiDisplayContextOnTablet(Context context) { 63 return detectScreenWidthBucket(context) >= SCREEN_BUCKET_TABLET; 64 } 65 66 /** 67 * @return Whether the display associated with the window is large enough to be 68 * considered a tablet and will thus load tablet-specific resources (those in the config 69 * -sw600). 70 * Not affected by Android N multi-window, but can change for external displays. 71 * E.g. http://developer.samsung.com/samsung-dex/testing 72 */ 73 @UiThread isWindowOnTablet(WindowAndroid windowAndroid)74 public static boolean isWindowOnTablet(WindowAndroid windowAndroid) { 75 return detectScreenWidthBucket(windowAndroid) >= SCREEN_BUCKET_TABLET; 76 } 77 78 /** 79 * @return Whether the display associated with the given context is large enough to be 80 * considered a large tablet and will thus load large-tablet-specific resources (those 81 * in the config -sw720). 82 * Not affected by Android N multi-window, but can change for external displays. 83 * E.g. http://developer.samsung.com/samsung-dex/testing 84 */ isNonMultiDisplayContextOnLargeTablet(Context context)85 public static boolean isNonMultiDisplayContextOnLargeTablet(Context context) { 86 return detectScreenWidthBucket(context) == SCREEN_BUCKET_LARGET_TABLET; 87 } 88 89 /** 90 * Detect the screen width bucket by loading the min_screen_width_bucket value (Android will 91 * select the value from the correct directory; values, *-sw600dp, *-sw720dp). We can't use any 92 * shortcuts here since there are several devices that are phone or tablet, but load each 93 * others' resources (see https://crbug.com/850096 and https://crbug.com/669974 for more info). 94 * @param context An Android context to read resources from. 95 * @return The screen width bucket the device is in (see constants at the top of this class). 96 */ detectScreenWidthBucket(Context context)97 private static int detectScreenWidthBucket(Context context) { 98 return context.getResources().getInteger(R.integer.min_screen_width_bucket); 99 } 100 detectScreenWidthBucket(WindowAndroid windowAndroid)101 private static int detectScreenWidthBucket(WindowAndroid windowAndroid) { 102 ThreadUtils.assertOnUiThread(); 103 Context context = windowAndroid.getContext().get(); 104 if (context == null) return 0; 105 return context.getResources().getInteger(R.integer.min_screen_width_bucket); 106 } 107 108 /** 109 * @return The minimum width in px at which the display should be treated like a tablet for 110 * layout. 111 */ 112 @UiThread getNonMultiDisplayMinimumTabletWidthPx(Context context)113 public static int getNonMultiDisplayMinimumTabletWidthPx(Context context) { 114 return getMinimumTabletWidthPx(DisplayAndroid.getNonMultiDisplay(context)); 115 } 116 117 /** 118 * @return The minimum width in px at which the display should be treated like a tablet for 119 * layout. 120 */ getMinimumTabletWidthPx(DisplayAndroid display)121 public static int getMinimumTabletWidthPx(DisplayAndroid display) { 122 return DisplayUtil.dpToPx(display, DeviceFormFactor.MINIMUM_TABLET_WIDTH_DP); 123 } 124 } 125