+ SharedPreferences pref = getSharedPreferences(context);
+ return pref.getBoolean("freeform_hack", false)
+ && ((isChromeOs(context) && pref.getBoolean("chrome_os_context_menu_fix", true))
+ || (!isChromeOs(context) && getCurrentApiVersion() >= 28.0f));
+ }
+
+ public static boolean isPlayStoreInstalled(Context context) {
+ try {
+ context.getPackageManager().getPackageInfo("com.android.vending", 0);
+ return true;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ private 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
+ return (float) Build.VERSION.SDK_INT;
+ }
+
+ public static boolean hasBrokenSetLaunchBoundsApi() {
+ return getCurrentApiVersion() >= 26.0f
+ && getCurrentApiVersion() < 28.0f
+ && !isSamsungDevice()
+ && !isNvidiaDevice();
+ }
+
+ public static String getSecondScreenPackageName(Context context) {
+ return getInstalledPackage(context, Arrays.asList(
+ "com.farmerbb.secondscreen.free",
+ "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, List<String> packageNames) {
+ if(packageNames == null || packageNames.isEmpty())
+ return null;
+
+ List<String> packages = packageNames instanceof ArrayList ? packageNames : new ArrayList<>(packageNames);
+ String packageName = packages.get(0);
+
+ try {
+ context.getPackageManager().getPackageInfo(packageName, 0);
+ return packageName;
+ } catch (PackageManager.NameNotFoundException e) {
+ packages.remove(0);
+ return getInstalledPackage(context, packages);
+ }
+ }
+
+ public static boolean visualFeedbackEnabled(Context context) {
+ SharedPreferences pref = getSharedPreferences(context);
+ return (getCurrentApiVersion() < 26.0f || getCurrentApiVersion() >= 28.0f)
+ && pref.getBoolean("visual_feedback", true);
+ }
+
+ public static void showRecentAppsDialog(Context context) {
+ showRecentAppsDialog(context, null, null);
+ }
+
+ public static AlertDialog showRecentAppsDialog(Context context, Runnable onError, Runnable onFinish) {
+ Runnable finalOnFinish = onFinish == null
+ ? () -> {}
+ : onFinish;
+
+ Runnable finalOnError = onError == null
+ ? () -> showErrorDialog(context, "GET_USAGE_STATS", finalOnFinish)
+ : onError;
+
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !isSystemApp(context)) {
+ ApplicationInfo applicationInfo = null;
+ try {
+ applicationInfo = context.getPackageManager().getApplicationInfo(BuildConfig.APPLICATION_ID, 0);
+ } catch (PackageManager.NameNotFoundException e) { /* Gracefully fail */ }
+
+ if(applicationInfo != null) {
+ AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ 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.pref_header_recent_apps)
+ .setMessage(R.string.enable_recent_apps)
+ .setPositiveButton(R.string.action_ok, (dialog, which) -> {
+ try {
+ context.startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));
+ showToastLong(context, R.string.usage_stats_message);
+
+ finalOnFinish.run();
+ } catch (ActivityNotFoundException e) {
+ finalOnError.run();
+ }
+ })
+ .setNegativeButton(R.string.action_cancel, (dialog, which) -> finalOnFinish.run());
+
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ dialog.setCancelable(false);
+
+ return dialog;
+ }
+ }
+ }
+
+ finalOnFinish.run();
+ return null;
+ }
+
+ public static Context wrapContext(Context context) {
+ SharedPreferences pref = getSharedPreferences(context);
+
+ int theme = -1;
+ switch(pref.getString("theme", "light")) {
+ case "light":
+ theme = R.style.AppTheme;
+ break;
+ case "dark":
+ theme = R.style.AppTheme_Dark;
+ break;
+ }
+
+ return theme > -1 ? new ContextThemeWrapper(context, theme) : context;