폼 팩터(Form Factor)의 정의를 위키피디아에서 살펴보면 아래와 같다.
컴퓨터 시스템의 각 부품의 물리적 치수의 형태를 의미한다.
즉, 소프트웨어가 동작하는 기기의 형태를 말하는 것이다. 안드로이드 적용범위가 확대되면서, 안드로이드 앱이 실행할 수 있는 하드웨어 기기가 많아졌다. 예로, 크롬북이나 TV등을 예로 들 수 있다.
최근에 안드로이드 앱을 크롬북과 삼성 덱스(DEX)의 UI/UX에 어울리도록 작업을 하면서 특정 기능(키보드 등)은 모바일/태블릿에서만 필요하다. 그래서 앱이 동작하는 기기의 정보를 확인해야 했고, 아래의 코드로 해결을 했다.
아래 코드는 구글 TalkBack 깃헙 사이트의 https://github.com/google/talkback/blob/master/utils/src/main/java/FormFactorUtils.java 코드에 삼성 덱스(DEX)를 확인하는 코드를 추가했다.
아래의 ARC는 App Runtime for Chrome의 줄임말으로 폼 팩터가 크롬북이라는 것을 알 수 있다.
import android.app.UiModeManager; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.os.Build; public class FormFactorUtils { private static final int FORM_FACTOR_PHONE_OR_TABLET = 0; private static final int FORM_FACTOR_WATCH = 1; private static final int FORM_FACTOR_TV = 2; private static final int FORM_FACTOR_ARC = 3; private static final int FORM_FACTOR_SAMSUNG_DEX = 100; private static final String ARC_DEVICE_PATTERN = ".+_cheets|cheets_.+"; private static FormFactorUtils sInstance; private final int mFormFactor; private final boolean mHasAccessibilityShortcut; private FormFactorUtils(final Context context) { // Find device type. if (context.getApplicationContext() .getPackageManager() .hasSystemFeature(PackageManager.FEATURE_WATCH)) { mFormFactor = FORM_FACTOR_WATCH; } else if (isContextTelevision(context)) { mFormFactor = FORM_FACTOR_TV; } else if (Build.DEVICE != null && Build.DEVICE.matches(ARC_DEVICE_PATTERN)) { mFormFactor = FORM_FACTOR_ARC; } else if(isContextDex(context)) { mFormFactor = FORM_FACTOR_SAMSUNG_DEX; } else { mFormFactor = FORM_FACTOR_PHONE_OR_TABLET; } // Find whether device supports accessibility shortcut. mHasAccessibilityShortcut = (BuildVersionUtils.isAtLeastO() && mFormFactor == FORM_FACTOR_PHONE_OR_TABLET); } /** @return an instance of this Singleton. */ public static synchronized FormFactorUtils getInstance(final Context context) { if (sInstance == null) { sInstance = new FormFactorUtils(context); } return sInstance; } /** Return the cached version of the isWatch. */ public boolean isWatch() { return mFormFactor == FORM_FACTOR_WATCH; } public boolean isArc() { return mFormFactor == FORM_FACTOR_ARC; } public boolean isTv() { return mFormFactor == FORM_FACTOR_TV; } public boolean isPhoneOrTablet() { return mFormFactor == FORM_FACTOR_PHONE_OR_TABLET; } public boolean isDex() { return mFormFactor == FORM_FACTOR_SAMSUNG_DEX; } public boolean hasAccessibilityShortcut() { return mHasAccessibilityShortcut; } public static boolean useSpeakPasswordsServicePref() { return BuildVersionUtils.isAtLeastO(); } public static boolean isContextTelevision(Context context) { if (context == null) { return false; } UiModeManager modeManager = (UiModeManager) context.getSystemService(Context.UI_MODE_SERVICE); return modeManager != null && modeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION; } private static boolean isContextDex(Context context) { if (context == null) { return false; } try { Configuration config = context.getResources().getConfiguration(); Class configClass = config.getClass(); if (configClass.getField("SEM_DESKTOP_MODE_ENABLED").getInt(configClass) == configClass.getField("semDesktopModeEnabled").getInt(config)) { return true; } } catch (Exception e) { // ignore } return false; } }
카테고리랑 태그랑 작성일의 형태가 아주 인상적입니다.