1 /* Copyright 2016 Braden Farmer
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 package com.farmerbb.taskbar.util;
18 import android.annotation.TargetApi;
19 import android.app.ActivityManager;
20 import android.app.ActivityOptions;
21 import android.app.AlertDialog;
22 import android.app.Service;
23 import android.app.admin.DevicePolicyManager;
24 import android.content.ActivityNotFoundException;
25 import android.content.ComponentName;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.SharedPreferences;
29 import android.content.pm.ActivityInfo;
30 import android.content.pm.ApplicationInfo;
31 import android.content.pm.LauncherActivityInfo;
32 import android.content.pm.LauncherApps;
33 import android.content.pm.PackageManager;
34 import android.content.pm.ResolveInfo;
35 import android.content.pm.ShortcutInfo;
36 import android.content.res.Configuration;
37 import android.graphics.Rect;
38 import android.graphics.drawable.BitmapDrawable;
39 import android.hardware.display.DisplayManager;
40 import android.net.Uri;
41 import android.os.Build;
42 import android.os.Bundle;
43 import android.os.Handler;
44 import android.os.Process;
45 import android.os.UserHandle;
46 import android.os.UserManager;
47 import android.provider.Settings;
48 import android.support.v4.content.LocalBroadcastManager;
49 import android.util.DisplayMetrics;
50 import android.view.Display;
51 import android.view.Surface;
52 import android.view.WindowManager;
53 import android.widget.Toast;
55 import com.farmerbb.taskbar.BuildConfig;
56 import com.farmerbb.taskbar.R;
57 import com.farmerbb.taskbar.activity.DummyActivity;
58 import com.farmerbb.taskbar.activity.InvisibleActivityFreeform;
59 import com.farmerbb.taskbar.activity.ShortcutActivity;
60 import com.farmerbb.taskbar.activity.StartTaskbarActivity;
61 import com.farmerbb.taskbar.receiver.LockDeviceReceiver;
62 import com.farmerbb.taskbar.service.DashboardService;
63 import com.farmerbb.taskbar.service.NotificationService;
64 import com.farmerbb.taskbar.service.PowerMenuService;
65 import com.farmerbb.taskbar.service.StartMenuService;
66 import com.farmerbb.taskbar.service.TaskbarService;
68 import java.lang.reflect.Method;
69 import java.util.ArrayList;
70 import java.util.List;
72 import moe.banana.support.ToastCompat;
78 private static SharedPreferences pref;
79 private static Integer cachedRotation;
81 private static final int MAXIMIZED = 0;
82 private static final int LEFT = -1;
83 private static final int RIGHT = 1;
85 public static final int HIDDEN = 0;
86 public static final int TOP_APPS = 1;
88 // From android.app.ActivityManager.StackId
89 private static final int FULLSCREEN_WORKSPACE_STACK_ID = 1;
90 private static final int FREEFORM_WORKSPACE_STACK_ID = 2;
92 public static SharedPreferences getSharedPreferences(Context context) {
93 if(pref == null) pref = context.getSharedPreferences(BuildConfig.APPLICATION_ID + "_preferences", Context.MODE_PRIVATE);
97 @TargetApi(Build.VERSION_CODES.M)
98 public static AlertDialog showPermissionDialog(final Context context) {
99 AlertDialog.Builder builder = new AlertDialog.Builder(context);
100 builder.setTitle(R.string.permission_dialog_title)
101 .setMessage(R.string.permission_dialog_message)
102 .setPositiveButton(R.string.action_grant_permission, (dialog, which) -> {
104 context.startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
105 Uri.parse("package:" + BuildConfig.APPLICATION_ID)));
106 } catch (ActivityNotFoundException e) {
107 showErrorDialog(context, "SYSTEM_ALERT_WINDOW");
111 AlertDialog dialog = builder.create();
113 dialog.setCancelable(false);
118 public static void showErrorDialog(final Context context, String appopCmd) {
119 AlertDialog.Builder builder = new AlertDialog.Builder(context);
120 builder.setTitle(R.string.error_dialog_title)
121 .setMessage(context.getString(R.string.error_dialog_message, BuildConfig.APPLICATION_ID, appopCmd))
122 .setPositiveButton(R.string.action_ok, null);
124 AlertDialog dialog = builder.create();
128 public static void lockDevice(Context context) {
129 ComponentName component = new ComponentName(context, LockDeviceReceiver.class);
130 context.getPackageManager().setComponentEnabledSetting(component, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
131 PackageManager.DONT_KILL_APP);
133 DevicePolicyManager mDevicePolicyManager = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
134 if(mDevicePolicyManager.isAdminActive(component))
135 mDevicePolicyManager.lockNow();
137 launchApp(context, () -> {
138 Intent intent = new Intent(context, DummyActivity.class);
139 intent.putExtra("device_admin", true);
140 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
141 context.startActivity(intent);
146 public static void sendAccessibilityAction(Context context, int action) {
147 ComponentName component = new ComponentName(context, PowerMenuService.class);
148 context.getPackageManager().setComponentEnabledSetting(component, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
149 PackageManager.DONT_KILL_APP);
151 if(isAccessibilityServiceEnabled(context)) {
152 Intent intent = new Intent("com.farmerbb.taskbar.ACCESSIBILITY_ACTION");
153 intent.putExtra("action", action);
154 LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
156 launchApp(context, () -> {
157 Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
158 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
161 context.startActivity(intent);
162 showToastLong(context, R.string.enable_accessibility);
163 } catch (ActivityNotFoundException e) {
164 showToast(context, R.string.lock_device_not_supported);
170 private static boolean isAccessibilityServiceEnabled(Context context) {
171 String accessibilityServices = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
172 ComponentName component = new ComponentName(context, PowerMenuService.class);
174 return accessibilityServices != null
175 && (accessibilityServices.contains(component.flattenToString())
176 || accessibilityServices.contains(component.flattenToShortString()));
179 public static void showToast(Context context, int message) {
180 showToast(context, context.getString(message), Toast.LENGTH_SHORT);
183 public static void showToastLong(Context context, int message) {
184 showToast(context, context.getString(message), Toast.LENGTH_LONG);
187 public static void showToast(Context context, String message, int length) {
190 ToastCompat toast = ToastCompat.makeText(context.getApplicationContext(), message, length);
193 ToastHelper.getInstance().setLastToast(toast);
196 public static void cancelToast() {
197 ToastCompat toast = ToastHelper.getInstance().getLastToast();
198 if(toast != null) toast.cancel();
201 public static void startShortcut(Context context, String packageName, String componentName, ShortcutInfo shortcut) {
212 public static void launchApp(final Context context,
213 final String packageName,
214 final String componentName,
215 final long userId, final String windowSize,
216 final boolean launchedFromTaskbar,
217 final boolean openInNewWindow) {
228 private static void launchApp(final Context context,
229 final String packageName,
230 final String componentName,
231 final long userId, final String windowSize,
232 final boolean launchedFromTaskbar,
233 final boolean openInNewWindow,
234 final ShortcutInfo shortcut) {
235 launchApp(context, launchedFromTaskbar, () -> continueLaunchingApp(context, packageName, componentName, userId,
236 windowSize, launchedFromTaskbar, openInNewWindow, shortcut));
239 public static void launchApp(Context context, Runnable runnable) {
240 launchApp(context, true, runnable);
243 private static void launchApp(Context context, boolean launchedFromTaskbar, Runnable runnable) {
244 SharedPreferences pref = getSharedPreferences(context);
245 FreeformHackHelper helper = FreeformHackHelper.getInstance();
247 boolean specialLaunch = isOPreview() && FreeformHackHelper.getInstance().isInFreeformWorkspace()
248 && MenuHelper.getInstance().isContextMenuOpen();
250 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
251 && pref.getBoolean("freeform_hack", false)
252 && (!helper.isInFreeformWorkspace() || specialLaunch)) {
253 new Handler().postDelayed(() -> {
254 startFreeformHack(context, true, launchedFromTaskbar);
256 new Handler().postDelayed(runnable, helper.isFreeformHackActive() ? 0 : 100);
257 }, launchedFromTaskbar ? 0 : 100);
262 @SuppressWarnings("deprecation")
263 @TargetApi(Build.VERSION_CODES.N)
264 public static void startFreeformHack(Context context, boolean checkMultiWindow, boolean launchedFromTaskbar) {
265 Intent freeformHackIntent = new Intent(context, InvisibleActivityFreeform.class);
266 freeformHackIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
269 freeformHackIntent.putExtra("check_multiwindow", true);
271 if(launchedFromTaskbar) {
272 SharedPreferences pref = getSharedPreferences(context);
273 if(pref.getBoolean("disable_animations", false))
274 freeformHackIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
277 if(canDrawOverlays(context))
278 launchAppLowerRight(context, freeformHackIntent);
281 @TargetApi(Build.VERSION_CODES.N)
282 private static void continueLaunchingApp(Context context,
284 String componentName,
287 boolean launchedFromTaskbar,
288 boolean openInNewWindow,
289 ShortcutInfo shortcut) {
290 SharedPreferences pref = getSharedPreferences(context);
291 Intent intent = new Intent();
292 intent.setComponent(ComponentName.unflattenFromString(componentName));
293 intent.setAction(Intent.ACTION_MAIN);
294 intent.addCategory(Intent.CATEGORY_LAUNCHER);
295 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
296 intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
298 if(FreeformHackHelper.getInstance().isInFreeformWorkspace()
299 && Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1
301 intent.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME);
303 if(launchedFromTaskbar) {
304 if(pref.getBoolean("disable_animations", false))
305 intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
308 if(openInNewWindow || pref.getBoolean("force_new_window", false)) {
309 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
311 ActivityInfo activityInfo = intent.resolveActivityInfo(context.getPackageManager(), 0);
312 if(activityInfo != null) {
313 switch(activityInfo.launchMode) {
314 case ActivityInfo.LAUNCH_SINGLE_TASK:
315 case ActivityInfo.LAUNCH_SINGLE_INSTANCE:
316 intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
322 ApplicationType type = getApplicationType(context, packageName);
324 if(windowSize == null)
325 windowSize = SavedWindowSizes.getInstance(context).getWindowSize(context, packageName);
327 if(Build.VERSION.SDK_INT < Build.VERSION_CODES.N
328 || !pref.getBoolean("freeform_hack", false)
329 || windowSize.equals("standard")) {
330 launchStandard(context, intent, userId, shortcut, type);
331 } else switch(windowSize) {
333 launchMode1(context, intent, userId, shortcut, type);
336 launchMode2(context, intent, MAXIMIZED, userId, shortcut, type);
339 launchMode2(context, intent, LEFT, userId, shortcut, type);
342 launchMode2(context, intent, RIGHT, userId, shortcut, type);
345 launchMode3(context, intent, userId, shortcut, type);
349 if(pref.getBoolean("hide_taskbar", true) && !FreeformHackHelper.getInstance().isInFreeformWorkspace())
350 LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_TASKBAR"));
352 LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU"));
355 private static void launchStandard(Context context, Intent intent, long userId, ShortcutInfo shortcut, ApplicationType type) {
356 Bundle bundle = Build.VERSION.SDK_INT < Build.VERSION_CODES.N ? null : getActivityOptions(type).toBundle();
357 if(shortcut == null) {
358 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
359 if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
361 context.startActivity(intent, bundle);
362 } catch (ActivityNotFoundException e) {
363 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
364 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
366 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
368 launchShortcut(context, shortcut, bundle);
371 @SuppressWarnings("deprecation")
372 @TargetApi(Build.VERSION_CODES.N)
373 private static void launchMode1(Context context, Intent intent, long userId, ShortcutInfo shortcut, ApplicationType type) {
374 DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
375 Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
377 int width1 = display.getWidth() / 8;
378 int width2 = display.getWidth() - width1;
379 int height1 = display.getHeight() / 8;
380 int height2 = display.getHeight() - height1;
382 Bundle bundle = getActivityOptions(type).setLaunchBounds(new Rect(
389 if(shortcut == null) {
390 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
391 if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
393 context.startActivity(intent, bundle);
394 } catch (ActivityNotFoundException e) {
395 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
396 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
398 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
400 launchShortcut(context, shortcut, bundle);
403 @SuppressWarnings("deprecation")
404 @TargetApi(Build.VERSION_CODES.N)
405 private static void launchMode2(Context context, Intent intent, int launchType, long userId, ShortcutInfo shortcut, ApplicationType type) {
406 DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
407 Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
409 int statusBarHeight = getStatusBarHeight(context);
410 String position = getTaskbarPosition(context);
412 boolean isPortrait = context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
413 boolean isLandscape = context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
415 int left = launchType == RIGHT && isLandscape
416 ? display.getWidth() / 2
419 int top = launchType == RIGHT && isPortrait
420 ? display.getHeight() / 2
423 int right = launchType == LEFT && isLandscape
424 ? display.getWidth() / 2
425 : display.getWidth();
427 int bottom = launchType == LEFT && isPortrait
428 ? display.getHeight() / 2
429 : display.getHeight();
431 int iconSize = context.getResources().getDimensionPixelSize(R.dimen.icon_size);
433 if(position.contains("vertical_left")) {
434 if(launchType != RIGHT || isPortrait) left = left + iconSize;
435 } else if(position.contains("vertical_right")) {
436 if(launchType != LEFT || isPortrait) right = right - iconSize;
437 } else if(position.contains("bottom")) {
438 if(isLandscape || (launchType != LEFT && isPortrait))
439 bottom = bottom - iconSize;
440 } else if(isLandscape || (launchType != RIGHT && isPortrait))
441 top = top + iconSize;
443 Bundle bundle = getActivityOptions(type).setLaunchBounds(new Rect(
450 if(shortcut == null) {
451 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
452 if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
454 context.startActivity(intent, bundle);
455 } catch (ActivityNotFoundException e) {
456 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
457 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
459 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
461 launchShortcut(context, shortcut, bundle);
464 @SuppressWarnings("deprecation")
465 @TargetApi(Build.VERSION_CODES.N)
466 private static void launchMode3(Context context, Intent intent, long userId, ShortcutInfo shortcut, ApplicationType type) {
467 DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
468 Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
470 int width1 = display.getWidth() / 2;
471 int width2 = context.getResources().getDimensionPixelSize(R.dimen.phone_size_width) / 2;
472 int height1 = display.getHeight() / 2;
473 int height2 = context.getResources().getDimensionPixelSize(R.dimen.phone_size_height) / 2;
475 Bundle bundle = getActivityOptions(type).setLaunchBounds(new Rect(
482 if(shortcut == null) {
483 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
484 if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
486 context.startActivity(intent, bundle);
487 } catch (ActivityNotFoundException e) {
488 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
489 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
491 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
493 launchShortcut(context, shortcut, bundle);
496 private static void launchAndroidForWork(Context context, ComponentName componentName, Bundle bundle, long userId) {
497 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
498 LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
501 launcherApps.startMainActivity(componentName, userManager.getUserForSerialNumber(userId), null, bundle);
502 } catch (ActivityNotFoundException | NullPointerException e) { /* Gracefully fail */ }
505 @TargetApi(Build.VERSION_CODES.N_MR1)
506 private static void launchShortcut(Context context, ShortcutInfo shortcut, Bundle bundle) {
507 LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
509 if(launcherApps.hasShortcutHostPermission()) {
511 launcherApps.startShortcut(shortcut, null, bundle);
512 } catch (ActivityNotFoundException | NullPointerException e) { /* Gracefully fail */ }
516 public static void launchAppMaximized(Context context, Intent intent) {
517 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
518 long userId = userManager.getSerialNumberForUser(Process.myUserHandle());
520 launchMode2(context, intent, MAXIMIZED, userId, null, ApplicationType.CONTEXT_MENU);
523 @SuppressWarnings("deprecation")
524 @TargetApi(Build.VERSION_CODES.N)
525 public static void launchAppLowerRight(Context context, Intent intent) {
526 DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
527 Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
529 context.startActivity(intent, getActivityOptions(ApplicationType.FREEFORM_HACK).setLaunchBounds(new Rect(
532 display.getWidth() + 1,
533 display.getHeight() + 1
535 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
538 public static void checkForUpdates(Context context) {
539 if(!BuildConfig.DEBUG) {
542 context.getPackageManager().getPackageInfo("com.android.vending", 0);
543 url = "https://play.google.com/store/apps/details?id=" + BuildConfig.APPLICATION_ID;
544 } catch (PackageManager.NameNotFoundException e) {
545 url = "https://f-droid.org/repository/browse/?fdid=" + BuildConfig.BASE_APPLICATION_ID;
548 Intent intent = new Intent(Intent.ACTION_VIEW);
549 intent.setData(Uri.parse(url));
550 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
553 context.startActivity(intent);
554 } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
556 showToast(context, R.string.debug_build);
559 public static boolean launcherIsDefault(Context context) {
560 Intent homeIntent = new Intent(Intent.ACTION_MAIN);
561 homeIntent.addCategory(Intent.CATEGORY_HOME);
562 ResolveInfo defaultLauncher = context.getPackageManager().resolveActivity(homeIntent, PackageManager.MATCH_DEFAULT_ONLY);
564 return defaultLauncher.activityInfo.packageName.equals(BuildConfig.APPLICATION_ID);
567 public static void setCachedRotation(int cachedRotation) {
568 U.cachedRotation = cachedRotation;
571 public static String getTaskbarPosition(Context context) {
572 SharedPreferences pref = getSharedPreferences(context);
573 String position = pref.getString("position", "bottom_left");
575 if(pref.getBoolean("anchor", false)) {
576 WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
577 int rotation = cachedRotation != null ? cachedRotation : windowManager.getDefaultDisplay().getRotation();
582 case Surface.ROTATION_0:
583 return "bottom_left";
584 case Surface.ROTATION_90:
585 return "bottom_vertical_right";
586 case Surface.ROTATION_180:
588 case Surface.ROTATION_270:
589 return "top_vertical_left";
592 case "bottom_vertical_left":
594 case Surface.ROTATION_0:
595 return "bottom_vertical_left";
596 case Surface.ROTATION_90:
597 return "bottom_right";
598 case Surface.ROTATION_180:
599 return "top_vertical_right";
600 case Surface.ROTATION_270:
606 case Surface.ROTATION_0:
607 return "bottom_right";
608 case Surface.ROTATION_90:
609 return "top_vertical_right";
610 case Surface.ROTATION_180:
612 case Surface.ROTATION_270:
613 return "bottom_vertical_left";
616 case "bottom_vertical_right":
618 case Surface.ROTATION_0:
619 return "bottom_vertical_right";
620 case Surface.ROTATION_90:
622 case Surface.ROTATION_180:
623 return "top_vertical_left";
624 case Surface.ROTATION_270:
625 return "bottom_left";
630 case Surface.ROTATION_0:
632 case Surface.ROTATION_90:
633 return "bottom_vertical_left";
634 case Surface.ROTATION_180:
635 return "bottom_right";
636 case Surface.ROTATION_270:
637 return "top_vertical_right";
640 case "top_vertical_left":
642 case Surface.ROTATION_0:
643 return "top_vertical_left";
644 case Surface.ROTATION_90:
645 return "bottom_left";
646 case Surface.ROTATION_180:
647 return "bottom_vertical_right";
648 case Surface.ROTATION_270:
654 case Surface.ROTATION_0:
656 case Surface.ROTATION_90:
657 return "top_vertical_left";
658 case Surface.ROTATION_180:
659 return "bottom_left";
660 case Surface.ROTATION_270:
661 return "bottom_vertical_right";
664 case "top_vertical_right":
666 case Surface.ROTATION_0:
667 return "top_vertical_right";
668 case Surface.ROTATION_90:
670 case Surface.ROTATION_180:
671 return "bottom_vertical_left";
672 case Surface.ROTATION_270:
673 return "bottom_right";
682 private static int getMaxNumOfColumns(Context context) {
683 SharedPreferences pref = getSharedPreferences(context);
684 DisplayMetrics metrics = context.getResources().getDisplayMetrics();
685 float baseTaskbarSize = getBaseTaskbarSizeFloat(context) / metrics.density;
686 int numOfColumns = 0;
688 float maxScreenSize = getTaskbarPosition(context).contains("vertical")
689 ? (metrics.heightPixels - getStatusBarHeight(context)) / metrics.density
690 : metrics.widthPixels / metrics.density;
692 float iconSize = context.getResources().getDimension(R.dimen.icon_size) / metrics.density;
694 int userMaxNumOfColumns = Integer.valueOf(pref.getString("max_num_of_recents", "10"));
696 while(baseTaskbarSize + iconSize < maxScreenSize
697 && numOfColumns < userMaxNumOfColumns) {
698 baseTaskbarSize = baseTaskbarSize + iconSize;
705 public static int getMaxNumOfEntries(Context context) {
706 SharedPreferences pref = getSharedPreferences(context);
707 return pref.getBoolean("disable_scrolling_list", false)
708 ? getMaxNumOfColumns(context)
709 : Integer.valueOf(pref.getString("max_num_of_recents", "10"));
712 public static int getStatusBarHeight(Context context) {
713 int statusBarHeight = 0;
714 int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
716 statusBarHeight = context.getResources().getDimensionPixelSize(resourceId);
718 return statusBarHeight;
721 public static void refreshPinnedIcons(Context context) {
722 IconCache.getInstance(context).clearCache();
724 PinnedBlockedApps pba = PinnedBlockedApps.getInstance(context);
725 List<AppEntry> pinnedAppsList = new ArrayList<>(pba.getPinnedApps());
726 List<AppEntry> blockedAppsList = new ArrayList<>(pba.getBlockedApps());
727 PackageManager pm = context.getPackageManager();
731 for(AppEntry entry : pinnedAppsList) {
732 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
733 LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
735 final List<UserHandle> userHandles = userManager.getUserProfiles();
736 LauncherActivityInfo appInfo = null;
738 for(UserHandle handle : userHandles) {
739 List<LauncherActivityInfo> list = launcherApps.getActivityList(entry.getPackageName(), handle);
740 if(!list.isEmpty()) {
741 // Google App workaround
742 if(!entry.getPackageName().equals("com.google.android.googlequicksearchbox"))
743 appInfo = list.get(0);
745 boolean added = false;
746 for(LauncherActivityInfo info : list) {
747 if(info.getName().equals("com.google.android.googlequicksearchbox.SearchActivity")) {
753 if(!added) appInfo = list.get(0);
760 if(appInfo != null) {
761 AppEntry newEntry = new AppEntry(
762 entry.getPackageName(),
763 entry.getComponentName(),
765 IconCache.getInstance(context).getIcon(context, pm, appInfo),
768 newEntry.setUserId(entry.getUserId(context));
769 pba.addPinnedApp(context, newEntry);
773 for(AppEntry entry : blockedAppsList) {
774 pba.addBlockedApp(context, entry);
778 public static Intent getShortcutIntent(Context context) {
779 Intent shortcutIntent = new Intent(context, ShortcutActivity.class);
780 shortcutIntent.setAction(Intent.ACTION_MAIN);
781 shortcutIntent.putExtra("is_launching_shortcut", true);
783 BitmapDrawable drawable = (BitmapDrawable) context.getDrawable(R.mipmap.ic_freeform_mode);
785 Intent intent = new Intent();
786 intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
787 if(drawable != null) intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, drawable.getBitmap());
788 intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, context.getString(R.string.pref_header_freeform));
793 public static Intent getStartStopIntent(Context context) {
794 Intent shortcutIntent = new Intent(context, StartTaskbarActivity.class);
795 shortcutIntent.setAction(Intent.ACTION_MAIN);
796 shortcutIntent.putExtra("is_launching_shortcut", true);
798 BitmapDrawable drawable = (BitmapDrawable) context.getDrawable(R.mipmap.ic_launcher);
800 Intent intent = new Intent();
801 intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
802 if(drawable != null) intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, drawable.getBitmap());
803 intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, context.getString(R.string.start_taskbar));
808 public static boolean hasFreeformSupport(Context context) {
809 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
810 && (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT)
811 || Settings.Global.getInt(context.getContentResolver(), "enable_freeform_support", -1) == 1
812 || (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1
813 && Settings.Global.getInt(context.getContentResolver(), "force_resizable_activities", -1) == 1));
816 public static boolean hasPartialFreeformSupport() {
817 return Build.MANUFACTURER.equalsIgnoreCase("Samsung") || isOPreview();
820 public static boolean isServiceRunning(Context context, Class<? extends Service> cls) {
821 return isServiceRunning(context, cls.getName());
824 public static boolean isServiceRunning(Context context, String className) {
825 ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
826 for(ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
827 if(className.equals(service.service.getClassName()))
834 public static int getBackgroundTint(Context context) {
835 SharedPreferences pref = getSharedPreferences(context);
837 // Import old background tint preference
838 if(pref.contains("show_background")) {
839 SharedPreferences.Editor editor = pref.edit();
841 if(!pref.getBoolean("show_background", true))
842 editor.putInt("background_tint", 0).apply();
844 editor.remove("show_background");
848 return pref.getInt("background_tint", context.getResources().getInteger(R.integer.translucent_gray));
851 public static int getAccentColor(Context context) {
852 SharedPreferences pref = getSharedPreferences(context);
853 return pref.getInt("accent_color", context.getResources().getInteger(R.integer.translucent_white));
856 @TargetApi(Build.VERSION_CODES.M)
857 public static boolean canDrawOverlays(Context context) {
858 return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(context);
861 public static boolean isGame(Context context, String packageName) {
862 SharedPreferences pref = getSharedPreferences(context);
863 if(pref.getBoolean("launch_games_fullscreen", true)) {
864 PackageManager pm = context.getPackageManager();
867 ApplicationInfo info = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
868 return (info.flags & ApplicationInfo.FLAG_IS_GAME) != 0 || (info.metaData != null && info.metaData.getBoolean("isGame", false));
869 } catch (PackageManager.NameNotFoundException e) {
876 @TargetApi(Build.VERSION_CODES.M)
877 public static ActivityOptions getActivityOptions(ApplicationType applicationType) {
878 ActivityOptions options = ActivityOptions.makeBasic();
879 Integer stackId = null;
881 switch(applicationType) {
883 if(!FreeformHackHelper.getInstance().isFreeformHackActive())
884 stackId = FULLSCREEN_WORKSPACE_STACK_ID;
887 stackId = FULLSCREEN_WORKSPACE_STACK_ID;
890 stackId = FREEFORM_WORKSPACE_STACK_ID;
893 if(isOPreview()) stackId = FULLSCREEN_WORKSPACE_STACK_ID;
896 if(stackId != null) {
898 Method method = ActivityOptions.class.getMethod("setLaunchStackId", int.class);
899 method.invoke(options, stackId);
900 } catch (Exception e) { /* Gracefully fail */ }
906 private static ApplicationType getApplicationType(Context context, String packageName) {
907 return isGame(context, packageName) ? ApplicationType.GAME : ApplicationType.APPLICATION;
910 public static boolean isSystemApp(Context context) {
912 ApplicationInfo info = context.getPackageManager().getApplicationInfo(BuildConfig.APPLICATION_ID, 0);
913 int mask = ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
914 return (info.flags & mask) != 0;
915 } catch (PackageManager.NameNotFoundException e) {
920 @TargetApi(Build.VERSION_CODES.M)
921 public static boolean isOPreview() {
922 return (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) || (Build.VERSION.RELEASE.equals("O") && Build.VERSION.PREVIEW_SDK_INT > 0);
925 public static boolean hasSupportLibrary(Context context) {
926 PackageManager pm = context.getPackageManager();
928 pm.getPackageInfo(BuildConfig.SUPPORT_APPLICATION_ID, 0);
929 return pm.checkSignatures(BuildConfig.SUPPORT_APPLICATION_ID, BuildConfig.APPLICATION_ID) == PackageManager.SIGNATURE_MATCH
930 && BuildConfig.APPLICATION_ID.equals(BuildConfig.BASE_APPLICATION_ID)
931 && isSystemApp(context);
932 } catch (PackageManager.NameNotFoundException e) {
937 public static int getBaseTaskbarSize(Context context) {
938 return Math.round(getBaseTaskbarSizeFloat(context));
941 private static float getBaseTaskbarSizeFloat(Context context) {
942 SharedPreferences pref = getSharedPreferences(context);
943 float baseTaskbarSize = context.getResources().getDimension(R.dimen.base_taskbar_size);
944 boolean navbarButtonsEnabled = false;
946 if(pref.getBoolean("dashboard", false))
947 baseTaskbarSize += context.getResources().getDimension(R.dimen.dashboard_button_size);
949 if(pref.getBoolean("button_back", false)) {
950 navbarButtonsEnabled = true;
951 baseTaskbarSize += context.getResources().getDimension(R.dimen.icon_size);
954 if(pref.getBoolean("button_home", false)) {
955 navbarButtonsEnabled = true;
956 baseTaskbarSize += context.getResources().getDimension(R.dimen.icon_size);
959 if(pref.getBoolean("button_recents", false)) {
960 navbarButtonsEnabled = true;
961 baseTaskbarSize += context.getResources().getDimension(R.dimen.icon_size);
964 if(navbarButtonsEnabled)
965 baseTaskbarSize += context.getResources().getDimension(R.dimen.navbar_buttons_margin);
967 return baseTaskbarSize;
970 private static void startTaskbarService(Context context, boolean fullRestart) {
971 context.startService(new Intent(context, TaskbarService.class));
972 context.startService(new Intent(context, StartMenuService.class));
973 context.startService(new Intent(context, DashboardService.class));
974 if(fullRestart) context.startService(new Intent(context, NotificationService.class));
977 private static void stopTaskbarService(Context context, boolean fullRestart) {
978 context.stopService(new Intent(context, TaskbarService.class));
979 context.stopService(new Intent(context, StartMenuService.class));
980 context.stopService(new Intent(context, DashboardService.class));
981 if(fullRestart) context.stopService(new Intent(context, NotificationService.class));
984 public static void restartTaskbar(Context context) {
985 SharedPreferences pref = getSharedPreferences(context);
986 if(pref.getBoolean("taskbar_active", false) && !pref.getBoolean("is_hidden", false)) {
988 .putBoolean("is_restarting", true)
989 .putBoolean("skip_auto_hide_navbar", true)
992 stopTaskbarService(context, true);
993 startTaskbarService(context, true);
994 } else if(isServiceRunning(context, StartMenuService.class)) {
995 pref.edit().putBoolean("skip_auto_hide_navbar", true).apply();
997 stopTaskbarService(context, false);
998 startTaskbarService(context, false);
1002 public static void restartNotificationService(Context context) {
1003 if(isServiceRunning(context, NotificationService.class)) {
1004 SharedPreferences pref = getSharedPreferences(context);
1005 pref.edit().putBoolean("is_restarting", true).apply();
1007 Intent intent = new Intent(context, NotificationService.class);
1008 context.stopService(intent);
1009 context.startService(intent);
1013 public static void showHideNavigationBar(Context context, boolean show) {
1014 // Show or hide the system navigation bar on Bliss-x86
1016 Settings.System.putInt(context.getContentResolver(), "navigation_bar_show", show ? 1 : 0);
1017 } catch (Exception e) { /* Gracefully fail */ }
1020 public static void initPrefs(Context context) {
1021 // On smaller-screened devices, set "Grid" as the default start menu layout
1022 SharedPreferences pref = getSharedPreferences(context);
1023 if(context.getApplicationContext().getResources().getConfiguration().smallestScreenWidthDp < 600
1024 && pref.getString("start_menu_layout", "null").equals("null")) {
1025 pref.edit().putString("start_menu_layout", "grid").apply();
1028 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
1029 if(!pref.getBoolean("freeform_hack_override", false)) {
1031 .putBoolean("freeform_hack", hasFreeformSupport(context) && !hasPartialFreeformSupport())
1032 .putBoolean("save_window_sizes", false)
1033 .putBoolean("freeform_hack_override", true)
1035 } else if(!hasFreeformSupport(context)) {
1036 pref.edit().putBoolean("freeform_hack", false).apply();
1038 LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.FINISH_FREEFORM_ACTIVITY"));