package com.farmerbb.taskbar.util;
+import android.Manifest;
+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.app.admin.DevicePolicyManager;
import android.content.ActivityNotFoundException;
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
+import android.content.pm.Signature;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.Rect;
import android.os.UserManager;
import android.provider.Settings;
import android.support.v4.content.LocalBroadcastManager;
+import android.support.v7.view.ContextThemeWrapper;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.Surface;
-import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;
import com.farmerbb.taskbar.BuildConfig;
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.ShortcutActivity;
import com.farmerbb.taskbar.activity.StartTaskbarActivity;
+import com.farmerbb.taskbar.activity.TouchAbsorberActivity;
+import com.farmerbb.taskbar.activity.dark.ContextMenuActivityDark;
import com.farmerbb.taskbar.receiver.LockDeviceReceiver;
import com.farmerbb.taskbar.service.DashboardService;
import com.farmerbb.taskbar.service.NotificationService;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
public class U {
private U() {}
- private static SharedPreferences pref;
private static Integer cachedRotation;
private static final int MAXIMIZED = 0;
private static final int FULLSCREEN_WORKSPACE_STACK_ID = 1;
private static final int FREEFORM_WORKSPACE_STACK_ID = 2;
+ // From android.app.WindowConfiguration
+ private static final int WINDOWING_MODE_FULLSCREEN = 1;
+ private static final int WINDOWING_MODE_FREEFORM = 5;
+
public static SharedPreferences getSharedPreferences(Context context) {
- if(pref == null) pref = context.getSharedPreferences(BuildConfig.APPLICATION_ID + "_preferences", Context.MODE_PRIVATE);
- return pref;
+ return context.getSharedPreferences(BuildConfig.APPLICATION_ID + "_preferences", Context.MODE_PRIVATE);
+ }
+
+ public static void showPermissionDialog(Context context) {
+ showPermissionDialog(context, null, null);
}
@TargetApi(Build.VERSION_CODES.M)
- public static AlertDialog showPermissionDialog(final Context context) {
+ public static AlertDialog showPermissionDialog(Context context, Runnable onError, Runnable onFinish) {
+ Runnable finalOnFinish = onFinish == null
+ ? () -> {}
+ : onFinish;
+
+ Runnable finalOnError = onError == null
+ ? () -> showErrorDialog(context, "SYSTEM_ALERT_WINDOW", finalOnFinish)
+ : onError;
+
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.permission_dialog_title)
.setMessage(R.string.permission_dialog_message)
try {
context.startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + BuildConfig.APPLICATION_ID)));
+
+ finalOnFinish.run();
} catch (ActivityNotFoundException e) {
- showErrorDialog(context, "SYSTEM_ALERT_WINDOW");
+ finalOnError.run();
}
});
return dialog;
}
- public static void showErrorDialog(final Context context, String appopCmd) {
+ public static AlertDialog showErrorDialog(Context context, String appopCmd) {
+ return showErrorDialog(context, appopCmd, null);
+ }
+
+ private static AlertDialog showErrorDialog(Context context, String appopCmd, Runnable onFinish) {
+ Runnable finalOnFinish = onFinish == null
+ ? () -> {}
+ : onFinish;
+
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.error_dialog_title)
.setMessage(context.getString(R.string.error_dialog_message, BuildConfig.APPLICATION_ID, appopCmd))
- .setPositiveButton(R.string.action_ok, null);
+ .setPositiveButton(R.string.action_ok, (dialog, which) -> finalOnFinish.run());
AlertDialog dialog = builder.create();
dialog.show();
+ dialog.setCancelable(false);
+
+ return dialog;
}
public static void lockDevice(Context context) {
launchApp(context, () -> {
Intent intent = new Intent(context, DummyActivity.class);
intent.putExtra("device_admin", true);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- context.startActivity(intent, getActivityOptionsBundle(ApplicationType.APPLICATION));
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION);
- if(context instanceof Activity)
- ((Activity) context).overridePendingTransition(0, 0);
+ try {
+ context.startActivity(intent, getActivityOptionsBundle(context, ApplicationType.APPLICATION));
+ } catch (IllegalArgumentException | SecurityException e) { /* Gracefully fail */ }
});
}
}
public static void sendAccessibilityAction(Context context, int action) {
+ sendAccessibilityAction(context, action, null);
+ }
+
+ 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);
- if(isAccessibilityServiceEnabled(context)) {
+ boolean isAccessibilityServiceEnabled = isAccessibilityServiceEnabled(context);
+
+ if(!isAccessibilityServiceEnabled
+ && hasWriteSecureSettingsPermission(context)) {
+ String notificationServices = Settings.Secure.getString(context.getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+
+ String powerMenuService = new ComponentName(context, PowerMenuService.class).flattenToString();
+
+ if(!notificationServices.contains(powerMenuService)) {
+ try {
+ Settings.Secure.putString(context.getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ notificationServices.isEmpty()
+ ? powerMenuService
+ : notificationServices + ":" + powerMenuService);
+ } catch (Exception e) { /* Gracefully fail */ }
+ }
+
+ new Handler().postDelayed(() -> {
+ Intent intent = new Intent("com.farmerbb.taskbar.ACCESSIBILITY_ACTION");
+ intent.putExtra("action", action);
+ LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
+
+ try {
+ Settings.Secure.putString(context.getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ notificationServices);
+ } catch (Exception e) { /* Gracefully fail */ }
+
+ if(onComplete != null) onComplete.run();
+ }, 100);
+ } else if(isAccessibilityServiceEnabled) {
Intent intent = new Intent("com.farmerbb.taskbar.ACCESSIBILITY_ACTION");
intent.putExtra("action", action);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
+
+ if(onComplete != null) onComplete.run();
} else {
launchApp(context, () -> {
Intent intent = new Intent(context, DummyActivity.class);
intent.putExtra("accessibility", true);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- context.startActivity(intent, getActivityOptionsBundle(ApplicationType.APPLICATION));
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION);
- if(context instanceof Activity)
- ((Activity) context).overridePendingTransition(0, 0);
+ try {
+ context.startActivity(intent, getActivityOptionsBundle(context, ApplicationType.APPLICATION));
+ } catch (IllegalArgumentException | SecurityException e) { /* Gracefully fail */ }
});
}
}
- private static boolean isAccessibilityServiceEnabled(Context context) {
+ public static boolean isAccessibilityServiceEnabled(Context context) {
String accessibilityServices = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
ComponentName component = new ComponentName(context, PowerMenuService.class);
|| accessibilityServices.contains(component.flattenToShortString()));
}
+ public static boolean hasWriteSecureSettingsPermission(Context context) {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+ && context.checkSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS) == PackageManager.PERMISSION_GRANTED;
+ }
+
public static void showToast(Context context, int message) {
showToast(context, context.getString(message), Toast.LENGTH_SHORT);
}
}
private static void launchApp(final Context context,
- final String packageName,
- final String componentName,
- final long userId, final String windowSize,
- final boolean launchedFromTaskbar,
- final boolean openInNewWindow,
- final ShortcutInfo shortcut) {
+ final String packageName,
+ final String componentName,
+ final long userId, final String windowSize,
+ final boolean launchedFromTaskbar,
+ final boolean openInNewWindow,
+ final ShortcutInfo shortcut) {
launchApp(context, launchedFromTaskbar, () -> continueLaunchingApp(context, packageName, componentName, userId,
- windowSize, launchedFromTaskbar, openInNewWindow, shortcut));
+ windowSize, openInNewWindow, shortcut));
}
public static void launchApp(Context context, Runnable runnable) {
SharedPreferences pref = getSharedPreferences(context);
FreeformHackHelper helper = FreeformHackHelper.getInstance();
- boolean specialLaunch = Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1
- && FreeformHackHelper.getInstance().isInFreeformWorkspace()
+ boolean specialLaunch = hasBrokenSetLaunchBoundsApi()
+ && helper.isInFreeformWorkspace()
&& MenuHelper.getInstance().isContextMenuOpen();
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
+ boolean noAnimation = pref.getBoolean("disable_animations", false);
+
+ if(hasFreeformSupport(context)
&& pref.getBoolean("freeform_hack", false)
&& (!helper.isInFreeformWorkspace() || specialLaunch)) {
new Handler().postDelayed(() -> {
- startFreeformHack(context, true, launchedFromTaskbar);
+ startFreeformHack(context, true);
new Handler().postDelayed(runnable, helper.isFreeformHackActive() ? 0 : 100);
}, launchedFromTaskbar ? 0 : 100);
} else
- runnable.run();
+ new Handler().postDelayed(runnable, !launchedFromTaskbar && noAnimation ? 100 : 0);
+ }
+
+ public static void startFreeformHack(Context context) {
+ startFreeformHack(context, false);
}
- @SuppressWarnings("deprecation")
@TargetApi(Build.VERSION_CODES.N)
- public static void startFreeformHack(Context context, boolean checkMultiWindow, boolean launchedFromTaskbar) {
+ public static void startFreeformHack(Context context, boolean checkMultiWindow) {
Intent freeformHackIntent = new Intent(context, InvisibleActivityFreeform.class);
- freeformHackIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
+ freeformHackIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT
+ | Intent.FLAG_ACTIVITY_NO_ANIMATION);
if(checkMultiWindow)
freeformHackIntent.putExtra("check_multiwindow", true);
- if(launchedFromTaskbar) {
- SharedPreferences pref = getSharedPreferences(context);
- if(pref.getBoolean("disable_animations", false))
- freeformHackIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
- }
-
if(canDrawOverlays(context))
- launchAppLowerRight(context, freeformHackIntent);
+ startActivityLowerRight(context, freeformHackIntent);
+ }
+
+ public static void stopFreeformHack(Context context) {
+ LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.FINISH_FREEFORM_ACTIVITY"));
+
+ if(isOverridingFreeformHack(context)) {
+ FreeformHackHelper helper = FreeformHackHelper.getInstance();
+ helper.setFreeformHackActive(false);
+ helper.setInFreeformWorkspace(false);
+ }
}
@TargetApi(Build.VERSION_CODES.N)
String componentName,
long userId,
String windowSize,
- boolean launchedFromTaskbar,
boolean openInNewWindow,
ShortcutInfo shortcut) {
SharedPreferences pref = getSharedPreferences(context);
&& Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1)
intent.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME);
- if(launchedFromTaskbar) {
- if(pref.getBoolean("disable_animations", false))
- intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
- }
+ if(pref.getBoolean("disable_animations", false))
+ intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
if(openInNewWindow || pref.getBoolean("force_new_window", false)) {
intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
if(windowSize == null)
windowSize = SavedWindowSizes.getInstance(context).getWindowSize(context, packageName);
- if(Build.VERSION.SDK_INT < Build.VERSION_CODES.N
- || !pref.getBoolean("freeform_hack", false)
- || windowSize.equals("standard")) {
- launchStandard(context, intent, userId, shortcut, type);
- } else switch(windowSize) {
- case "large":
- launchMode1(context, intent, userId, shortcut, type);
- break;
- case "fullscreen":
- launchMode2(context, intent, MAXIMIZED, userId, shortcut, type);
- break;
- case "half_left":
- launchMode2(context, intent, LEFT, userId, shortcut, type);
- break;
- case "half_right":
- launchMode2(context, intent, RIGHT, userId, shortcut, type);
- break;
- case "phone_size":
- launchMode3(context, intent, userId, shortcut, type);
- break;
- }
+ Bundle bundle = getActivityOptionsBundle(context, type, windowSize);
+
+ prepareToStartActivity(context, () -> {
+ if(shortcut == null) {
+ UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
+ try {
+ context.startActivity(intent, bundle);
+ } catch (ActivityNotFoundException e) {
+ launchAndroidForWork(context, intent.getComponent(), bundle, userId);
+ } catch (IllegalArgumentException | SecurityException e) { /* Gracefully fail */ }
+ } else
+ launchAndroidForWork(context, intent.getComponent(), bundle, userId);
+ } else
+ launchShortcut(context, shortcut, bundle);
+ });
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"));
}
-
- private static void launchStandard(Context context, Intent intent, long userId, ShortcutInfo shortcut, ApplicationType type) {
- Bundle bundle = Build.VERSION.SDK_INT < Build.VERSION_CODES.N ? null : getActivityOptions(type).toBundle();
- if(shortcut == null) {
- UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
- if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
- try {
- context.startActivity(intent, bundle);
- } catch (ActivityNotFoundException e) {
- launchAndroidForWork(context, intent.getComponent(), bundle, userId);
- } catch (IllegalArgumentException | SecurityException e) { /* Gracefully fail */ }
- } else
- launchAndroidForWork(context, intent.getComponent(), bundle, userId);
- } else
- launchShortcut(context, shortcut, bundle);
- }
@SuppressWarnings("deprecation")
@TargetApi(Build.VERSION_CODES.N)
- private static void launchMode1(Context context, Intent intent, long userId, ShortcutInfo shortcut, ApplicationType type) {
- DisplayMetrics metrics = getRealDisplayMetrics(context);
+ private static Bundle launchMode1(Context context, ApplicationType type) {
+ DisplayInfo display = getDisplayInfo(context);
- int width1 = metrics.widthPixels / 8;
- int width2 = metrics.widthPixels - width1;
- int height1 = metrics.heightPixels / 8;
- int height2 = metrics.heightPixels - height1;
+ int width1 = display.width / 8;
+ int width2 = display.width - width1;
+ int height1 = display.height / 8;
+ int height2 = display.height - height1;
- Bundle bundle = getActivityOptions(type).setLaunchBounds(new Rect(
+ return getActivityOptions(context, type).setLaunchBounds(new Rect(
width1,
height1,
width2,
height2
)).toBundle();
-
- if(shortcut == null) {
- UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
- if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
- try {
- context.startActivity(intent, bundle);
- } catch (ActivityNotFoundException e) {
- launchAndroidForWork(context, intent.getComponent(), bundle, userId);
- } catch (IllegalArgumentException | SecurityException e) { /* Gracefully fail */ }
- } else
- launchAndroidForWork(context, intent.getComponent(), bundle, userId);
- } else
- launchShortcut(context, shortcut, bundle);
}
@SuppressWarnings("deprecation")
@TargetApi(Build.VERSION_CODES.N)
- private static void launchMode2(Context context, Intent intent, int launchType, long userId, ShortcutInfo shortcut, ApplicationType type) {
- DisplayMetrics metrics = getRealDisplayMetrics(context);
-
+ private static Bundle launchMode2(Context context, int launchType, ApplicationType type) {
+ DisplayInfo display = getDisplayInfo(context);
+
int statusBarHeight = getStatusBarHeight(context);
String position = getTaskbarPosition(context);
boolean isPortrait = context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
boolean isLandscape = context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
- int left = launchType == RIGHT && isLandscape
- ? metrics.widthPixels / 2
- : 0;
-
- int top = launchType == RIGHT && isPortrait
- ? metrics.heightPixels / 2
- : statusBarHeight;
+ int left = 0;
+ int top = statusBarHeight;
+ int right = display.width;
+ int bottom = display.height;
- int right = launchType == LEFT && isLandscape
- ? metrics.widthPixels / 2
- : metrics.widthPixels;
-
- int bottom = launchType == LEFT && isPortrait
- ? metrics.heightPixels / 2
- : metrics.heightPixels;
-
- int iconSize = isOverridingFreeformHack(context)
+ int iconSize = isOverridingFreeformHack(context) && !LauncherHelper.getInstance().isOnHomeScreen()
? 0
: context.getResources().getDimensionPixelSize(R.dimen.icon_size);
- if(position.contains("vertical_left")) {
- if(launchType != RIGHT || isPortrait) left = left + iconSize;
- } else if(position.contains("vertical_right")) {
- if(launchType != LEFT || isPortrait) right = right - iconSize;
- } else if(position.contains("bottom")) {
- if(isLandscape || (launchType != LEFT && isPortrait))
- bottom = bottom - iconSize;
- } else if(isLandscape || (launchType != RIGHT && isPortrait))
+ if(position.contains("vertical_left"))
+ left = left + iconSize;
+ else if(position.contains("vertical_right"))
+ right = right - iconSize;
+ else if(position.contains("bottom"))
+ bottom = bottom - iconSize;
+ else
top = top + iconSize;
- Bundle bundle = getActivityOptions(type).setLaunchBounds(new Rect(
- left,
- top,
- right,
- bottom
- )).toBundle();
+ if(launchType == RIGHT && isLandscape)
+ left = (right / 2) + ((iconSize / 2) * (position.contains("vertical_left") ? 1 : 0));
+ else if(launchType == RIGHT && isPortrait)
+ top = (bottom / 2) + ((iconSize / 2)
+ * ((position.equals("top_left") || position.equals("top_right")) ? 1 : 0));
+ else if(launchType == LEFT && isLandscape)
+ right = (right / 2) + ((iconSize / 2) * (position.contains("vertical_left") ? 1 : 0));
+ else if(launchType == LEFT && isPortrait)
+ bottom = (bottom / 2) + ((iconSize / 2)
+ * ((position.equals("top_left") || position.equals("top_right")) ? 1 : 0));
- if(shortcut == null) {
- UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
- if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
- try {
- context.startActivity(intent, bundle);
- } catch (ActivityNotFoundException e) {
- launchAndroidForWork(context, intent.getComponent(), bundle, userId);
- } catch (IllegalArgumentException | SecurityException e) { /* Gracefully fail */ }
- } else
- launchAndroidForWork(context, intent.getComponent(), bundle, userId);
- } else
- launchShortcut(context, shortcut, bundle);
+ return getActivityOptions(context, type)
+ .setLaunchBounds(new Rect(left, top, right, bottom)).toBundle();
}
@SuppressWarnings("deprecation")
@TargetApi(Build.VERSION_CODES.N)
- private static void launchMode3(Context context, Intent intent, long userId, ShortcutInfo shortcut, ApplicationType type) {
- DisplayMetrics metrics = getRealDisplayMetrics(context);
+ private static Bundle launchMode3(Context context, ApplicationType type) {
+ DisplayInfo display = getDisplayInfo(context);
- int width1 = metrics.widthPixels / 2;
+ int width1 = display.width / 2;
int width2 = context.getResources().getDimensionPixelSize(R.dimen.phone_size_width) / 2;
- int height1 = metrics.heightPixels / 2;
+ int height1 = display.height / 2;
int height2 = context.getResources().getDimensionPixelSize(R.dimen.phone_size_height) / 2;
- Bundle bundle = getActivityOptions(type).setLaunchBounds(new Rect(
+ return getActivityOptions(context, type).setLaunchBounds(new Rect(
width1 - width2,
height1 - height2,
width1 + width2,
height1 + height2
)).toBundle();
-
- if(shortcut == null) {
- UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
- if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
- try {
- context.startActivity(intent, bundle);
- } catch (ActivityNotFoundException e) {
- launchAndroidForWork(context, intent.getComponent(), bundle, userId);
- } catch (IllegalArgumentException | SecurityException e) { /* Gracefully fail */ }
- } else
- launchAndroidForWork(context, intent.getComponent(), bundle, userId);
- } else
- launchShortcut(context, shortcut, bundle);
}
private static void launchAndroidForWork(Context context, ComponentName componentName, Bundle bundle, long userId) {
}
}
- public static void launchAppMaximized(Context context, Intent intent) {
- UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
- long userId = userManager.getSerialNumberForUser(Process.myUserHandle());
+ private static void prepareToStartActivity(Context context, Runnable runnable) {
+ boolean shouldLaunchTouchAbsorber =
+ !FreeformHackHelper.getInstance().isTouchAbsorberActive()
+ && isOverridingFreeformHack(context)
+ && !isChromeOs(context);
- launchMode2(context, intent, MAXIMIZED, userId, null, ApplicationType.CONTEXT_MENU);
+ if(!shouldLaunchTouchAbsorber) {
+ runnable.run();
+ return;
+ }
+
+ startTouchAbsorberActivity(context);
+ new Handler().postDelayed(runnable, 100);
+ }
+
+ public static void startActivityMaximized(Context context, Intent intent) {
+ Bundle bundle = launchMode2(context, MAXIMIZED, ApplicationType.CONTEXT_MENU);
+ prepareToStartActivity(context, () -> context.startActivity(intent, bundle));
}
- @SuppressWarnings("deprecation")
@TargetApi(Build.VERSION_CODES.N)
- public static void launchAppLowerRight(Context context, Intent intent) {
- DisplayMetrics metrics = getRealDisplayMetrics(context);
+ public static void startActivityLowerRight(Context context, Intent intent) {
+ DisplayInfo display = getDisplayInfo(context);
try {
- context.startActivity(intent, getActivityOptions(ApplicationType.FREEFORM_HACK).setLaunchBounds(new Rect(
- metrics.widthPixels,
- metrics.heightPixels,
- metrics.widthPixels + 1,
- metrics.heightPixels + 1
- )).toBundle());
+ context.startActivity(intent,
+ getActivityOptions(context, ApplicationType.FREEFORM_HACK)
+ .setLaunchBounds(new Rect(
+ display.width,
+ display.height,
+ display.width + 1,
+ display.height + 1
+ )).toBundle());
} catch (IllegalArgumentException | SecurityException e) { /* Gracefully fail */ }
}
- public static void checkForUpdates(Context context) {
- if(!BuildConfig.APPLICATION_ID.equals(BuildConfig.ANDROIDX86_APPLICATION_ID)) {
- if(!BuildConfig.DEBUG) {
- String url;
- try {
- context.getPackageManager().getPackageInfo("com.android.vending", 0);
- url = "https://play.google.com/store/apps/details?id=" + BuildConfig.APPLICATION_ID;
- } catch (PackageManager.NameNotFoundException e) {
- url = "https://f-droid.org/repository/browse/?fdid=" + BuildConfig.BASE_APPLICATION_ID;
- }
+ @TargetApi(Build.VERSION_CODES.N)
+ public static void startTouchAbsorberActivity(Context context) {
+ String position = getTaskbarPosition(context);
+ DisplayInfo display = getDisplayInfo(context);
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(url));
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ int left = 0;
+ int top = 0;
+ int right = display.width;
+ int bottom = display.height;
- try {
- context.startActivity(intent);
- } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
- } else
- showToast(context, R.string.debug_build);
+ int iconSize = context.getResources().getDimensionPixelSize(R.dimen.icon_size);
+
+ if(position.contains("vertical_left"))
+ right = iconSize;
+ else if(position.contains("vertical_right"))
+ left = right - iconSize;
+ else if(position.contains("bottom"))
+ top = bottom - iconSize;
+ else
+ bottom = iconSize;
+
+ Intent intent = new Intent(context, TouchAbsorberActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
+
+ try {
+ context.startActivity(intent,
+ getActivityOptions(context, ApplicationType.FREEFORM_HACK)
+ .setLaunchBounds(new Rect(left, top, right, bottom)).toBundle());
+ } catch (IllegalArgumentException | SecurityException e) { /* Gracefully fail */ }
+ }
+
+ public static void startContextMenuActivity(Context context, Bundle args) {
+ SharedPreferences pref = getSharedPreferences(context);
+ Intent intent = null;
+
+ switch(pref.getString("theme", "light")) {
+ case "light":
+ intent = new Intent(context, ContextMenuActivity.class);
+ break;
+ case "dark":
+ intent = new Intent(context, ContextMenuActivityDark.class);
+ break;
}
+
+ if(intent != null) {
+ intent.putExtra("args", args);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ }
+
+ if(hasFreeformSupport(context) && FreeformHackHelper.getInstance().isInFreeformWorkspace()) {
+ DisplayInfo display = getDisplayInfo(context);
+
+ if(intent != null && hasBrokenSetLaunchBoundsApi())
+ intent.putExtra("context_menu_fix", true);
+
+ context.startActivity(intent,
+ getActivityOptions(context, ApplicationType.CONTEXT_MENU)
+ .setLaunchBounds(
+ new Rect(0, 0, display.width, display.height)
+ ).toBundle());
+ } else
+ context.startActivity(intent);
+ }
+
+ public static void checkForUpdates(Context context) {
+ String url;
+ if(isPlayStoreRelease(context)) {
+ if(BuildConfig.APPLICATION_ID.equals(BuildConfig.BASE_APPLICATION_ID)
+ && !isPlayStoreInstalled(context))
+ url = "https://github.com/farmerbb/Taskbar/releases";
+ else
+ url = "https://play.google.com/store/apps/details?id=" + BuildConfig.APPLICATION_ID;
+ } else
+ url = "https://f-droid.org/repository/browse/?fdid=" + BuildConfig.APPLICATION_ID;
+
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(url));
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ try {
+ context.startActivity(intent);
+ } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
}
public static boolean launcherIsDefault(Context context) {
private static int getMaxNumOfColumns(Context context) {
SharedPreferences pref = getSharedPreferences(context);
- DisplayMetrics metrics = getRealDisplayMetrics(context);
- float baseTaskbarSize = getBaseTaskbarSizeFloat(context) / metrics.density;
+ DisplayInfo display = getDisplayInfo(context);
+ float density = display.density / 160;
+ float baseTaskbarSize = getBaseTaskbarSizeFloat(context) / density;
int numOfColumns = 0;
float maxScreenSize = getTaskbarPosition(context).contains("vertical")
- ? (metrics.heightPixels - getStatusBarHeight(context)) / metrics.density
- : metrics.widthPixels / metrics.density;
+ ? (display.height - getStatusBarHeight(context)) / density
+ : display.width / density;
- float iconSize = context.getResources().getDimension(R.dimen.icon_size) / metrics.density;
+ float iconSize = context.getResources().getDimension(R.dimen.icon_size) / density;
int userMaxNumOfColumns = Integer.valueOf(pref.getString("max_num_of_recents", "10"));
}
public static int getStatusBarHeight(Context context) {
- int statusBarHeight = 0;
- int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
+ return getSystemDimen(context, "status_bar_height");
+ }
+
+ private static int getNavbarHeight(Context context) {
+ return getSystemDimen(context, "navigation_bar_height");
+ }
+
+ private static int getSystemDimen(Context context, String id) {
+ int value = 0;
+ int resourceId = context.getResources().getIdentifier(id, "dimen", "android");
if(resourceId > 0)
- statusBarHeight = context.getResources().getDimensionPixelSize(resourceId);
+ value = context.getResources().getDimensionPixelSize(resourceId);
- return statusBarHeight;
+ return value;
}
public static void refreshPinnedIcons(Context context) {
return intent;
}
+ public static boolean canEnableFreeform() {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
+ }
+
+ @TargetApi(Build.VERSION_CODES.N)
public static boolean hasFreeformSupport(Context context) {
- return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
+ return canEnableFreeform()
&& (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT)
- || Settings.Global.getInt(context.getContentResolver(), "enable_freeform_support", -1) == 1
+ || Settings.Global.getInt(context.getContentResolver(), "enable_freeform_support", 0) != 0
|| (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1
- && Settings.Global.getInt(context.getContentResolver(), "force_resizable_activities", -1) == 1));
+ && Settings.Global.getInt(context.getContentResolver(), "force_resizable_activities", 0) != 0));
}
- public static boolean hasPartialFreeformSupport() {
- return Build.MANUFACTURER.equalsIgnoreCase("Samsung");
+ public static boolean isSamsungDevice() {
+ return Build.MANUFACTURER.equalsIgnoreCase("Samsung");
+ }
+
+ public static boolean isNvidiaDevice() {
+ return Build.MANUFACTURER.equalsIgnoreCase("NVIDIA");
}
public static boolean isServiceRunning(Context context, Class<? extends Service> cls) {
return isServiceRunning(context, cls.getName());
}
- public static boolean isServiceRunning(Context context, String className) {
+ private static boolean isServiceRunning(Context context, String className) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for(ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if(className.equals(service.service.getClassName()))
}
@TargetApi(Build.VERSION_CODES.N)
- public static ActivityOptions getActivityOptions(ApplicationType applicationType) {
+ public static ActivityOptions getActivityOptions(Context context, ApplicationType applicationType) {
ActivityOptions options = ActivityOptions.makeBasic();
int stackId = -1;
switch(applicationType) {
case APPLICATION:
if(FreeformHackHelper.getInstance().isFreeformHackActive())
- stackId = FREEFORM_WORKSPACE_STACK_ID;
+ stackId = getFreeformWindowModeId();
else
- stackId = FULLSCREEN_WORKSPACE_STACK_ID;
+ stackId = getFullscreenWindowModeId();
break;
case GAME:
- stackId = FULLSCREEN_WORKSPACE_STACK_ID;
+ stackId = getFullscreenWindowModeId();
break;
case FREEFORM_HACK:
- stackId = FREEFORM_WORKSPACE_STACK_ID;
+ stackId = getFreeformWindowModeId();
break;
case CONTEXT_MENU:
- if(Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1)
- stackId = FULLSCREEN_WORKSPACE_STACK_ID;
+ if(hasBrokenSetLaunchBoundsApi()
+ || (!isChromeOs(context) && getCurrentApiVersion() >= 28.0f))
+ stackId = getFullscreenWindowModeId();
break;
}
try {
- Method method = ActivityOptions.class.getMethod("setLaunchStackId", int.class);
+ Method method = ActivityOptions.class.getMethod(getWindowingModeMethodName(), int.class);
method.invoke(options, stackId);
} catch (Exception e) { /* Gracefully fail */ }
return options;
}
- public static Bundle getActivityOptionsBundle(ApplicationType applicationType) {
- if(Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
- return null;
+ private static int getFullscreenWindowModeId() {
+ if(getCurrentApiVersion() >= 28.0f)
+ return WINDOWING_MODE_FULLSCREEN;
+ else
+ return FULLSCREEN_WORKSPACE_STACK_ID;
+ }
+
+ private static int getFreeformWindowModeId() {
+ if(getCurrentApiVersion() >= 28.0f)
+ return WINDOWING_MODE_FREEFORM;
+ else
+ return FREEFORM_WORKSPACE_STACK_ID;
+ }
+
+ private static String getWindowingModeMethodName() {
+ if(getCurrentApiVersion() >= 28.0f)
+ return "setLaunchWindowingMode";
else
- return getActivityOptions(applicationType).toBundle();
+ return "setLaunchStackId";
+ }
+
+ public static Bundle getActivityOptionsBundle(Context context, ApplicationType type) {
+ SharedPreferences pref = getSharedPreferences(context);
+
+ return getActivityOptionsBundle(context, type, pref.getString("window_size", "standard"));
+ }
+
+ private static Bundle getActivityOptionsBundle(Context context, ApplicationType type, String windowSize) {
+ SharedPreferences pref = getSharedPreferences(context);
+ if(!canEnableFreeform() || !pref.getBoolean("freeform_hack", false))
+ return null;
+
+ switch(windowSize) {
+ case "large":
+ return launchMode1(context, type);
+ case "fullscreen":
+ return launchMode2(context, MAXIMIZED, type);
+ case "half_left":
+ return launchMode2(context, LEFT, type);
+ case "half_right":
+ return launchMode2(context, RIGHT, type);
+ case "phone_size":
+ return launchMode3(context, type);
+ }
+
+ return getActivityOptions(context, type).toBundle();
}
private static ApplicationType getApplicationType(Context context, String packageName) {
return context.getPackageManager().hasSystemFeature("org.chromium.arc");
}
- public static boolean hasSupportLibrary(Context context) {
+ public static boolean isBlissOs(Context context) {
+ boolean validBlissOsBuildProp = false;
+
+ String blissVersion = DependencyUtils.getSystemProperty("ro.bliss.version");
+ if(blissVersion != null && !blissVersion.isEmpty())
+ validBlissOsBuildProp = true;
+
+ String buildUser = DependencyUtils.getSystemProperty("ro.build.user");
+ if(buildUser != null && buildUser.equals("electrikjesus"))
+ validBlissOsBuildProp = true;
+
+ return validBlissOsBuildProp
+ && BuildConfig.APPLICATION_ID.equals(BuildConfig.BASE_APPLICATION_ID)
+ && isSystemApp(context);
+ }
+
+ public static boolean isLauncherPermanentlyEnabled(Context context) {
+ if(BuildConfig.APPLICATION_ID.equals(BuildConfig.ANDROIDX86_APPLICATION_ID))
+ return true;
+
PackageManager pm = context.getPackageManager();
try {
pm.getPackageInfo(BuildConfig.SUPPORT_APPLICATION_ID, 0);
public static void initPrefs(Context context) {
// On smaller-screened devices, set "Grid" as the default start menu layout
SharedPreferences pref = getSharedPreferences(context);
- if(context.getApplicationContext().getResources().getConfiguration().smallestScreenWidthDp < 600
+ if(context.getApplicationContext().getResources().getConfiguration().smallestScreenWidthDp < 720
&& pref.getString("start_menu_layout", "null").equals("null")) {
pref.edit().putString("start_menu_layout", "grid").apply();
}
// Enable freeform hack automatically on supported devices
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ if(canEnableFreeform()) {
if(!pref.getBoolean("freeform_hack_override", false)) {
pref.edit()
- .putBoolean("freeform_hack", hasFreeformSupport(context) && !hasPartialFreeformSupport())
+ .putBoolean("freeform_hack", hasFreeformSupport(context) && !isSamsungDevice())
.putBoolean("save_window_sizes", false)
.putBoolean("freeform_hack_override", true)
.apply();
} else if(!hasFreeformSupport(context)) {
pref.edit().putBoolean("freeform_hack", false).apply();
- LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.FINISH_FREEFORM_ACTIVITY"));
+ stopFreeformHack(context);
}
+ } else {
+ boolean freeformWasEnabled = pref.getBoolean("freeform_hack", false)
+ || pref.getBoolean("show_freeform_disabled_message", false);
+
+ pref.edit()
+ .putBoolean("freeform_hack", false)
+ .putBoolean("show_freeform_disabled_message", freeformWasEnabled)
+ .apply();
+
+ SavedWindowSizes.getInstance(context).clear(context);
+ stopFreeformHack(context);
+ }
+
+ // Customizations for BlissOS
+ if(isBlissOs(context) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+ && !pref.getBoolean("bliss_os_prefs", false)) {
+ SharedPreferences.Editor editor = pref.edit();
+
+ if(hasFreeformSupport(context)) {
+ editor.putBoolean("freeform_hack", true);
+ }
+
+ editor.putString("recents_amount", "running_apps_only");
+ editor.putString("refresh_frequency", "0");
+ editor.putString("max_num_of_recents", "2147483647");
+ editor.putString("sort_order", "true");
+ editor.putString("window_size", "phone_size");
+ editor.putBoolean("full_length", true);
+ editor.putBoolean("dashboard", true);
+ editor.putBoolean("app_drawer_icon", true);
+ editor.putBoolean("button_back", true);
+ editor.putBoolean("button_home", true);
+ editor.putBoolean("button_recents", true);
+ editor.putBoolean("auto_hide_navbar", true);
+ editor.putBoolean("bliss_os_prefs", true);
+ editor.apply();
}
// Customizations for Android-x86 devices (non-Bliss)
.putString("refresh_frequency", "0")
.putString("max_num_of_recents", "2147483647")
.putString("sort_order", "true")
+ .putString("window_size", "phone_size")
.putBoolean("full_length", true)
.putBoolean("dashboard", true)
.putBoolean("android_x86_prefs", true)
}
}
- public static DisplayMetrics getRealDisplayMetrics(Context context) {
- DisplayMetrics metrics = new DisplayMetrics();
+ public static DisplayInfo getDisplayInfo(Context context) {
+ context = context.getApplicationContext();
+
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display disp = wm.getDefaultDisplay();
- SharedPreferences pref = getSharedPreferences(context);
- if(isChromeOs(context) && !pref.getBoolean("chrome_os_context_menu_fix", true))
- disp.getRealMetrics(metrics);
- else
- disp.getMetrics(metrics);
+ DisplayMetrics metrics = new DisplayMetrics();
+ disp.getMetrics(metrics);
+
+ DisplayMetrics realMetrics = new DisplayMetrics();
+ disp.getRealMetrics(realMetrics);
- return metrics;
+ DisplayInfo display = new DisplayInfo(metrics.widthPixels, metrics.heightPixels, metrics.densityDpi);
+
+ if(isChromeOs(context)) {
+ SharedPreferences pref = getSharedPreferences(context);
+ if(!pref.getBoolean("chrome_os_context_menu_fix", true)) {
+ display.width = realMetrics.widthPixels;
+ display.height = realMetrics.heightPixels;
+ }
+
+ return display;
+ }
+
+ boolean sameWidth = metrics.widthPixels == realMetrics.widthPixels;
+ boolean sameHeight = metrics.heightPixels == realMetrics.heightPixels;
+
+ if(sameWidth && !sameHeight) {
+ display.width = realMetrics.widthPixels;
+ display.height = realMetrics.heightPixels - getNavbarHeight(context);
+ }
+
+ if(!sameWidth && sameHeight) {
+ display.width = realMetrics.widthPixels - getNavbarHeight(context);
+ display.height = realMetrics.heightPixels;
+ }
+
+ return display;
}
- static void pinAppShortcut(Context context) {
- Intent intent = getShortcutIntent(context);
- intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
- intent.putExtra("duplicate", false);
+ public static void pinAppShortcut(Context context) {
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ ShortcutManager mShortcutManager = context.getSystemService(ShortcutManager.class);
- Intent homeIntent = new Intent(Intent.ACTION_MAIN);
- homeIntent.addCategory(Intent.CATEGORY_HOME);
- ResolveInfo defaultLauncher = context.getPackageManager().resolveActivity(homeIntent, PackageManager.MATCH_DEFAULT_ONLY);
+ if(mShortcutManager.isRequestPinShortcutSupported()) {
+ ShortcutInfo pinShortcutInfo = new ShortcutInfo.Builder(context, "freeform_mode").build();
+
+ mShortcutManager.requestPinShortcut(pinShortcutInfo, null);
+ } else
+ showToastLong(context, R.string.pin_shortcut_not_supported);
+ } else {
+ Intent intent = getShortcutIntent(context);
+ intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
+ intent.putExtra("duplicate", false);
- intent.setPackage(defaultLauncher.activityInfo.packageName);
- context.sendBroadcast(intent);
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+ homeIntent.addCategory(Intent.CATEGORY_HOME);
+ ResolveInfo defaultLauncher = context.getPackageManager().resolveActivity(homeIntent, PackageManager.MATCH_DEFAULT_ONLY);
- showToast(context, R.string.shortcut_created);
+ intent.setPackage(defaultLauncher.activityInfo.packageName);
+ context.sendBroadcast(intent);
+
+ showToast(context, R.string.shortcut_created);
+ }
}
public static boolean shouldCollapse(Context context, boolean pendingAppLaunch) {
SharedPreferences pref = getSharedPreferences(context);
if(pref.getBoolean("hide_taskbar", true)) {
if(isOverridingFreeformHack(context))
- return true;
+ return !LauncherHelper.getInstance().isOnHomeScreen();
else {
FreeformHackHelper helper = FreeformHackHelper.getInstance();
if(pendingAppLaunch)
}
public static boolean isOverridingFreeformHack(Context context) {
- SharedPreferences pref = U.getSharedPreferences(context);
- return isChromeOs(context) && pref.getBoolean("chrome_os_context_menu_fix", true);
- }
-
- @SuppressWarnings("unchecked")
- public static <T extends View> T findViewById(Activity target, int id) {
- return (T) target.findViewById(id);
- }
-
- @SuppressWarnings("unchecked")
- public static <T extends View> T findViewById(View target, int id) {
- return (T) target.findViewById(id);
+ 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) {
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;
+ }
+
+ @SuppressLint("PackageManagerGetSignatures")
+ public static boolean isPlayStoreRelease(Context context) {
+ Signature playStoreSignature = new Signature(context.getString(R.string.signature));
+ try {
+ PackageManager pm = context.getPackageManager();
+ PackageInfo info = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
+ for(Signature signature : info.signatures) {
+ if(signature.equals(playStoreSignature))
+ return true;
+ }
+ } catch (Exception e) { /* Gracefully fail */ }
+
+ return false;
+ }
+
+ public static boolean isExternalAccessDisabled(Context context) {
+ SharedPreferences pref = getSharedPreferences(context);
+ return !pref.getBoolean("tasker_enabled", true);
+ }
+
+ public static boolean enableFreeformModeShortcut(Context context) {
+ return canEnableFreeform()
+ && !U.isOverridingFreeformHack(context)
+ && !U.isChromeOs(context);
+ }
+
+ public static void startForegroundService(Context context, Intent intent) {
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ if(Settings.canDrawOverlays(context))
+ context.startForegroundService(intent);
+ } else
+ context.startService(intent);
+ }
+
+ public static int getOverlayType() {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
+ ? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
+ : WindowManager.LayoutParams.TYPE_PHONE;
+ }
+
+ public static boolean isDelegatingHomeActivity(Context context) {
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+ homeIntent.addCategory(Intent.CATEGORY_HOME);
+
+ final List<ResolveInfo> listOfLaunchers = context.getPackageManager().queryIntentActivities(homeIntent, 0);
+ for(ResolveInfo launcher : listOfLaunchers) {
+ if(launcher.activityInfo.packageName.equals(BuildConfig.SUPPORT_APPLICATION_ID))
+ return true;
+ }
+
+ return false;
+ }
}