OSDN Git Service

9e11be6a5d0a9468b8fc03f1bc71e9bb9e328aad
[android-x86/packages-apps-Taskbar.git] / app / src / main / java / com / farmerbb / taskbar / util / U.java
1 /* Copyright 2016 Braden Farmer
2  *
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
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15
16 package com.farmerbb.taskbar.util;
17
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;
54
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;
67
68 import java.lang.reflect.Method;
69 import java.util.ArrayList;
70 import java.util.List;
71
72 import moe.banana.support.ToastCompat;
73
74 public class U {
75
76     private U() {}
77
78     private static SharedPreferences pref;
79     private static Integer cachedRotation;
80
81     private static final int MAXIMIZED = 0;
82     private static final int LEFT = -1;
83     private static final int RIGHT = 1;
84
85     public static final int HIDDEN = 0;
86     public static final int TOP_APPS = 1;
87
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;
91
92     public static SharedPreferences getSharedPreferences(Context context) {
93         if(pref == null) pref = context.getSharedPreferences(BuildConfig.APPLICATION_ID + "_preferences", Context.MODE_PRIVATE);
94         return pref;
95     }
96
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) -> {
103                     try {
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");
108                     }
109                 });
110
111         AlertDialog dialog = builder.create();
112         dialog.show();
113         dialog.setCancelable(false);
114
115         return dialog;
116     }
117
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);
123
124         AlertDialog dialog = builder.create();
125         dialog.show();
126     }
127
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);
132
133         DevicePolicyManager mDevicePolicyManager = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
134         if(mDevicePolicyManager.isAdminActive(component))
135             mDevicePolicyManager.lockNow();
136         else {
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);
142             });
143         }
144     }
145
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);
150
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);
155         } else {
156             launchApp(context, () -> {
157                 Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
158                 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
159
160                 try {
161                     context.startActivity(intent);
162                     showToastLong(context, R.string.enable_accessibility);
163                 } catch (ActivityNotFoundException e) {
164                     showToast(context, R.string.lock_device_not_supported);
165                 }
166             });
167         }
168     }
169
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);
173
174         return accessibilityServices != null
175                 && (accessibilityServices.contains(component.flattenToString())
176                 || accessibilityServices.contains(component.flattenToShortString()));
177     }
178
179     public static void showToast(Context context, int message) {
180         showToast(context, context.getString(message), Toast.LENGTH_SHORT);
181     }
182
183     public static void showToastLong(Context context, int message) {
184         showToast(context, context.getString(message), Toast.LENGTH_LONG);
185     }
186
187     public static void showToast(Context context, String message, int length) {
188         cancelToast();
189
190         ToastCompat toast = ToastCompat.makeText(context.getApplicationContext(), message, length);
191         toast.show();
192
193         ToastHelper.getInstance().setLastToast(toast);
194     }
195
196     public static void cancelToast() {
197         ToastCompat toast = ToastHelper.getInstance().getLastToast();
198         if(toast != null) toast.cancel();
199     }
200
201     public static void startShortcut(Context context, String packageName, String componentName, ShortcutInfo shortcut) {
202         launchApp(context,
203                 packageName,
204                 componentName,
205                 0,
206                 null,
207                 false,
208                 false,
209                 shortcut);
210     }
211
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) {
218         launchApp(context,
219                 packageName,
220                 componentName,
221                 userId,
222                 windowSize,
223                 launchedFromTaskbar,
224                 openInNewWindow,
225                 null);
226     }
227
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));
237     }
238
239     public static void launchApp(Context context, Runnable runnable) {
240         launchApp(context, true, runnable);
241     }
242
243     private static void launchApp(Context context, boolean launchedFromTaskbar, Runnable runnable) {
244         SharedPreferences pref = getSharedPreferences(context);
245         FreeformHackHelper helper = FreeformHackHelper.getInstance();
246
247         boolean specialLaunch = isOPreview() && FreeformHackHelper.getInstance().isInFreeformWorkspace()
248                 && MenuHelper.getInstance().isContextMenuOpen();
249
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);
255
256                 new Handler().postDelayed(runnable, helper.isFreeformHackActive() ? 0 : 100);
257             }, launchedFromTaskbar ? 0 : 100);
258         } else
259             runnable.run();
260     }
261
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);
267
268         if(checkMultiWindow)
269             freeformHackIntent.putExtra("check_multiwindow", true);
270
271         if(launchedFromTaskbar) {
272             SharedPreferences pref = getSharedPreferences(context);
273             if(pref.getBoolean("disable_animations", false))
274                 freeformHackIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
275         }
276
277         if(canDrawOverlays(context))
278             launchAppLowerRight(context, freeformHackIntent);
279     }
280
281     @TargetApi(Build.VERSION_CODES.N)
282     private static void continueLaunchingApp(Context context,
283                                              String packageName,
284                                              String componentName,
285                                              long userId,
286                                              String windowSize,
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);
297
298         if(FreeformHackHelper.getInstance().isInFreeformWorkspace()
299                 && Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1
300                 && !isOPreview())
301             intent.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME);
302
303         if(launchedFromTaskbar) {
304             if(pref.getBoolean("disable_animations", false))
305                 intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
306         }
307
308         if(openInNewWindow || pref.getBoolean("force_new_window", false)) {
309             intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
310
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);
317                         break;
318                 }
319             }
320         }
321
322         ApplicationType type = getApplicationType(context, packageName);
323
324         if(windowSize == null)
325             windowSize = SavedWindowSizes.getInstance(context).getWindowSize(context, packageName);
326
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) {
332             case "large":
333                 launchMode1(context, intent, userId, shortcut, type);
334                 break;
335             case "fullscreen":
336                 launchMode2(context, intent, MAXIMIZED, userId, shortcut, type);
337                 break;
338             case "half_left":
339                 launchMode2(context, intent, LEFT, userId, shortcut, type);
340                 break;
341             case "half_right":
342                 launchMode2(context, intent, RIGHT, userId, shortcut, type);
343                 break;
344             case "phone_size":
345                 launchMode3(context, intent, userId, shortcut, type);
346                 break;
347         }
348
349         if(pref.getBoolean("hide_taskbar", true) && !FreeformHackHelper.getInstance().isInFreeformWorkspace())
350             LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_TASKBAR"));
351         else
352             LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU"));
353     }
354     
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())) {
360                 try {
361                     context.startActivity(intent, bundle);
362                 } catch (ActivityNotFoundException e) {
363                     launchAndroidForWork(context, intent.getComponent(), bundle, userId);
364                 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
365             } else
366                 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
367         } else
368             launchShortcut(context, shortcut, bundle);
369     }
370
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);
376
377         int width1 = display.getWidth() / 8;
378         int width2 = display.getWidth() - width1;
379         int height1 = display.getHeight() / 8;
380         int height2 = display.getHeight() - height1;
381
382         Bundle bundle = getActivityOptions(type).setLaunchBounds(new Rect(
383                 width1,
384                 height1,
385                 width2,
386                 height2
387         )).toBundle();
388
389         if(shortcut == null) {
390             UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
391             if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
392                 try {
393                     context.startActivity(intent, bundle);
394                 } catch (ActivityNotFoundException e) {
395                     launchAndroidForWork(context, intent.getComponent(), bundle, userId);
396                 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
397             } else
398                 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
399         } else
400             launchShortcut(context, shortcut, bundle);
401     }
402
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);
408
409         int statusBarHeight = getStatusBarHeight(context);
410         String position = getTaskbarPosition(context);
411
412         boolean isPortrait = context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
413         boolean isLandscape = context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
414
415         int left = launchType == RIGHT && isLandscape
416                 ? display.getWidth() / 2
417                 : 0;
418
419         int top = launchType == RIGHT && isPortrait
420                 ? display.getHeight() / 2
421                 : statusBarHeight;
422
423         int right = launchType == LEFT && isLandscape
424                 ? display.getWidth() / 2
425                 : display.getWidth();
426
427         int bottom = launchType == LEFT && isPortrait
428                 ? display.getHeight() / 2
429                 : display.getHeight();
430
431         int iconSize = context.getResources().getDimensionPixelSize(R.dimen.icon_size);
432
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;
442
443         Bundle bundle = getActivityOptions(type).setLaunchBounds(new Rect(
444                 left,
445                 top,
446                 right,
447                 bottom
448         )).toBundle();
449
450         if(shortcut == null) {
451             UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
452             if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
453                 try {
454                     context.startActivity(intent, bundle);
455                 } catch (ActivityNotFoundException e) {
456                     launchAndroidForWork(context, intent.getComponent(), bundle, userId);
457                 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
458             } else
459                 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
460         } else
461             launchShortcut(context, shortcut, bundle);
462     }
463
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);
469
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;
474
475         Bundle bundle = getActivityOptions(type).setLaunchBounds(new Rect(
476                 width1 - width2,
477                 height1 - height2,
478                 width1 + width2,
479                 height1 + height2
480         )).toBundle();
481
482         if(shortcut == null) {
483             UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
484             if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
485                 try {
486                     context.startActivity(intent, bundle);
487                 } catch (ActivityNotFoundException e) {
488                     launchAndroidForWork(context, intent.getComponent(), bundle, userId);
489                 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
490             } else
491                 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
492         } else
493             launchShortcut(context, shortcut, bundle);
494     }
495
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);
499
500         try {
501             launcherApps.startMainActivity(componentName, userManager.getUserForSerialNumber(userId), null, bundle);
502         } catch (ActivityNotFoundException | NullPointerException e) { /* Gracefully fail */ }
503     }
504
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);
508
509         if(launcherApps.hasShortcutHostPermission()) {
510             try {
511                 launcherApps.startShortcut(shortcut, null, bundle);
512             } catch (ActivityNotFoundException | NullPointerException e) { /* Gracefully fail */ }
513         }
514     }
515
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());
519
520         launchMode2(context, intent, MAXIMIZED, userId, null, ApplicationType.CONTEXT_MENU);
521     }
522
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);
528         try {
529             context.startActivity(intent, getActivityOptions(ApplicationType.FREEFORM_HACK).setLaunchBounds(new Rect(
530                     display.getWidth(),
531                     display.getHeight(),
532                     display.getWidth() + 1,
533                     display.getHeight() + 1
534             )).toBundle());
535         } catch (IllegalArgumentException e) { /* Gracefully fail */ }
536     }
537
538     public static void checkForUpdates(Context context) {
539         if(!BuildConfig.DEBUG) {
540             String url;
541             try {
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;
546             }
547
548             Intent intent = new Intent(Intent.ACTION_VIEW);
549             intent.setData(Uri.parse(url));
550             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
551
552             try {
553                 context.startActivity(intent);
554             } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
555         } else
556             showToast(context, R.string.debug_build);
557     }
558
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);
563
564         return defaultLauncher.activityInfo.packageName.equals(BuildConfig.APPLICATION_ID);
565     }
566
567     public static void setCachedRotation(int cachedRotation) {
568         U.cachedRotation = cachedRotation;
569     }
570
571     public static String getTaskbarPosition(Context context) {
572         SharedPreferences pref = getSharedPreferences(context);
573         String position = pref.getString("position", "bottom_left");
574
575         if(pref.getBoolean("anchor", false)) {
576             WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
577             int rotation = cachedRotation != null ? cachedRotation : windowManager.getDefaultDisplay().getRotation();
578
579             switch(position) {
580                 case "bottom_left":
581                     switch(rotation) {
582                         case Surface.ROTATION_0:
583                             return "bottom_left";
584                         case Surface.ROTATION_90:
585                             return "bottom_vertical_right";
586                         case Surface.ROTATION_180:
587                             return "top_right";
588                         case Surface.ROTATION_270:
589                             return "top_vertical_left";
590                     }
591                     break;
592                 case "bottom_vertical_left":
593                     switch(rotation) {
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:
601                             return "top_left";
602                     }
603                     break;
604                 case "bottom_right":
605                     switch(rotation) {
606                         case Surface.ROTATION_0:
607                             return "bottom_right";
608                         case Surface.ROTATION_90:
609                             return "top_vertical_right";
610                         case Surface.ROTATION_180:
611                             return "top_left";
612                         case Surface.ROTATION_270:
613                             return "bottom_vertical_left";
614                     }
615                     break;
616                 case "bottom_vertical_right":
617                     switch(rotation) {
618                         case Surface.ROTATION_0:
619                             return "bottom_vertical_right";
620                         case Surface.ROTATION_90:
621                             return "top_right";
622                         case Surface.ROTATION_180:
623                             return "top_vertical_left";
624                         case Surface.ROTATION_270:
625                             return "bottom_left";
626                     }
627                     break;
628                 case "top_left":
629                     switch(rotation) {
630                         case Surface.ROTATION_0:
631                             return "top_left";
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";
638                     }
639                     break;
640                 case "top_vertical_left":
641                     switch(rotation) {
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:
649                             return "top_right";
650                     }
651                     break;
652                 case "top_right":
653                     switch(rotation) {
654                         case Surface.ROTATION_0:
655                             return "top_right";
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";
662                     }
663                     break;
664                 case "top_vertical_right":
665                     switch(rotation) {
666                         case Surface.ROTATION_0:
667                             return "top_vertical_right";
668                         case Surface.ROTATION_90:
669                             return "top_left";
670                         case Surface.ROTATION_180:
671                             return "bottom_vertical_left";
672                         case Surface.ROTATION_270:
673                             return "bottom_right";
674                     }
675                     break;
676             }
677         }
678
679         return position;
680     }
681
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;
687
688         float maxScreenSize = getTaskbarPosition(context).contains("vertical")
689                 ? (metrics.heightPixels - getStatusBarHeight(context)) / metrics.density
690                 : metrics.widthPixels / metrics.density;
691
692         float iconSize = context.getResources().getDimension(R.dimen.icon_size) / metrics.density;
693
694         int userMaxNumOfColumns = Integer.valueOf(pref.getString("max_num_of_recents", "10"));
695
696         while(baseTaskbarSize + iconSize < maxScreenSize
697                 && numOfColumns < userMaxNumOfColumns) {
698             baseTaskbarSize = baseTaskbarSize + iconSize;
699             numOfColumns++;
700         }
701
702         return numOfColumns;
703     }
704
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"));
710     }
711
712     public static int getStatusBarHeight(Context context) {
713         int statusBarHeight = 0;
714         int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
715         if(resourceId > 0)
716             statusBarHeight = context.getResources().getDimensionPixelSize(resourceId);
717
718         return statusBarHeight;
719     }
720
721     public static void refreshPinnedIcons(Context context) {
722         IconCache.getInstance(context).clearCache();
723
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();
728
729         pba.clear(context);
730
731         for(AppEntry entry : pinnedAppsList) {
732             UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
733             LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
734
735             final List<UserHandle> userHandles = userManager.getUserProfiles();
736             LauncherActivityInfo appInfo = null;
737
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);
744                     else {
745                         boolean added = false;
746                         for(LauncherActivityInfo info : list) {
747                             if(info.getName().equals("com.google.android.googlequicksearchbox.SearchActivity")) {
748                                 appInfo = info;
749                                 added = true;
750                             }
751                         }
752
753                         if(!added) appInfo = list.get(0);
754                     }
755
756                     break;
757                 }
758             }
759
760             if(appInfo != null) {
761                 AppEntry newEntry = new AppEntry(
762                         entry.getPackageName(),
763                         entry.getComponentName(),
764                         entry.getLabel(),
765                         IconCache.getInstance(context).getIcon(context, pm, appInfo),
766                         true);
767
768                 newEntry.setUserId(entry.getUserId(context));
769                 pba.addPinnedApp(context, newEntry);
770             }
771         }
772
773         for(AppEntry entry : blockedAppsList) {
774             pba.addBlockedApp(context, entry);
775         }
776     }
777
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);
782
783         BitmapDrawable drawable = (BitmapDrawable) context.getDrawable(R.mipmap.ic_freeform_mode);
784
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));
789
790         return intent;
791     }
792
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);
797
798         BitmapDrawable drawable = (BitmapDrawable) context.getDrawable(R.mipmap.ic_launcher);
799
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));
804
805         return intent;
806     }
807
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));
814     }
815
816     public static boolean hasPartialFreeformSupport() {
817          return Build.MANUFACTURER.equalsIgnoreCase("Samsung") || isOPreview();
818     }
819
820     public static boolean isServiceRunning(Context context, Class<? extends Service> cls) {
821         return isServiceRunning(context, cls.getName());
822     }
823
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()))
828                 return true;
829         }
830
831         return false;
832     }
833
834     public static int getBackgroundTint(Context context) {
835         SharedPreferences pref = getSharedPreferences(context);
836
837         // Import old background tint preference
838         if(pref.contains("show_background")) {
839             SharedPreferences.Editor editor = pref.edit();
840
841             if(!pref.getBoolean("show_background", true))
842                 editor.putInt("background_tint", 0).apply();
843
844             editor.remove("show_background");
845             editor.apply();
846         }
847
848         return pref.getInt("background_tint", context.getResources().getInteger(R.integer.translucent_gray));
849     }
850
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));
854     }
855
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);
859     }
860
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();
865
866             try {
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) {
870                 return false;
871             }
872         } else
873             return false;
874     }
875
876     @TargetApi(Build.VERSION_CODES.M)
877     public static ActivityOptions getActivityOptions(ApplicationType applicationType) {
878         ActivityOptions options = ActivityOptions.makeBasic();
879         Integer stackId = null;
880
881         switch(applicationType) {
882             case APPLICATION:
883                 if(!FreeformHackHelper.getInstance().isFreeformHackActive())
884                     stackId = FULLSCREEN_WORKSPACE_STACK_ID;
885                 break;
886             case GAME:
887                 stackId = FULLSCREEN_WORKSPACE_STACK_ID;
888                 break;
889             case FREEFORM_HACK:
890                 stackId = FREEFORM_WORKSPACE_STACK_ID;
891                 break;
892             case CONTEXT_MENU:
893                 if(isOPreview()) stackId = FULLSCREEN_WORKSPACE_STACK_ID;
894         }
895
896         if(stackId != null) {
897             try {
898                 Method method = ActivityOptions.class.getMethod("setLaunchStackId", int.class);
899                 method.invoke(options, stackId);
900             } catch (Exception e) { /* Gracefully fail */ }
901         }
902
903         return options;
904     }
905
906     private static ApplicationType getApplicationType(Context context, String packageName) {
907         return isGame(context, packageName) ? ApplicationType.GAME : ApplicationType.APPLICATION;
908     }
909
910     public static boolean isSystemApp(Context context) {
911         try {
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) {
916             return false;
917         }
918     }
919
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);
923     }
924
925     public static boolean hasSupportLibrary(Context context) {
926         PackageManager pm = context.getPackageManager();
927         try {
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) {
933             return false;
934         }
935     }
936
937     public static int getBaseTaskbarSize(Context context) {
938         return Math.round(getBaseTaskbarSizeFloat(context));
939     }
940
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;
945
946         if(pref.getBoolean("dashboard", false))
947             baseTaskbarSize += context.getResources().getDimension(R.dimen.dashboard_button_size);
948
949         if(pref.getBoolean("button_back", false)) {
950             navbarButtonsEnabled = true;
951             baseTaskbarSize += context.getResources().getDimension(R.dimen.icon_size);
952         }
953
954         if(pref.getBoolean("button_home", false)) {
955             navbarButtonsEnabled = true;
956             baseTaskbarSize += context.getResources().getDimension(R.dimen.icon_size);
957         }
958
959         if(pref.getBoolean("button_recents", false)) {
960             navbarButtonsEnabled = true;
961             baseTaskbarSize += context.getResources().getDimension(R.dimen.icon_size);
962         }
963
964         if(navbarButtonsEnabled)
965             baseTaskbarSize += context.getResources().getDimension(R.dimen.navbar_buttons_margin);
966
967         return baseTaskbarSize;
968     }
969
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));
975     }
976
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));
982     }
983
984     public static void restartTaskbar(Context context) {
985         SharedPreferences pref = getSharedPreferences(context);
986         if(pref.getBoolean("taskbar_active", false) && !pref.getBoolean("is_hidden", false)) {
987             pref.edit()
988                     .putBoolean("is_restarting", true)
989                     .putBoolean("skip_auto_hide_navbar", true)
990                     .apply();
991
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();
996
997             stopTaskbarService(context, false);
998             startTaskbarService(context, false);
999         }
1000     }
1001
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();
1006
1007             Intent intent = new Intent(context, NotificationService.class);
1008             context.stopService(intent);
1009             context.startService(intent);
1010         }
1011     }
1012
1013     public static void showHideNavigationBar(Context context, boolean show) {
1014         // Show or hide the system navigation bar on Bliss-x86
1015         try {
1016             Settings.System.putInt(context.getContentResolver(), "navigation_bar_show", show ? 1 : 0);
1017         } catch (Exception e) { /* Gracefully fail */ }
1018     }
1019
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();
1026         }
1027
1028         if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
1029             if(!pref.getBoolean("freeform_hack_override", false)) {
1030                 pref.edit()
1031                         .putBoolean("freeform_hack", hasFreeformSupport(context) && !hasPartialFreeformSupport())
1032                         .putBoolean("save_window_sizes", false)
1033                         .putBoolean("freeform_hack_override", true)
1034                         .apply();
1035             } else if(!hasFreeformSupport(context)) {
1036                 pref.edit().putBoolean("freeform_hack", false).apply();
1037
1038                 LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.FINISH_FREEFORM_ACTIVITY"));
1039             }
1040         }
1041     }
1042 }