X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fcom%2Ffarmerbb%2Ftaskbar%2Futil%2FU.java;h=4d922d6ad68b6bbf821cb3375c64d180382e335f;hb=a42891dd10be0b3bcc3ba5db0b00f2f77f1557dd;hp=2add266a16a0090e91aab4c409124c32b2d48314;hpb=54b8057e2a6721598b34f09a976cf31be129a280;p=android-x86%2Fpackages-apps-Taskbar.git diff --git a/app/src/main/java/com/farmerbb/taskbar/util/U.java b/app/src/main/java/com/farmerbb/taskbar/util/U.java index 2add266a..4d922d6a 100644 --- a/app/src/main/java/com/farmerbb/taskbar/util/U.java +++ b/app/src/main/java/com/farmerbb/taskbar/util/U.java @@ -19,15 +19,18 @@ import android.Manifest; import android.accessibilityservice.AccessibilityService; import android.annotation.SuppressLint; import android.annotation.TargetApi; +import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.AlertDialog; import android.app.AppOpsManager; import android.app.Service; import android.content.ActivityNotFoundException; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; @@ -65,8 +68,10 @@ import com.farmerbb.taskbar.R; import com.farmerbb.taskbar.activity.ContextMenuActivity; import com.farmerbb.taskbar.activity.DummyActivity; import com.farmerbb.taskbar.activity.InvisibleActivityFreeform; +import com.farmerbb.taskbar.activity.MainActivity; import com.farmerbb.taskbar.activity.TouchAbsorberActivity; import com.farmerbb.taskbar.activity.dark.ContextMenuActivityDark; +import com.farmerbb.taskbar.content.TaskbarIntent; import com.farmerbb.taskbar.service.DashboardService; import com.farmerbb.taskbar.service.NotificationService; import com.farmerbb.taskbar.service.PowerMenuService; @@ -105,6 +110,9 @@ public class U { private static final int WINDOWING_MODE_FULLSCREEN = 1; private static final int WINDOWING_MODE_FREEFORM = 5; + public static final int EXPORT = 123; + public static final int IMPORT = 456; + @SuppressWarnings("deprecation") public static SharedPreferences getSharedPreferences(Context context) { return context.getSharedPreferences(BuildConfig.APPLICATION_ID + "_preferences", Context.MODE_PRIVATE); @@ -114,7 +122,6 @@ public class U { showPermissionDialog(context, null, null); } - @TargetApi(Build.VERSION_CODES.M) public static AlertDialog showPermissionDialog(Context context, Runnable onError, Runnable onFinish) { Runnable finalOnFinish = onFinish == null ? () -> {} @@ -124,25 +131,48 @@ public class U { ? () -> showErrorDialog(context, "SYSTEM_ALERT_WINDOW", finalOnFinish) : onError; - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.tb_permission_dialog_title) + AlertDialog.Builder builder; + if(hasAndroidTVSettings(context)) + builder = buildPermissionDialogAndroidTV(context, finalOnError, finalOnFinish); + else + builder = buildPermissionDialogStandard(context, finalOnError, finalOnFinish); + + AlertDialog dialog = builder.create(); + dialog.show(); + dialog.setCancelable(false); + + return dialog; + } + + @TargetApi(Build.VERSION_CODES.M) + private static AlertDialog.Builder buildPermissionDialogStandard(Context context, Runnable onError, Runnable onFinish) { + return new AlertDialog.Builder(context) + .setTitle(R.string.tb_permission_dialog_title) .setMessage(R.string.tb_permission_dialog_message) .setPositiveButton(R.string.tb_action_grant_permission, (dialog, which) -> { try { context.startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context.getPackageName()))); - finalOnFinish.run(); + onFinish.run(); } catch (ActivityNotFoundException e) { - finalOnError.run(); + onError.run(); } }); + } - AlertDialog dialog = builder.create(); - dialog.show(); - dialog.setCancelable(false); - - return dialog; + private static AlertDialog.Builder buildPermissionDialogAndroidTV(Context context, Runnable onError, Runnable onFinish) { + return new AlertDialog.Builder(context) + .setTitle(R.string.tb_permission_dialog_title) + .setMessage(R.string.tb_permission_dialog_message_alt) + .setPositiveButton(R.string.tb_action_open_settings, (dialog, which) -> { + try { + context.startActivity(new Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS)); + onFinish.run(); + } catch (ActivityNotFoundException e) { + onError.run(); + } + }); } public static AlertDialog showErrorDialog(Context context, String appopCmd) { @@ -176,9 +206,7 @@ public class U { } public static void sendAccessibilityAction(Context context, int action, Runnable onComplete) { - ComponentName component = new ComponentName(context, PowerMenuService.class); - context.getPackageManager().setComponentEnabledSetting(component, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, - PackageManager.DONT_KILL_APP); + setComponentEnabled(context, PowerMenuService.class, true); boolean isAccessibilityServiceEnabled = isAccessibilityServiceEnabled(context); @@ -202,9 +230,9 @@ public class U { } new Handler().postDelayed(() -> { - Intent intent = new Intent("com.farmerbb.taskbar.ACCESSIBILITY_ACTION"); + Intent intent = new Intent(TaskbarIntent.ACTION_ACCESSIBILITY_ACTION); intent.putExtra("action", action); - LocalBroadcastManager.getInstance(context).sendBroadcast(intent); + sendBroadcast(context, intent); try { Settings.Secure.putString(context.getContentResolver(), @@ -215,9 +243,9 @@ public class U { if(onComplete != null) onComplete.run(); }, 100); } else if(isAccessibilityServiceEnabled) { - Intent intent = new Intent("com.farmerbb.taskbar.ACCESSIBILITY_ACTION"); + Intent intent = new Intent(TaskbarIntent.ACTION_ACCESSIBILITY_ACTION); intent.putExtra("action", action); - LocalBroadcastManager.getInstance(context).sendBroadcast(intent); + sendBroadcast(context, intent); if(onComplete != null) onComplete.run(); } else { @@ -227,7 +255,7 @@ public class U { intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION); try { - context.startActivity(intent, getActivityOptionsBundle(context, ApplicationType.APPLICATION, null)); + context.startActivity(intent, getActivityOptionsBundle(context, ApplicationType.APP_PORTRAIT, null)); } catch (IllegalArgumentException | SecurityException e) { /* Gracefully fail */ } }); } @@ -275,8 +303,10 @@ public class U { null, false, false, + false, shortcut, - view); + view, + null); } public static void launchApp(final Context context, @@ -289,27 +319,47 @@ public class U { entry, windowSize, launchedFromTaskbar, + false, openInNewWindow, null, - view); + view, + null); + } + + public static void launchApp(final Context context, + final AppEntry entry, + final String windowSize, + final Runnable onError) { + launchApp(context, + entry, + windowSize, + false, + true, + false, + null, + null, + onError); } private static void launchApp(final Context context, final AppEntry entry, final String windowSize, final boolean launchedFromTaskbar, + final boolean isPersistentShortcut, final boolean openInNewWindow, final ShortcutInfo shortcut, - final View view) { - launchApp(context, launchedFromTaskbar, () -> continueLaunchingApp(context, entry, - windowSize, openInNewWindow, shortcut, view)); + final View view, + final Runnable onError) { + launchApp(context, launchedFromTaskbar, isPersistentShortcut, () -> + continueLaunchingApp(context, entry, windowSize, openInNewWindow, shortcut, view, onError) + ); } public static void launchApp(Context context, Runnable runnable) { - launchApp(context, true, runnable); + launchApp(context, true, false, runnable); } - private static void launchApp(Context context, boolean launchedFromTaskbar, Runnable runnable) { + private static void launchApp(Context context, boolean launchedFromTaskbar, boolean isPersistentShortcut, Runnable runnable) { SharedPreferences pref = getSharedPreferences(context); FreeformHackHelper helper = FreeformHackHelper.getInstance(); @@ -320,7 +370,7 @@ public class U { boolean noAnimation = pref.getBoolean("disable_animations", false); if(hasFreeformSupport(context) - && pref.getBoolean("freeform_hack", false) + && (pref.getBoolean("freeform_hack", false) || isPersistentShortcut) && (!helper.isInFreeformWorkspace() || specialLaunch)) { new Handler().postDelayed(() -> { startFreeformHack(context, true); @@ -350,9 +400,9 @@ public class U { } public static void stopFreeformHack(Context context) { - LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.FINISH_FREEFORM_ACTIVITY")); + sendBroadcast(context, TaskbarIntent.ACTION_FINISH_FREEFORM_ACTIVITY); - if(isOverridingFreeformHack(context)) { + if(isOverridingFreeformHack(context, false)) { FreeformHackHelper helper = FreeformHackHelper.getInstance(); helper.setFreeformHackActive(false); helper.setInFreeformWorkspace(false); @@ -365,7 +415,8 @@ public class U { String windowSize, boolean openInNewWindow, ShortcutInfo shortcut, - View view) { + View view, + Runnable onError) { SharedPreferences pref = getSharedPreferences(context); Intent intent = new Intent(); intent.setComponent(ComponentName.unflattenFromString(entry.getComponentName())); @@ -396,7 +447,7 @@ public class U { } } - ApplicationType type = getApplicationType(context, entry.getPackageName()); + ApplicationType type = getApplicationType(context, entry); if(windowSize == null) windowSize = SavedWindowSizes.getInstance(context).getWindowSize(context, entry.getPackageName()); @@ -410,38 +461,37 @@ public class U { try { context.startActivity(intent, bundle); } catch (ActivityNotFoundException e) { - launchAndroidForWork(context, intent.getComponent(), bundle, entry.getUserId(context)); + launchAndroidForWork(context, intent.getComponent(), bundle, entry.getUserId(context), onError); } catch (IllegalArgumentException | SecurityException e) { /* Gracefully fail */ } } else - launchAndroidForWork(context, intent.getComponent(), bundle, entry.getUserId(context)); + launchAndroidForWork(context, intent.getComponent(), bundle, entry.getUserId(context), onError); } else - launchShortcut(context, shortcut, bundle); + launchShortcut(context, shortcut, bundle, onError); }); - if(shouldCollapse(context, true)) - LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_TASKBAR")); - else - LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU")); + if(shouldCollapse(context, true)) { + sendBroadcast(context, TaskbarIntent.ACTION_HIDE_TASKBAR); + } else { + sendBroadcast(context, TaskbarIntent.ACTION_HIDE_START_MENU); + } } - @TargetApi(Build.VERSION_CODES.N) - private static Bundle launchMode1(Context context, ApplicationType type, View view) { + private static Bundle launchMode1(Context context, ApplicationType type, View view, int factor) { DisplayInfo display = getDisplayInfo(context); - int width1 = display.width / 8; + int width1 = display.width / factor; int width2 = display.width - width1; - int height1 = display.height / 8; + int height1 = display.height / factor; int height2 = display.height - height1; - return getActivityOptions(context, type, view).setLaunchBounds(new Rect( + return getActivityOptionsBundle(context, type, view, width1, height1, width2, height2 - )).toBundle(); + ); } - @TargetApi(Build.VERSION_CODES.N) private static Bundle launchMode2(Context context, int launchType, ApplicationType type, View view) { DisplayInfo display = getDisplayInfo(context); @@ -481,49 +531,57 @@ public class U { else if(launchType == LEFT && isPortrait) bottom = halfPortrait; - return getActivityOptions(context, type, view) - .setLaunchBounds(new Rect(left, top, right, bottom)).toBundle(); + return getActivityOptionsBundle(context, type, view, left, top, right, bottom); } - @TargetApi(Build.VERSION_CODES.N) private static Bundle launchMode3(Context context, ApplicationType type, View view) { DisplayInfo display = getDisplayInfo(context); + boolean isLandscape = type == ApplicationType.APP_LANDSCAPE; + int widthDimen = isLandscape ? R.dimen.tb_phone_size_height : R.dimen.tb_phone_size_width; + int heightDimen = isLandscape ? R.dimen.tb_phone_size_width : R.dimen.tb_phone_size_height; + int width1 = display.width / 2; - int width2 = context.getResources().getDimensionPixelSize(R.dimen.tb_phone_size_width) / 2; + int width2 = context.getResources().getDimensionPixelSize(widthDimen) / 2; int height1 = display.height / 2; - int height2 = context.getResources().getDimensionPixelSize(R.dimen.tb_phone_size_height) / 2; + int height2 = context.getResources().getDimensionPixelSize(heightDimen) / 2; - return getActivityOptions(context, type, view).setLaunchBounds(new Rect( + return getActivityOptionsBundle(context, type, view, width1 - width2, height1 - height2, width1 + width2, height1 + height2 - )).toBundle(); + ); } - private static void launchAndroidForWork(Context context, ComponentName componentName, Bundle bundle, long userId) { + private static void launchAndroidForWork(Context context, ComponentName componentName, Bundle bundle, long userId, Runnable onError) { UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE); try { launcherApps.startMainActivity(componentName, userManager.getUserForSerialNumber(userId), null, bundle); - } catch (ActivityNotFoundException | NullPointerException | SecurityException e) { /* Gracefully fail */ } + } catch (ActivityNotFoundException | NullPointerException + | IllegalStateException | SecurityException e) { + if(onError != null) launchApp(context, onError); + } } @TargetApi(Build.VERSION_CODES.N_MR1) - private static void launchShortcut(Context context, ShortcutInfo shortcut, Bundle bundle) { + private static void launchShortcut(Context context, ShortcutInfo shortcut, Bundle bundle, Runnable onError) { LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE); if(launcherApps.hasShortcutHostPermission()) { try { launcherApps.startShortcut(shortcut, null, bundle); - } catch (ActivityNotFoundException | NullPointerException | SecurityException e) { /* Gracefully fail */ } + } catch (ActivityNotFoundException | NullPointerException + | IllegalStateException | SecurityException e) { + if(onError != null) launchApp(context, onError); + } } } private static void prepareToStartActivity(Context context, boolean openInNewWindow, Runnable runnable) { - LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_CONTEXT_MENU")); + sendBroadcast(context, TaskbarIntent.ACTION_HIDE_CONTEXT_MENU); if(!FreeformHackHelper.getInstance().isTouchAbsorberActive() && shouldLaunchTouchAbsorber(context)) { @@ -546,22 +604,19 @@ public class U { prepareToStartActivity(context, false, () -> context.startActivity(intent, bundle)); } - @TargetApi(Build.VERSION_CODES.N) public static void startActivityLowerRight(Context context, Intent intent) { DisplayInfo display = getDisplayInfo(context); try { context.startActivity(intent, - getActivityOptions(context, ApplicationType.FREEFORM_HACK, null) - .setLaunchBounds(new Rect( - display.width, - display.height, - display.width + 1, - display.height + 1 - )).toBundle()); + getActivityOptionsBundle(context, ApplicationType.FREEFORM_HACK, null, + display.width, + display.height, + display.width + 1, + display.height + 1 + )); } catch (IllegalArgumentException | SecurityException e) { /* Gracefully fail */ } } - @TargetApi(Build.VERSION_CODES.N) public static void startTouchAbsorberActivity(Context context) { String position = getTaskbarPosition(context); DisplayInfo display = getDisplayInfo(context); @@ -588,8 +643,8 @@ public class U { try { context.startActivity(intent, - getActivityOptions(context, ApplicationType.FREEFORM_HACK, null) - .setLaunchBounds(new Rect(left, top, right, bottom)).toBundle()); + getActivityOptionsBundle(context, ApplicationType.FREEFORM_HACK, null, + left, top, right, bottom)); } catch (IllegalArgumentException | SecurityException e) { /* Gracefully fail */ } } @@ -618,10 +673,8 @@ public class U { intent.putExtra("context_menu_fix", true); context.startActivity(intent, - getActivityOptions(context, ApplicationType.CONTEXT_MENU, null) - .setLaunchBounds( - new Rect(0, 0, display.width, display.height) - ).toBundle()); + getActivityOptionsBundle(context, ApplicationType.CONTEXT_MENU, null, + 0, 0, display.width, display.height)); } else context.startActivity(intent); } @@ -888,10 +941,11 @@ public class U { } public static boolean canBootToFreeform(Context context) { - SharedPreferences pref = getSharedPreferences(context); - return hasFreeformSupport(context) - && pref.getBoolean("freeform_hack", false) - && !isOverridingFreeformHack(context); + return canBootToFreeform(context, true); + } + + private static boolean canBootToFreeform(Context context, boolean checkPref) { + return hasFreeformSupport(context) && !isOverridingFreeformHack(context, checkPref); } public static boolean isSamsungDevice() { @@ -944,7 +998,6 @@ public class U { return pref.getInt("accent_color", context.getResources().getInteger(R.integer.tb_translucent_white)); } - @TargetApi(Build.VERSION_CODES.M) public static boolean canDrawOverlays(Context context) { return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(context); } @@ -968,7 +1021,7 @@ public class U { return getActivityOptions(null, null, view); } - private static ActivityOptions getActivityOptions(Context context, ApplicationType applicationType, View view) { + public static ActivityOptions getActivityOptions(Context context, ApplicationType applicationType, View view) { ActivityOptions options; if(view != null) options = ActivityOptions.makeScaleUpAnimation(view, 0, 0, view.getWidth(), view.getHeight()); @@ -980,7 +1033,6 @@ public class U { constructor.setAccessible(true); options = constructor.newInstance(); } catch (Exception e) { - // If this ever happens, the app will likely crash at this point due to NPE return null; } } @@ -991,13 +1043,14 @@ public class U { int stackId = -1; switch(applicationType) { - case APPLICATION: + case APP_PORTRAIT: + case APP_LANDSCAPE: if(FreeformHackHelper.getInstance().isFreeformHackActive()) stackId = getFreeformWindowModeId(); else stackId = getFullscreenWindowModeId(); break; - case GAME: + case APP_FULLSCREEN: stackId = getFullscreenWindowModeId(); break; case FREEFORM_HACK: @@ -1057,8 +1110,12 @@ public class U { return getActivityOptions(view).toBundle(); switch(windowSize) { + case "standard": + if(getCurrentApiVersion() > 29.0f) + return launchMode1(context, type, view, 4); + break; case "large": - return launchMode1(context, type, view); + return launchMode1(context, type, view, 8); case "fullscreen": return launchMode2(context, MAXIMIZED, type, view); case "half_left": @@ -1072,8 +1129,47 @@ public class U { return getActivityOptions(context, type, view).toBundle(); } - private static ApplicationType getApplicationType(Context context, String packageName) { - return isGame(context, packageName) ? ApplicationType.GAME : ApplicationType.APPLICATION; + private static Bundle getActivityOptionsBundle(Context context, ApplicationType applicationType, View view, + int left, int top, int right, int bottom) { + ActivityOptions options = getActivityOptions(context, applicationType, view); + if(options == null) + return null; + + if(Build.VERSION.SDK_INT < Build.VERSION_CODES.N) + return options.toBundle(); + + return options.setLaunchBounds(new Rect(left, top, right, bottom)).toBundle(); + } + + @SuppressLint("SwitchIntDef") + private static ApplicationType getApplicationType(Context context, AppEntry entry) { + if(isGame(context, entry.getPackageName())) + return ApplicationType.APP_FULLSCREEN; + + try { + ActivityInfo info = context.getPackageManager().getActivityInfo( + ComponentName.unflattenFromString(entry.getComponentName()), + 0 + ); + + switch(info.screenOrientation) { + case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: + case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE: + case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE: + case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE: + return ApplicationType.APP_LANDSCAPE; + + case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: + case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT: + case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT: + case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT: + return ApplicationType.APP_PORTRAIT; + } + } catch (PackageManager.NameNotFoundException e) { /* Gracefully fail */ } + + return context.getPackageName().equals(BuildConfig.ANDROIDX86_APPLICATION_ID) + ? ApplicationType.APP_LANDSCAPE + : ApplicationType.APP_PORTRAIT; } public static boolean isSystemApp(Context context) { @@ -1110,15 +1206,7 @@ public class U { if(context.getPackageName().equals(BuildConfig.ANDROIDX86_APPLICATION_ID)) return true; - PackageManager pm = context.getPackageManager(); - try { - pm.getPackageInfo(BuildConfig.SUPPORT_APPLICATION_ID, 0); - return pm.checkSignatures(BuildConfig.SUPPORT_APPLICATION_ID, context.getPackageName()) == PackageManager.SIGNATURE_MATCH - && context.getPackageName().equals(BuildConfig.BASE_APPLICATION_ID) - && isSystemApp(context); - } catch (PackageManager.NameNotFoundException e) { - return false; - } + return hasSupportLibrary(context, 0); } public static boolean hasSupportLibrary(Context context, int minVersion) { @@ -1201,7 +1289,7 @@ public class U { startTaskbarService(context, false); } - LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.RESTART")); + sendBroadcast(context, TaskbarIntent.ACTION_RESTART); } public static void restartNotificationService(Context context) { @@ -1216,18 +1304,38 @@ public class U { } public static void showHideNavigationBar(Context context, boolean show) { + if(!isDesktopModeActive(context) + && !isBlissOs(context) + && !hasSupportLibrary(context, 7)) { + return; + } + + int displayID = getDisplayID(); + int value = show ? 0 : getNavbarHeight(context) * -1; + + if(hasWriteSecureSettingsPermission(context)) { + try { + setOverscan(displayID, value); + return; + } catch (Exception e) { + // Fallback to next method + } + } + if(hasSupportLibrary(context, 7)) { Intent intent = new Intent(BuildConfig.SUPPORT_APPLICATION_ID + ".CHANGE_OVERSCAN"); intent.setPackage(BuildConfig.SUPPORT_APPLICATION_ID); - intent.putExtra("display_id", getDisplayID()); - intent.putExtra("value", show ? 0 : getNavbarHeight(context) * -1); + intent.putExtra("display_id", displayID); + intent.putExtra("value", value); context.sendBroadcast(intent); return; } // Show or hide the system navigation bar on Bliss-x86 + if(!isBlissOs(context)) return; + try { if(getCurrentApiVersion() >= 28.0f) Settings.Secure.putInt(context.getContentResolver(), "navigation_bar_visible", show ? 1 : 0); @@ -1399,7 +1507,8 @@ public class U { public static boolean shouldCollapse(Context context, boolean pendingAppLaunch) { SharedPreferences pref = getSharedPreferences(context); if(pref.getBoolean("hide_taskbar", true)) { - if(isOverridingFreeformHack(context)) + if(!pref.getBoolean("freeform_hack", false) + || isOverridingFreeformHack(context, false)) return !LauncherHelper.getInstance().isOnHomeScreen(); else { FreeformHackHelper helper = FreeformHackHelper.getInstance(); @@ -1413,8 +1522,12 @@ public class U { } public static boolean isOverridingFreeformHack(Context context) { + return isOverridingFreeformHack(context, true); + } + + public static boolean isOverridingFreeformHack(Context context, boolean checkPref) { SharedPreferences pref = getSharedPreferences(context); - return pref.getBoolean("freeform_hack", false) + return (!checkPref || pref.getBoolean("freeform_hack", false)) && ((isChromeOs(context) && pref.getBoolean("chrome_os_context_menu_fix", true)) || (!isChromeOs(context) && getCurrentApiVersion() >= 28.0f)); } @@ -1428,7 +1541,7 @@ public class U { } } - private static float getCurrentApiVersion() { + public static float getCurrentApiVersion() { if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) return Float.valueOf(Build.VERSION.SDK_INT + "." + Build.VERSION.PREVIEW_SDK_INT); else @@ -1443,12 +1556,16 @@ public class U { } public static String getSecondScreenPackageName(Context context) { - return getInstalledPackage(context, Arrays.asList( + return getInstalledPackage(context, "com.farmerbb.secondscreen.free", - "com.farmerbb.secondscreen")); + "com.farmerbb.secondscreen"); } // Returns the name of an installed package from a list of package names, in order of preference + private static String getInstalledPackage(Context context, String... packageNames) { + return getInstalledPackage(context, Arrays.asList(packageNames)); + } + private static String getInstalledPackage(Context context, List packageNames) { if(packageNames == null || packageNames.isEmpty()) return null; @@ -1489,20 +1606,11 @@ public class U { int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, applicationInfo.uid, applicationInfo.packageName); if(mode != AppOpsManager.MODE_ALLOWED) { - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.tb_pref_header_recent_apps) - .setMessage(R.string.tb_enable_recent_apps) - .setPositiveButton(R.string.tb_action_ok, (dialog, which) -> { - try { - context.startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)); - showToastLong(context, R.string.tb_usage_stats_message); - - finalOnFinish.run(); - } catch (ActivityNotFoundException e) { - finalOnError.run(); - } - }) - .setNegativeButton(R.string.tb_action_cancel, (dialog, which) -> finalOnFinish.run()); + AlertDialog.Builder builder; + if(hasAndroidTVSettings(context)) + builder = buildRecentAppsDialogAndroidTV(context, finalOnError, finalOnFinish); + else + builder = buildRecentAppsDialogStandard(context, finalOnError, finalOnFinish); AlertDialog dialog = builder.create(); dialog.show(); @@ -1517,6 +1625,38 @@ public class U { return null; } + private static AlertDialog.Builder buildRecentAppsDialogStandard(Context context, Runnable onError, Runnable onFinish) { + return new AlertDialog.Builder(context) + .setTitle(R.string.tb_pref_header_recent_apps) + .setMessage(R.string.tb_enable_recent_apps) + .setPositiveButton(R.string.tb_action_ok, (dialog, which) -> { + try { + context.startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)); + showToastLong(context, R.string.tb_usage_stats_message); + + onFinish.run(); + } catch (ActivityNotFoundException e) { + onError.run(); + } + }) + .setNegativeButton(R.string.tb_action_cancel, (dialog, which) -> onFinish.run()); + } + + private static AlertDialog.Builder buildRecentAppsDialogAndroidTV(Context context, Runnable onError, Runnable onFinish) { + return new AlertDialog.Builder(context) + .setTitle(R.string.tb_pref_header_recent_apps) + .setMessage(R.string.tb_enable_recent_apps_alt) + .setPositiveButton(R.string.tb_action_open_settings, (dialog, which) -> { + try { + context.startActivity(new Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS)); + onFinish.run(); + } catch (ActivityNotFoundException e) { + onError.run(); + } + }) + .setNegativeButton(R.string.tb_action_cancel, (dialog, which) -> onFinish.run()); + } + public static Context wrapContext(Context context) { SharedPreferences pref = getSharedPreferences(context); @@ -1553,13 +1693,15 @@ public class U { } public static boolean isExternalAccessDisabled(Context context) { + if(isLibrary(context)) return true; + SharedPreferences pref = getSharedPreferences(context); return !pref.getBoolean("tasker_enabled", true); } public static boolean enableFreeformModeShortcut(Context context) { return canEnableFreeform() - && !isOverridingFreeformHack(context) + && !isOverridingFreeformHack(context, false) && !isChromeOs(context); } @@ -1642,7 +1784,7 @@ public class U { } public static boolean isDesktopIconsEnabled(Context context) { - return !canBootToFreeform(context) && !shouldLaunchTouchAbsorber(context); + return !canBootToFreeform(context, false) && !shouldLaunchTouchAbsorber(context); } public static boolean isSystemTrayEnabled(Context context) { @@ -1667,4 +1809,127 @@ public class U { 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); + } }