+
+ private static boolean shouldLaunchTouchAbsorber(Context context) {
+ return isOverridingFreeformHack(context) && !isChromeOs(context) && getCurrentApiVersion() < 29.0f;
+ }
+
+ public static boolean isDesktopIconsEnabled(Context context) {
+ return !canBootToFreeform(context, false) && !shouldLaunchTouchAbsorber(context);
+ }
+
+ public static boolean isSystemTrayEnabled(Context context) {
+ SharedPreferences pref = getSharedPreferences(context);
+
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+ && pref.getBoolean("sys_tray", context.getResources().getBoolean(R.bool.tb_def_sys_tray))
+ && pref.getBoolean("full_length", context.getResources().getBoolean(R.bool.tb_def_full_length))
+ && !getTaskbarPosition(context).contains("vertical");
+ }
+
+ @SuppressWarnings("deprecation")
+ public static boolean isLibrary(Context context) {
+ return !context.getPackageName().equals(BuildConfig.APPLICATION_ID);
+ }
+
+ public static boolean applyDisplayCutoutModeTo(WindowManager.LayoutParams params) {
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ params.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ return true;
+ }
+
+ return false;
+ }
+
+ private static boolean hasAndroidTVSettings(Context context) {
+ return getInstalledPackage(context, "com.android.tv.settings") != null
+ && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
+ }
+
+ public static void restartApp(Activity activity, boolean shouldFade) {
+ Intent restartIntent = new Intent(activity, MainActivity.class);
+ restartIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+ activity.startActivity(restartIntent);
+
+ activity.overridePendingTransition(
+ shouldFade ? android.R.anim.fade_in : 0,
+ shouldFade ? android.R.anim.fade_out : 0
+ );
+
+ System.exit(0);
+ }
+
+ public static boolean isDesktopModeSupported(Context context) {
+ if(isLauncherPermanentlyEnabled(context)
+ || isLibrary(context)
+ || !BuildConfig.DEBUG // TODO remove this line
+ || isChromeOs(context))
+ return false;
+
+ return Build.VERSION.SDK_INT > Build.VERSION_CODES.P
+ && context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS);
+ }
+
+ public static boolean isDesktopModeActive(Context context) {
+ if(!isDesktopModeSupported(context)) return false;
+
+ boolean desktopModePrefEnabled;
+
+ try {
+ desktopModePrefEnabled = Settings.Global.getInt(context.getContentResolver(), "force_desktop_mode_on_external_displays") == 1;
+ } catch (Settings.SettingNotFoundException e) {
+ desktopModePrefEnabled = false;
+ }
+
+ return desktopModePrefEnabled && getExternalDisplayID(context) != Display.DEFAULT_DISPLAY;
+ }
+
+ public static boolean shouldStartDesktopMode(Context context) {
+ SharedPreferences pref = getSharedPreferences(context);
+
+ return isDesktopModeSupported(context)
+ && pref.getBoolean("desktop_mode", false)
+ && !pref.getBoolean("launcher", false);
+ }
+
+ // TODO remove this in favor of the existing getDisplayID method?
+ public static int getExternalDisplayID(Context context) {
+ DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
+ Display[] displays = dm.getDisplays();
+
+ return displays[displays.length - 1].getDisplayId();
+ }
+
+ @SuppressLint("PrivateApi")
+ private static Object getWindowManagerService() throws Exception {
+ return Class.forName("android.view.WindowManagerGlobal")
+ .getMethod("getWindowManagerService")
+ .invoke(null);
+ }
+
+ @SuppressLint("PrivateApi")
+ private static void setDensity(int displayID, String value) throws Exception {
+ // From android.os.UserHandle
+ final int USER_CURRENT_OR_SELF = -3;
+
+ if(value.equals("reset")) {
+ Class.forName("android.view.IWindowManager")
+ .getMethod("clearForcedDisplayDensityForUser", int.class, int.class)
+ .invoke(getWindowManagerService(), displayID, USER_CURRENT_OR_SELF);
+ } else {
+ int density = Integer.parseInt(value);
+
+ Class.forName("android.view.IWindowManager")
+ .getMethod("setForcedDisplayDensityForUser", int.class, int.class, int.class)
+ .invoke(getWindowManagerService(), displayID, density, USER_CURRENT_OR_SELF);
+ }
+ }
+
+ @SuppressLint("PrivateApi")
+ private static void setOverscan(int displayID, int value) throws Exception {
+ Class.forName("android.view.IWindowManager")
+ .getMethod("setOverscan", int.class, int.class, int.class, int.class, int.class)
+ .invoke(getWindowManagerService(), displayID, 0, 0, 0, value);
+ }
+
+ public static void registerReceiver(Context context, BroadcastReceiver receiver, String... actions) {
+ unregisterReceiver(context, receiver);
+
+ IntentFilter intentFilter = new IntentFilter();
+ for(String action : actions) {
+ intentFilter.addAction(action);
+ }
+
+ LocalBroadcastManager.getInstance(context).registerReceiver(receiver, intentFilter);
+ }
+
+ public static void unregisterReceiver(Context context, BroadcastReceiver receiver) {
+ LocalBroadcastManager.getInstance(context).unregisterReceiver(receiver);
+ }
+
+ public static void sendBroadcast(Context context, String action) {
+ sendBroadcast(context, new Intent(action));
+ }
+
+ public static void sendBroadcast(Context context, Intent intent) {
+ LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
+ }
+
+ @SuppressWarnings("rawtypes")
+ public static void setComponentEnabled(Context context, Class clazz, boolean enabled) {
+ ComponentName component = new ComponentName(context, clazz);
+ context.getPackageManager().setComponentEnabledSetting(component,
+ enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+ : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP);
+ }