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;
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;
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);
showPermissionDialog(context, null, null);
}
- @TargetApi(Build.VERSION_CODES.M)
public static AlertDialog showPermissionDialog(Context context, Runnable onError, Runnable onFinish) {
Runnable finalOnFinish = onFinish == null
? () -> {}
? () -> 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) {
}
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);
}
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(),
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 {
null,
false,
false,
+ false,
shortcut,
- view);
+ view,
+ null);
}
public static void launchApp(final Context context,
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();
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);
}
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, false)) {
FreeformHackHelper helper = FreeformHackHelper.getInstance();
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()));
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);
+ }
}
- 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 getActivityOptionsBundle(context, type, view,
);
}
- 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
- | IllegalStateException | SecurityException e) { /* Gracefully fail */ }
+ | 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
- | IllegalStateException | SecurityException e) { /* Gracefully fail */ }
+ | 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)) {
}
public static boolean canBootToFreeform(Context context) {
- return hasFreeformSupport(context) && !isOverridingFreeformHack(context);
+ return canBootToFreeform(context, true);
+ }
+
+ private static boolean canBootToFreeform(Context context, boolean checkPref) {
+ return hasFreeformSupport(context) && !isOverridingFreeformHack(context, checkPref);
}
public static boolean isSamsungDevice() {
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());
else
stackId = getFullscreenWindowModeId();
break;
- case GAME:
+ case APP_FULLSCREEN:
stackId = getFullscreenWindowModeId();
break;
case FREEFORM_HACK:
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":
@SuppressLint("SwitchIntDef")
private static ApplicationType getApplicationType(Context context, AppEntry entry) {
if(isGame(context, entry.getPackageName()))
- return ApplicationType.GAME;
+ return ApplicationType.APP_FULLSCREEN;
try {
ActivityInfo info = context.getPackageManager().getActivityInfo(
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 ApplicationType.APP_PORTRAIT;
+ return context.getPackageName().equals(BuildConfig.ANDROIDX86_APPLICATION_ID)
+ ? ApplicationType.APP_LANDSCAPE
+ : ApplicationType.APP_PORTRAIT;
}
public static boolean isSystemApp(Context context) {
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) {
startTaskbarService(context, false);
}
- LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.RESTART"));
+ sendBroadcast(context, TaskbarIntent.ACTION_RESTART);
}
public static void restartNotificationService(Context context) {
}
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);
public static boolean shouldCollapse(Context context, boolean pendingAppLaunch) {
SharedPreferences pref = getSharedPreferences(context);
if(pref.getBoolean("hide_taskbar", true)) {
- if(!pref.getBoolean("freeform_hack", false))
- return true;
- else if(isOverridingFreeformHack(context, false))
+ if(!pref.getBoolean("freeform_hack", false)
+ || isOverridingFreeformHack(context, false))
return !LauncherHelper.getInstance().isOnHomeScreen();
else {
FreeformHackHelper helper = FreeformHackHelper.getInstance();
}
}
- 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
}
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<String> packageNames) {
if(packageNames == null || packageNames.isEmpty())
return null;
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();
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);
}
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);
}
}
public static boolean isDesktopIconsEnabled(Context context) {
- return !canBootToFreeform(context) && !shouldLaunchTouchAbsorber(context);
+ return !canBootToFreeform(context, false) && !shouldLaunchTouchAbsorber(context);
}
public static boolean isSystemTrayEnabled(Context context) {
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);
+ }
}