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.PowerMenuService;
64 import java.lang.reflect.Method;
65 import java.util.ArrayList;
66 import java.util.List;
68 import moe.banana.support.ToastCompat;
74 private static SharedPreferences pref;
75 private static Integer cachedRotation;
77 private static final int MAXIMIZED = 0;
78 private static final int LEFT = -1;
79 private static final int RIGHT = 1;
81 public static final int HIDDEN = 0;
82 public static final int TOP_APPS = 1;
84 // From android.app.ActivityManager.StackId
85 private static final int FULLSCREEN_WORKSPACE_STACK_ID = 1;
86 private static final int FREEFORM_WORKSPACE_STACK_ID = 2;
88 public static SharedPreferences getSharedPreferences(Context context) {
89 if(pref == null) pref = context.getSharedPreferences(BuildConfig.APPLICATION_ID + "_preferences", Context.MODE_PRIVATE);
93 @TargetApi(Build.VERSION_CODES.M)
94 public static void showPermissionDialog(final Context context) {
95 AlertDialog.Builder builder = new AlertDialog.Builder(context);
96 builder.setTitle(R.string.permission_dialog_title)
97 .setMessage(R.string.permission_dialog_message)
98 .setPositiveButton(R.string.action_grant_permission, (dialog, which) -> {
100 context.startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
101 Uri.parse("package:" + BuildConfig.APPLICATION_ID)));
102 } catch (ActivityNotFoundException e) {
103 showErrorDialog(context, "SYSTEM_ALERT_WINDOW");
107 AlertDialog dialog = builder.create();
109 dialog.setCancelable(false);
112 public static void showErrorDialog(final Context context, String appopCmd) {
113 AlertDialog.Builder builder = new AlertDialog.Builder(context);
114 builder.setTitle(R.string.error_dialog_title)
115 .setMessage(context.getString(R.string.error_dialog_message, BuildConfig.APPLICATION_ID, appopCmd))
116 .setPositiveButton(R.string.action_ok, null);
118 AlertDialog dialog = builder.create();
122 public static void lockDevice(Context context) {
123 ComponentName component = new ComponentName(context, LockDeviceReceiver.class);
124 context.getPackageManager().setComponentEnabledSetting(component, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
125 PackageManager.DONT_KILL_APP);
127 DevicePolicyManager mDevicePolicyManager = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
128 if(mDevicePolicyManager.isAdminActive(component))
129 mDevicePolicyManager.lockNow();
131 Intent intent = new Intent(context, DummyActivity.class);
132 intent.putExtra("device_admin", true);
133 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
134 context.startActivity(intent);
138 public static void showPowerMenu(Context context) {
139 ComponentName component = new ComponentName(context, PowerMenuService.class);
140 context.getPackageManager().setComponentEnabledSetting(component, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
141 PackageManager.DONT_KILL_APP);
143 if(isAccessibilityServiceEnabled(context))
144 LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.SHOW_POWER_MENU"));
146 Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
147 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
150 context.startActivity(intent);
151 showToastLong(context, R.string.enable_accessibility);
152 } catch (ActivityNotFoundException e) {
153 showToast(context, R.string.lock_device_not_supported);
158 private static boolean isAccessibilityServiceEnabled(Context context) {
159 String accessibilityServices = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
160 ComponentName component = new ComponentName(context, PowerMenuService.class);
162 return accessibilityServices != null
163 && (accessibilityServices.contains(component.flattenToString())
164 || accessibilityServices.contains(component.flattenToShortString()));
167 public static void showToast(Context context, int message) {
168 showToast(context, context.getString(message), Toast.LENGTH_SHORT);
171 public static void showToastLong(Context context, int message) {
172 showToast(context, context.getString(message), Toast.LENGTH_LONG);
175 public static void showToast(Context context, String message, int length) {
178 ToastCompat toast = ToastCompat.makeText(context.getApplicationContext(), message, length);
181 ToastHelper.getInstance().setLastToast(toast);
184 public static void cancelToast() {
185 ToastCompat toast = ToastHelper.getInstance().getLastToast();
186 if(toast != null) toast.cancel();
189 public static void startShortcut(Context context, String packageName, String componentName, ShortcutInfo shortcut) {
200 public static void launchApp(final Context context,
201 final String packageName,
202 final String componentName,
203 final long userId, final String windowSize,
204 final boolean launchedFromTaskbar,
205 final boolean openInNewWindow) {
216 private static void launchApp(final Context context,
217 final String packageName,
218 final String componentName,
219 final long userId, final String windowSize,
220 final boolean launchedFromTaskbar,
221 final boolean openInNewWindow,
222 final ShortcutInfo shortcut) {
223 boolean shouldDelay = false;
225 SharedPreferences pref = getSharedPreferences(context);
226 FreeformHackHelper helper = FreeformHackHelper.getInstance();
227 boolean freeformHackActive = openInNewWindow
228 ? helper.isInFreeformWorkspace()
229 : helper.isFreeformHackActive();
231 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
232 && pref.getBoolean("freeform_hack", false)
233 && !freeformHackActive) {
236 new Handler().postDelayed(() -> {
237 startFreeformHack(context, true, launchedFromTaskbar);
239 new Handler().postDelayed(() -> continueLaunchingApp(context, packageName, componentName, userId,
240 windowSize, launchedFromTaskbar, openInNewWindow, shortcut), 100);
241 }, launchedFromTaskbar ? 0 : 100);
244 if(!helper.isFreeformHackActive()) {
246 continueLaunchingApp(context, packageName, componentName, userId,
247 windowSize, launchedFromTaskbar, openInNewWindow, shortcut);
249 continueLaunchingApp(context, packageName, componentName, userId,
250 windowSize, launchedFromTaskbar, openInNewWindow, shortcut);
253 @SuppressWarnings("deprecation")
254 @TargetApi(Build.VERSION_CODES.N)
255 public static void startFreeformHack(Context context, boolean checkMultiWindow, boolean launchedFromTaskbar) {
256 Intent freeformHackIntent = new Intent(context, InvisibleActivityFreeform.class);
257 freeformHackIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
260 freeformHackIntent.putExtra("check_multiwindow", true);
262 if(launchedFromTaskbar) {
263 SharedPreferences pref = getSharedPreferences(context);
264 if(pref.getBoolean("disable_animations", false))
265 freeformHackIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
268 launchAppLowerRight(context, freeformHackIntent);
271 @TargetApi(Build.VERSION_CODES.N)
272 private static void continueLaunchingApp(Context context,
274 String componentName,
277 boolean launchedFromTaskbar,
278 boolean openInNewWindow,
279 ShortcutInfo shortcut) {
280 SharedPreferences pref = getSharedPreferences(context);
281 Intent intent = new Intent();
282 intent.setComponent(ComponentName.unflattenFromString(componentName));
283 intent.setAction(Intent.ACTION_MAIN);
284 intent.addCategory(Intent.CATEGORY_LAUNCHER);
285 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
286 intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
288 if(FreeformHackHelper.getInstance().isInFreeformWorkspace())
289 intent.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME);
291 if(launchedFromTaskbar) {
292 if(pref.getBoolean("disable_animations", false))
293 intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
296 if(openInNewWindow || pref.getBoolean("force_new_window", false)) {
297 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
299 ActivityInfo activityInfo = intent.resolveActivityInfo(context.getPackageManager(), 0);
300 if(activityInfo != null) {
301 switch(activityInfo.launchMode) {
302 case ActivityInfo.LAUNCH_SINGLE_TASK:
303 case ActivityInfo.LAUNCH_SINGLE_INSTANCE:
304 intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
310 if(windowSize == null) {
311 if(pref.getBoolean("save_window_sizes", true))
312 windowSize = SavedWindowSizes.getInstance(context).getWindowSize(context, packageName);
314 windowSize = pref.getString("window_size", "standard");
317 if(Build.VERSION.SDK_INT < Build.VERSION_CODES.N || !pref.getBoolean("freeform_hack", false)) {
318 if(shortcut == null) {
319 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
320 if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
322 context.startActivity(intent, null);
323 } catch (ActivityNotFoundException e) {
324 launchAndroidForWork(context, intent.getComponent(), null, userId);
325 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
327 launchAndroidForWork(context, intent.getComponent(), null, userId);
329 launchShortcut(context, shortcut, null);
330 } else switch(windowSize) {
332 if(FreeformHackHelper.getInstance().isInFreeformWorkspace()) {
333 Bundle bundle = getActivityOptions(isGame(context, packageName)).toBundle();
334 if(shortcut == null) {
335 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
336 if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
338 context.startActivity(intent, bundle);
339 } catch (ActivityNotFoundException e) {
340 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
341 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
343 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
345 launchShortcut(context, shortcut, bundle);
347 launchMode1(context, intent, 1, userId, shortcut, isGame(context, packageName));
350 launchMode1(context, intent, 2, userId, shortcut, isGame(context, packageName));
353 launchMode2(context, intent, MAXIMIZED, userId, shortcut, isGame(context, packageName));
356 launchMode2(context, intent, LEFT, userId, shortcut, isGame(context, packageName));
359 launchMode2(context, intent, RIGHT, userId, shortcut, isGame(context, packageName));
362 launchMode3(context, intent, userId, shortcut, isGame(context, packageName));
366 if(pref.getBoolean("hide_taskbar", true) && !FreeformHackHelper.getInstance().isInFreeformWorkspace())
367 LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_TASKBAR"));
369 LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU"));
372 @SuppressWarnings("deprecation")
373 @TargetApi(Build.VERSION_CODES.N)
374 private static void launchMode1(Context context, Intent intent, int factor, long userId, ShortcutInfo shortcut, Boolean isGame) {
375 DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
376 Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
378 int width1 = display.getWidth() / (4 * factor);
379 int width2 = display.getWidth() - width1;
380 int height1 = display.getHeight() / (4 * factor);
381 int height2 = display.getHeight() - height1;
383 Bundle bundle = getActivityOptions(isGame).setLaunchBounds(new Rect(
390 if(shortcut == null) {
391 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
392 if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
394 context.startActivity(intent, bundle);
395 } catch (ActivityNotFoundException e) {
396 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
397 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
399 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
401 launchShortcut(context, shortcut, bundle);
404 @SuppressWarnings("deprecation")
405 @TargetApi(Build.VERSION_CODES.N)
406 private static void launchMode2(Context context, Intent intent, int launchType, long userId, ShortcutInfo shortcut, Boolean isGame) {
407 DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
408 Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
410 int statusBarHeight = getStatusBarHeight(context);
411 String position = getTaskbarPosition(context);
413 boolean isPortrait = context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
414 boolean isLandscape = context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
416 int left = launchType == RIGHT && isLandscape
417 ? display.getWidth() / 2
420 int top = launchType == RIGHT && isPortrait
421 ? display.getHeight() / 2
424 int right = launchType == LEFT && isLandscape
425 ? display.getWidth() / 2
426 : display.getWidth();
428 int bottom = launchType == LEFT && isPortrait
429 ? display.getHeight() / 2
430 : display.getHeight();
432 int iconSize = context.getResources().getDimensionPixelSize(R.dimen.icon_size);
434 if(position.contains("vertical_left")) {
435 if(launchType != RIGHT || isPortrait) left = left + iconSize;
436 } else if(position.contains("vertical_right")) {
437 if(launchType != LEFT || isPortrait) right = right - iconSize;
438 } else if(position.contains("bottom")) {
439 if(isLandscape || (launchType != LEFT && isPortrait))
440 bottom = bottom - iconSize;
441 } else if(isLandscape || (launchType != RIGHT && isPortrait))
442 top = top + iconSize;
444 Bundle bundle = getActivityOptions(isGame).setLaunchBounds(new Rect(
451 if(shortcut == null) {
452 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
453 if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
455 context.startActivity(intent, bundle);
456 } catch (ActivityNotFoundException e) {
457 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
458 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
460 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
462 launchShortcut(context, shortcut, bundle);
465 @SuppressWarnings("deprecation")
466 @TargetApi(Build.VERSION_CODES.N)
467 private static void launchMode3(Context context, Intent intent, long userId, ShortcutInfo shortcut, Boolean isGame) {
468 DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
469 Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
471 int width1 = display.getWidth() / 2;
472 int width2 = context.getResources().getDimensionPixelSize(R.dimen.phone_size_width) / 2;
473 int height1 = display.getHeight() / 2;
474 int height2 = context.getResources().getDimensionPixelSize(R.dimen.phone_size_height) / 2;
476 Bundle bundle = getActivityOptions(isGame).setLaunchBounds(new Rect(
483 if(shortcut == null) {
484 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
485 if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
487 context.startActivity(intent, bundle);
488 } catch (ActivityNotFoundException e) {
489 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
490 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
492 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
494 launchShortcut(context, shortcut, bundle);
497 private static void launchAndroidForWork(Context context, ComponentName componentName, Bundle bundle, long userId) {
498 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
499 LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
502 launcherApps.startMainActivity(componentName, userManager.getUserForSerialNumber(userId), null, bundle);
503 } catch (ActivityNotFoundException | NullPointerException e) { /* Gracefully fail */ }
506 @TargetApi(Build.VERSION_CODES.N_MR1)
507 private static void launchShortcut(Context context, ShortcutInfo shortcut, Bundle bundle) {
508 LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
510 if(launcherApps.hasShortcutHostPermission()) {
512 launcherApps.startShortcut(shortcut, null, bundle);
513 } catch (ActivityNotFoundException | NullPointerException e) { /* Gracefully fail */ }
517 public static void launchAppMaximized(Context context, Intent intent) {
518 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
519 long userId = userManager.getSerialNumberForUser(Process.myUserHandle());
521 launchMode2(context, intent, MAXIMIZED, userId, null, null);
524 @SuppressWarnings("deprecation")
525 @TargetApi(Build.VERSION_CODES.N)
526 public static void launchAppLowerRight(Context context, Intent intent) {
527 DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
528 Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
530 context.startActivity(intent, getActivityOptions(false).setLaunchBounds(new Rect(
533 display.getWidth() + 1,
534 display.getHeight() + 1
536 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
539 public static void checkForUpdates(Context context) {
540 if(!BuildConfig.DEBUG) {
543 context.getPackageManager().getPackageInfo("com.android.vending", 0);
544 url = "https://play.google.com/store/apps/details?id=" + BuildConfig.APPLICATION_ID;
545 } catch (PackageManager.NameNotFoundException e) {
546 url = "https://f-droid.org/repository/browse/?fdid=" + BuildConfig.BASE_APPLICATION_ID;
549 Intent intent = new Intent(Intent.ACTION_VIEW);
550 intent.setData(Uri.parse(url));
551 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
554 context.startActivity(intent);
555 } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
557 showToast(context, R.string.debug_build);
560 public static boolean launcherIsDefault(Context context) {
561 Intent homeIntent = new Intent(Intent.ACTION_MAIN);
562 homeIntent.addCategory(Intent.CATEGORY_HOME);
563 ResolveInfo defaultLauncher = context.getPackageManager().resolveActivity(homeIntent, PackageManager.MATCH_DEFAULT_ONLY);
565 return defaultLauncher.activityInfo.packageName.equals(BuildConfig.APPLICATION_ID);
568 public static void setCachedRotation(int cachedRotation) {
569 U.cachedRotation = cachedRotation;
572 public static String getTaskbarPosition(Context context) {
573 SharedPreferences pref = getSharedPreferences(context);
574 String position = pref.getString("position", "bottom_left");
576 if(pref.getBoolean("anchor", false)) {
577 WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
578 int rotation = cachedRotation != null ? cachedRotation : windowManager.getDefaultDisplay().getRotation();
583 case Surface.ROTATION_0:
584 return "bottom_left";
585 case Surface.ROTATION_90:
586 return "bottom_vertical_right";
587 case Surface.ROTATION_180:
589 case Surface.ROTATION_270:
590 return "top_vertical_left";
593 case "bottom_vertical_left":
595 case Surface.ROTATION_0:
596 return "bottom_vertical_left";
597 case Surface.ROTATION_90:
598 return "bottom_right";
599 case Surface.ROTATION_180:
600 return "top_vertical_right";
601 case Surface.ROTATION_270:
607 case Surface.ROTATION_0:
608 return "bottom_right";
609 case Surface.ROTATION_90:
610 return "top_vertical_right";
611 case Surface.ROTATION_180:
613 case Surface.ROTATION_270:
614 return "bottom_vertical_left";
617 case "bottom_vertical_right":
619 case Surface.ROTATION_0:
620 return "bottom_vertical_right";
621 case Surface.ROTATION_90:
623 case Surface.ROTATION_180:
624 return "top_vertical_left";
625 case Surface.ROTATION_270:
626 return "bottom_left";
631 case Surface.ROTATION_0:
633 case Surface.ROTATION_90:
634 return "bottom_vertical_left";
635 case Surface.ROTATION_180:
636 return "bottom_right";
637 case Surface.ROTATION_270:
638 return "top_vertical_right";
641 case "top_vertical_left":
643 case Surface.ROTATION_0:
644 return "top_vertical_left";
645 case Surface.ROTATION_90:
646 return "bottom_left";
647 case Surface.ROTATION_180:
648 return "bottom_vertical_right";
649 case Surface.ROTATION_270:
655 case Surface.ROTATION_0:
657 case Surface.ROTATION_90:
658 return "top_vertical_left";
659 case Surface.ROTATION_180:
660 return "bottom_left";
661 case Surface.ROTATION_270:
662 return "bottom_vertical_right";
665 case "top_vertical_right":
667 case Surface.ROTATION_0:
668 return "top_vertical_right";
669 case Surface.ROTATION_90:
671 case Surface.ROTATION_180:
672 return "bottom_vertical_left";
673 case Surface.ROTATION_270:
674 return "bottom_right";
683 private static int getMaxNumOfColumns(Context context) {
684 SharedPreferences pref = getSharedPreferences(context);
685 DisplayMetrics metrics = context.getResources().getDisplayMetrics();
686 float baseTaskbarSize = context.getResources().getDimension(pref.getBoolean("dashboard", false) ? R.dimen.base_taskbar_size_dashboard : R.dimen.base_taskbar_size) / metrics.density;
687 int numOfColumns = 0;
689 float maxScreenSize = getTaskbarPosition(context).contains("vertical")
690 ? (metrics.heightPixels - getStatusBarHeight(context)) / metrics.density
691 : metrics.widthPixels / metrics.density;
693 float iconSize = context.getResources().getDimension(R.dimen.icon_size) / metrics.density;
695 int userMaxNumOfColumns = Integer.valueOf(pref.getString("max_num_of_recents", "10"));
697 while(baseTaskbarSize + iconSize < maxScreenSize
698 && numOfColumns < userMaxNumOfColumns) {
699 baseTaskbarSize = baseTaskbarSize + iconSize;
706 public static int getMaxNumOfEntries(Context context) {
707 SharedPreferences pref = getSharedPreferences(context);
708 return pref.getBoolean("disable_scrolling_list", false)
709 ? getMaxNumOfColumns(context)
710 : Integer.valueOf(pref.getString("max_num_of_recents", "10"));
713 public static int getStatusBarHeight(Context context) {
714 int statusBarHeight = 0;
715 int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
717 statusBarHeight = context.getResources().getDimensionPixelSize(resourceId);
719 return statusBarHeight;
722 public static void refreshPinnedIcons(Context context) {
723 IconCache.getInstance(context).clearCache();
725 PinnedBlockedApps pba = PinnedBlockedApps.getInstance(context);
726 List<AppEntry> pinnedAppsList = new ArrayList<>(pba.getPinnedApps());
727 List<AppEntry> blockedAppsList = new ArrayList<>(pba.getBlockedApps());
728 PackageManager pm = context.getPackageManager();
732 for(AppEntry entry : pinnedAppsList) {
733 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
734 LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
736 final List<UserHandle> userHandles = userManager.getUserProfiles();
737 LauncherActivityInfo appInfo = null;
739 for(UserHandle handle : userHandles) {
740 List<LauncherActivityInfo> list = launcherApps.getActivityList(entry.getPackageName(), handle);
741 if(!list.isEmpty()) {
742 // Google App workaround
743 if(!entry.getPackageName().equals("com.google.android.googlequicksearchbox"))
744 appInfo = list.get(0);
746 boolean added = false;
747 for(LauncherActivityInfo info : list) {
748 if(info.getName().equals("com.google.android.googlequicksearchbox.SearchActivity")) {
754 if(!added) appInfo = list.get(0);
761 if(appInfo != null) {
762 AppEntry newEntry = new AppEntry(
763 entry.getPackageName(),
764 entry.getComponentName(),
766 IconCache.getInstance(context).getIcon(context, pm, appInfo),
769 newEntry.setUserId(entry.getUserId(context));
770 pba.addPinnedApp(context, newEntry);
774 for(AppEntry entry : blockedAppsList) {
775 pba.addBlockedApp(context, entry);
779 public static Intent getShortcutIntent(Context context) {
780 Intent shortcutIntent = new Intent(context, ShortcutActivity.class);
781 shortcutIntent.setAction(Intent.ACTION_MAIN);
782 shortcutIntent.putExtra("is_launching_shortcut", true);
784 BitmapDrawable drawable = (BitmapDrawable) context.getDrawable(R.mipmap.ic_freeform_mode);
786 Intent intent = new Intent();
787 intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
788 if(drawable != null) intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, drawable.getBitmap());
789 intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, context.getString(R.string.pref_header_freeform));
794 public static Intent getStartStopIntent(Context context) {
795 Intent shortcutIntent = new Intent(context, StartTaskbarActivity.class);
796 shortcutIntent.setAction(Intent.ACTION_MAIN);
797 shortcutIntent.putExtra("is_launching_shortcut", true);
799 BitmapDrawable drawable = (BitmapDrawable) context.getDrawable(R.mipmap.ic_launcher);
801 Intent intent = new Intent();
802 intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
803 if(drawable != null) intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, drawable.getBitmap());
804 intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, context.getString(R.string.start_taskbar));
809 public static boolean hasFreeformSupport(Context context) {
810 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
811 && (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT)
812 || Settings.Global.getInt(context.getContentResolver(), "enable_freeform_support", -1) == 1
813 || Settings.Global.getInt(context.getContentResolver(), "force_resizable_activities", -1) == 1);
816 public static boolean isServiceRunning(Context context, Class<? extends Service> cls) {
817 return isServiceRunning(context, cls.getName());
820 public static boolean isServiceRunning(Context context, String className) {
821 ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
822 for(ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
823 if(className.equals(service.service.getClassName()))
830 public static int getBackgroundTint(Context context) {
831 SharedPreferences pref = getSharedPreferences(context);
833 // Import old background tint preference
834 if(pref.contains("show_background")) {
835 SharedPreferences.Editor editor = pref.edit();
837 if(!pref.getBoolean("show_background", true))
838 editor.putInt("background_tint", 0).apply();
840 editor.remove("show_background");
844 return pref.getInt("background_tint", context.getResources().getInteger(R.integer.translucent_gray));
847 public static int getAccentColor(Context context) {
848 SharedPreferences pref = getSharedPreferences(context);
849 return pref.getInt("accent_color", context.getResources().getInteger(R.integer.translucent_white));
852 @TargetApi(Build.VERSION_CODES.M)
853 public static boolean canDrawOverlays(Context context) {
854 return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(context);
857 public static boolean isGame(Context context, String packageName) {
858 SharedPreferences pref = getSharedPreferences(context);
859 if(pref.getBoolean("launch_games_fullscreen", true)) {
860 PackageManager pm = context.getPackageManager();
863 ApplicationInfo info = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
864 return (info.flags & ApplicationInfo.FLAG_IS_GAME) != 0 || (info.metaData != null && info.metaData.getBoolean("isGame", false));
865 } catch (PackageManager.NameNotFoundException e) {
872 @TargetApi(Build.VERSION_CODES.M)
873 private static ActivityOptions getActivityOptions(Boolean isGame) {
874 ActivityOptions options = ActivityOptions.makeBasic();
878 Method method = ActivityOptions.class.getMethod("setLaunchStackId", int.class);
879 method.invoke(options, isGame ? FULLSCREEN_WORKSPACE_STACK_ID : FREEFORM_WORKSPACE_STACK_ID);
880 } catch (Exception e) { /* Gracefully fail */ }