OSDN Git Service

Treat apps launched in freeform mode as being launched from home
[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.DialogInterface;
28 import android.content.Intent;
29 import android.content.SharedPreferences;
30 import android.content.pm.ActivityInfo;
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.receiver.LockDeviceReceiver;
61 import com.farmerbb.taskbar.service.PowerMenuService;
62
63 import java.util.ArrayList;
64 import java.util.List;
65
66 import moe.banana.support.ToastCompat;
67
68 public class U {
69
70     private U() {}
71
72     private static SharedPreferences pref;
73     private static Integer cachedRotation;
74
75     private static final int FULLSCREEN = 0;
76     private static final int LEFT = -1;
77     private static final int RIGHT = 1;
78
79     public static final int HIDDEN = 0;
80     public static final int TOP_APPS = 1;
81
82     public static SharedPreferences getSharedPreferences(Context context) {
83         if(pref == null) pref = context.getSharedPreferences(BuildConfig.APPLICATION_ID + "_preferences", Context.MODE_PRIVATE);
84         return pref;
85     }
86
87     @TargetApi(Build.VERSION_CODES.M)
88     public static void showPermissionDialog(final Context context) {
89         AlertDialog.Builder builder = new AlertDialog.Builder(context);
90         builder.setTitle(R.string.permission_dialog_title)
91                 .setMessage(R.string.permission_dialog_message)
92                 .setPositiveButton(R.string.action_grant_permission, new DialogInterface.OnClickListener() {
93                     @Override
94                     public void onClick(DialogInterface dialog, int which) {
95                         try {
96                             context.startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
97                                     Uri.parse("package:" + BuildConfig.APPLICATION_ID)));
98                         } catch (ActivityNotFoundException e) {
99                             showErrorDialog(context, "SYSTEM_ALERT_WINDOW");
100                         }
101                     }
102                 });
103
104         AlertDialog dialog = builder.create();
105         dialog.show();
106         dialog.setCancelable(false);
107     }
108
109     public static void showErrorDialog(final Context context, String appopCmd) {
110         AlertDialog.Builder builder = new AlertDialog.Builder(context);
111         builder.setTitle(R.string.error_dialog_title)
112                 .setMessage(context.getString(R.string.error_dialog_message, BuildConfig.APPLICATION_ID, appopCmd))
113                 .setPositiveButton(R.string.action_ok, null);
114
115         AlertDialog dialog = builder.create();
116         dialog.show();
117     }
118
119     public static void lockDevice(Context context) {
120         ComponentName component = new ComponentName(context, LockDeviceReceiver.class);
121         context.getPackageManager().setComponentEnabledSetting(component, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
122                 PackageManager.DONT_KILL_APP);
123
124         DevicePolicyManager mDevicePolicyManager = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
125         if(mDevicePolicyManager.isAdminActive(component))
126             mDevicePolicyManager.lockNow();
127         else {
128             Intent intent = new Intent(context, DummyActivity.class);
129             intent.putExtra("device_admin", true);
130             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
131             context.startActivity(intent);
132         }
133     }
134
135     public static void showPowerMenu(Context context) {
136         ComponentName component = new ComponentName(context, PowerMenuService.class);
137         context.getPackageManager().setComponentEnabledSetting(component, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
138                 PackageManager.DONT_KILL_APP);
139
140         if(isAccessibilityServiceEnabled(context))
141             context.startService(new Intent(context, PowerMenuService.class));
142         else {
143             Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
144             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
145
146             try {
147                 context.startActivity(intent);
148                 showToastLong(context, R.string.enable_accessibility);
149             } catch (ActivityNotFoundException e) {
150                 showToast(context, R.string.lock_device_not_supported);
151             }
152         }
153     }
154
155     private static boolean isAccessibilityServiceEnabled(Context context) {
156         String accessibilityServices = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
157         ComponentName component = new ComponentName(context, PowerMenuService.class);
158
159         return accessibilityServices != null
160                 && (accessibilityServices.contains(component.flattenToString())
161                 || accessibilityServices.contains(component.flattenToShortString()));
162     }
163
164     public static void showToast(Context context, int message) {
165         showToast(context, context.getString(message), Toast.LENGTH_SHORT);
166     }
167
168     public static void showToastLong(Context context, int message) {
169         showToast(context, context.getString(message), Toast.LENGTH_LONG);
170     }
171
172     public static void showToast(Context context, String message, int length) {
173         ToastCompat.makeText(context, message, length).show();
174     }
175
176     public static void startShortcut(Context context, String packageName, String componentName, ShortcutInfo shortcut) {
177         launchApp(context,
178                 packageName,
179                 componentName,
180                 0,
181                 null,
182                 false,
183                 false,
184                 shortcut);
185     }
186
187     public static void launchApp(final Context context,
188                                  final String packageName,
189                                  final String componentName,
190                                  final long userId, final String windowSize,
191                                  final boolean launchedFromTaskbar,
192                                  final boolean openInNewWindow) {
193         launchApp(context,
194                 packageName,
195                 componentName,
196                 userId,
197                 windowSize,
198                 launchedFromTaskbar,
199                 openInNewWindow,
200                 null);
201     }
202
203     private static void launchApp(final Context context,
204                                  final String packageName,
205                                  final String componentName,
206                                  final long userId, final String windowSize,
207                                  final boolean launchedFromTaskbar,
208                                  final boolean openInNewWindow,
209                                  final ShortcutInfo shortcut) {
210         boolean shouldDelay = false;
211
212         SharedPreferences pref = getSharedPreferences(context);
213         boolean openInFullscreen = pref.getBoolean("open_in_fullscreen", true);
214         boolean freeformHackActive = openInNewWindow
215                 ? FreeformHackHelper.getInstance().isInFreeformWorkspace()
216                 : (openInFullscreen
217                     ? FreeformHackHelper.getInstance().isInFreeformWorkspace()
218                     : FreeformHackHelper.getInstance().isFreeformHackActive());
219
220         if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
221                 && pref.getBoolean("freeform_hack", false)
222                 && !freeformHackActive) {
223             shouldDelay = true;
224
225             new Handler().postDelayed(new Runnable() {
226                 @Override
227                 public void run() {
228                     startFreeformHack(context, true, launchedFromTaskbar);
229
230                     new Handler().postDelayed(new Runnable() {
231                         @Override
232                         public void run() {
233                             continueLaunchingApp(context, packageName, componentName, userId,
234                                     windowSize, launchedFromTaskbar, openInNewWindow, shortcut);
235                         }
236                     }, 100);
237                 }
238             }, launchedFromTaskbar ? 0 : 100);
239         }
240
241         if(!FreeformHackHelper.getInstance().isFreeformHackActive()) {
242             if(!shouldDelay)
243                 continueLaunchingApp(context, packageName, componentName, userId,
244                         windowSize, launchedFromTaskbar, openInNewWindow, shortcut);
245         } else if(FreeformHackHelper.getInstance().isInFreeformWorkspace() || !openInFullscreen)
246             continueLaunchingApp(context, packageName, componentName, userId,
247                     windowSize, launchedFromTaskbar, openInNewWindow, shortcut);
248     }
249
250     @SuppressWarnings("deprecation")
251     @TargetApi(Build.VERSION_CODES.N)
252     public static void startFreeformHack(Context context, boolean checkMultiWindow, boolean launchedFromTaskbar) {
253         Intent freeformHackIntent = new Intent(context, InvisibleActivityFreeform.class);
254         freeformHackIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
255
256         if(checkMultiWindow)
257             freeformHackIntent.putExtra("check_multiwindow", true);
258
259         if(launchedFromTaskbar) {
260             SharedPreferences pref = getSharedPreferences(context);
261             if(pref.getBoolean("disable_animations", false))
262                 freeformHackIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
263         }
264
265         DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
266         Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
267         try {
268             context.startActivity(freeformHackIntent, ActivityOptions.makeBasic().setLaunchBounds(new Rect(
269                     display.getWidth(),
270                     display.getHeight(),
271                     display.getWidth() + 1,
272                     display.getHeight() + 1
273             )).toBundle());
274         } catch (IllegalArgumentException e) { /* Gracefully fail */ }
275     }
276
277     @TargetApi(Build.VERSION_CODES.N)
278     private static void continueLaunchingApp(Context context,
279                                              String packageName,
280                                              String componentName,
281                                              long userId,
282                                              String windowSize,
283                                              boolean launchedFromTaskbar,
284                                              boolean openInNewWindow,
285                                              ShortcutInfo shortcut) {
286         SharedPreferences pref = getSharedPreferences(context);
287         Intent intent = new Intent();
288         intent.setComponent(ComponentName.unflattenFromString(componentName));
289         intent.setAction(Intent.ACTION_MAIN);
290         intent.addCategory(Intent.CATEGORY_LAUNCHER);
291         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
292         intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
293
294         if(FreeformHackHelper.getInstance().isInFreeformWorkspace())
295             intent.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME);
296
297         if(launchedFromTaskbar) {
298             if(pref.getBoolean("disable_animations", false))
299                 intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
300         }
301
302         if(openInNewWindow || pref.getBoolean("force_new_window", false)) {
303             intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
304
305             ActivityInfo activityInfo = intent.resolveActivityInfo(context.getPackageManager(), 0);
306             if(activityInfo != null) {
307                 switch(activityInfo.launchMode) {
308                     case ActivityInfo.LAUNCH_SINGLE_TASK:
309                     case ActivityInfo.LAUNCH_SINGLE_INSTANCE:
310                         intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
311                         break;
312                 }
313             }
314         }
315
316         if(windowSize == null) {
317             if(pref.getBoolean("save_window_sizes", true))
318                 windowSize = SavedWindowSizes.getInstance(context).getWindowSize(context, packageName);
319             else
320                 windowSize = pref.getString("window_size", "standard");
321         }
322
323         if(Build.VERSION.SDK_INT < Build.VERSION_CODES.N || !pref.getBoolean("freeform_hack", false)) {
324             if(shortcut == null) {
325                 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
326                 if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
327                     try {
328                         context.startActivity(intent, null);
329                     } catch (ActivityNotFoundException e) {
330                         launchAndroidForWork(context, intent.getComponent(), null, userId);
331                     } catch (IllegalArgumentException e) { /* Gracefully fail */ }
332                 } else
333                     launchAndroidForWork(context, intent.getComponent(), null, userId);
334             } else
335                 launchShortcut(context, shortcut, null);
336         } else switch(windowSize) {
337             case "standard":
338                 if(FreeformHackHelper.getInstance().isInFreeformWorkspace()) {
339                     if(shortcut == null) {
340                         UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
341                         if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
342                             try {
343                                 context.startActivity(intent);
344                             } catch (ActivityNotFoundException e) {
345                                 launchAndroidForWork(context, intent.getComponent(), null, userId);
346                             } catch (IllegalArgumentException e) { /* Gracefully fail */ }
347                         } else
348                             launchAndroidForWork(context, intent.getComponent(), null, userId);
349                     } else
350                         launchShortcut(context, shortcut, null);
351                 } else
352                     launchMode1(context, intent, 1, userId, shortcut);
353                 break;
354             case "large":
355                 launchMode1(context, intent, 2, userId, shortcut);
356                 break;
357             case "fullscreen":
358                 launchMode2(context, intent, FULLSCREEN, userId, shortcut);
359                 break;
360             case "half_left":
361                 launchMode2(context, intent, LEFT, userId, shortcut);
362                 break;
363             case "half_right":
364                 launchMode2(context, intent, RIGHT, userId, shortcut);
365                 break;
366             case "phone_size":
367                 launchMode3(context, intent, userId, shortcut);
368                 break;
369         }
370
371         if(pref.getBoolean("hide_taskbar", true) && !FreeformHackHelper.getInstance().isInFreeformWorkspace())
372             LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_TASKBAR"));
373         else
374             LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU"));
375     }
376     
377     @SuppressWarnings("deprecation")
378     @TargetApi(Build.VERSION_CODES.N)
379     private static void launchMode1(Context context, Intent intent, int factor, long userId, ShortcutInfo shortcut) {
380         DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
381         Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
382
383         int width1 = display.getWidth() / (4 * factor);
384         int width2 = display.getWidth() - width1;
385         int height1 = display.getHeight() / (4 * factor);
386         int height2 = display.getHeight() - height1;
387
388         Bundle bundle = ActivityOptions.makeBasic().setLaunchBounds(new Rect(
389                 width1,
390                 height1,
391                 width2,
392                 height2
393         )).toBundle();
394
395         if(shortcut == null) {
396             UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
397             if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
398                 try {
399                     context.startActivity(intent, bundle);
400                 } catch (ActivityNotFoundException e) {
401                     launchAndroidForWork(context, intent.getComponent(), bundle, userId);
402                 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
403             } else
404                 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
405         } else
406             launchShortcut(context, shortcut, bundle);
407     }
408
409     @SuppressWarnings("deprecation")
410     @TargetApi(Build.VERSION_CODES.N)
411     private static void launchMode2(Context context, Intent intent, int launchType, long userId, ShortcutInfo shortcut) {
412         DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
413         Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
414
415         int statusBarHeight = getStatusBarHeight(context);
416         String position = getTaskbarPosition(context);
417
418         boolean isPortrait = context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
419         boolean isLandscape = context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
420
421         int left = launchType == RIGHT && isLandscape
422                 ? display.getWidth() / 2
423                 : 0;
424
425         int top = launchType == RIGHT && isPortrait
426                 ? display.getHeight() / 2
427                 : statusBarHeight;
428
429         int right = launchType == LEFT && isLandscape
430                 ? display.getWidth() / 2
431                 : display.getWidth();
432
433         int bottom = launchType == LEFT && isPortrait
434                 ? display.getHeight() / 2
435                 : display.getHeight();
436
437         int iconSize = context.getResources().getDimensionPixelSize(R.dimen.icon_size);
438
439         if(position.contains("vertical_left")) {
440             if(launchType != RIGHT || isPortrait) left = left + iconSize;
441         } else if(position.contains("vertical_right")) {
442             if(launchType != LEFT || isPortrait) right = right - iconSize;
443         } else if(position.contains("bottom")) {
444             if(isLandscape || (launchType != LEFT && isPortrait))
445                 bottom = bottom - iconSize;
446         } else if(isLandscape || (launchType != RIGHT && isPortrait))
447             top = top + iconSize;
448
449         Bundle bundle = ActivityOptions.makeBasic().setLaunchBounds(new Rect(
450                 left,
451                 top,
452                 right,
453                 bottom
454         )).toBundle();
455
456         if(shortcut == null) {
457             UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
458             if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
459                 try {
460                     context.startActivity(intent, bundle);
461                 } catch (ActivityNotFoundException e) {
462                     launchAndroidForWork(context, intent.getComponent(), bundle, userId);
463                 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
464             } else
465                 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
466         } else
467             launchShortcut(context, shortcut, bundle);
468     }
469
470     @SuppressWarnings("deprecation")
471     @TargetApi(Build.VERSION_CODES.N)
472     private static void launchMode3(Context context, Intent intent, long userId, ShortcutInfo shortcut) {
473         DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
474         Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
475
476         int width1 = display.getWidth() / 2;
477         int width2 = context.getResources().getDimensionPixelSize(R.dimen.phone_size_width) / 2;
478         int height1 = display.getHeight() / 2;
479         int height2 = context.getResources().getDimensionPixelSize(R.dimen.phone_size_height) / 2;
480
481         Bundle bundle = ActivityOptions.makeBasic().setLaunchBounds(new Rect(
482                 width1 - width2,
483                 height1 - height2,
484                 width1 + width2,
485                 height1 + height2
486         )).toBundle();
487
488         if(shortcut == null) {
489             UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
490             if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
491                 try {
492                     context.startActivity(intent, bundle);
493                 } catch (ActivityNotFoundException e) {
494                     launchAndroidForWork(context, intent.getComponent(), bundle, userId);
495                 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
496             } else
497                 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
498         } else
499             launchShortcut(context, shortcut, bundle);
500     }
501
502     private static void launchAndroidForWork(Context context, ComponentName componentName, Bundle bundle, long userId) {
503         UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
504         LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
505
506         try {
507             launcherApps.startMainActivity(componentName, userManager.getUserForSerialNumber(userId), null, bundle);
508         } catch (ActivityNotFoundException | NullPointerException e) { /* Gracefully fail */ }
509     }
510
511     @TargetApi(Build.VERSION_CODES.N_MR1)
512     private static void launchShortcut(Context context, ShortcutInfo shortcut, Bundle bundle) {
513         LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
514
515         try {
516             launcherApps.startShortcut(shortcut, null, bundle);
517         } catch (ActivityNotFoundException | NullPointerException e) { /* Gracefully fail */ }
518     }
519
520     public static void launchAppFullscreen(Context context, Intent intent) {
521         UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
522         long userId = userManager.getSerialNumberForUser(Process.myUserHandle());
523
524         launchMode2(context, intent, FULLSCREEN, userId, null);
525     }
526
527     public static void checkForUpdates(Context context) {
528         String url;
529         try {
530             context.getPackageManager().getPackageInfo("com.android.vending", 0);
531             url = "https://play.google.com/store/apps/details?id=" + BuildConfig.APPLICATION_ID;
532         } catch (PackageManager.NameNotFoundException e) {
533             url = "https://f-droid.org/repository/browse/?fdid=" + BuildConfig.BASE_APPLICATION_ID;
534         }
535
536         Intent intent = new Intent(Intent.ACTION_VIEW);
537         intent.setData(Uri.parse(url));
538         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
539
540         try {
541             context.startActivity(intent);
542         } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
543     }
544
545     public static boolean launcherIsDefault(Context context) {
546         Intent homeIntent = new Intent(Intent.ACTION_MAIN);
547         homeIntent.addCategory(Intent.CATEGORY_HOME);
548         ResolveInfo defaultLauncher = context.getPackageManager().resolveActivity(homeIntent, PackageManager.MATCH_DEFAULT_ONLY);
549
550         return defaultLauncher.activityInfo.packageName.equals(BuildConfig.APPLICATION_ID);
551     }
552
553     public static void setCachedRotation(int cachedRotation) {
554         U.cachedRotation = cachedRotation;
555     }
556
557     public static String getTaskbarPosition(Context context) {
558         SharedPreferences pref = getSharedPreferences(context);
559         String position = pref.getString("position", "bottom_left");
560
561         if(pref.getBoolean("anchor", false)) {
562             WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
563             int rotation = cachedRotation != null ? cachedRotation : windowManager.getDefaultDisplay().getRotation();
564
565             switch(position) {
566                 case "bottom_left":
567                     switch(rotation) {
568                         case Surface.ROTATION_0:
569                             return "bottom_left";
570                         case Surface.ROTATION_90:
571                             return "bottom_vertical_right";
572                         case Surface.ROTATION_180:
573                             return "top_right";
574                         case Surface.ROTATION_270:
575                             return "top_vertical_left";
576                     }
577                     break;
578                 case "bottom_vertical_left":
579                     switch(rotation) {
580                         case Surface.ROTATION_0:
581                             return "bottom_vertical_left";
582                         case Surface.ROTATION_90:
583                             return "bottom_right";
584                         case Surface.ROTATION_180:
585                             return "top_vertical_right";
586                         case Surface.ROTATION_270:
587                             return "top_left";
588                     }
589                     break;
590                 case "bottom_right":
591                     switch(rotation) {
592                         case Surface.ROTATION_0:
593                             return "bottom_right";
594                         case Surface.ROTATION_90:
595                             return "top_vertical_right";
596                         case Surface.ROTATION_180:
597                             return "top_left";
598                         case Surface.ROTATION_270:
599                             return "bottom_vertical_left";
600                     }
601                     break;
602                 case "bottom_vertical_right":
603                     switch(rotation) {
604                         case Surface.ROTATION_0:
605                             return "bottom_vertical_right";
606                         case Surface.ROTATION_90:
607                             return "top_right";
608                         case Surface.ROTATION_180:
609                             return "top_vertical_left";
610                         case Surface.ROTATION_270:
611                             return "bottom_left";
612                     }
613                     break;
614                 case "top_left":
615                     switch(rotation) {
616                         case Surface.ROTATION_0:
617                             return "top_left";
618                         case Surface.ROTATION_90:
619                             return "bottom_vertical_left";
620                         case Surface.ROTATION_180:
621                             return "bottom_right";
622                         case Surface.ROTATION_270:
623                             return "top_vertical_right";
624                     }
625                     break;
626                 case "top_vertical_left":
627                     switch(rotation) {
628                         case Surface.ROTATION_0:
629                             return "top_vertical_left";
630                         case Surface.ROTATION_90:
631                             return "bottom_left";
632                         case Surface.ROTATION_180:
633                             return "bottom_vertical_right";
634                         case Surface.ROTATION_270:
635                             return "top_right";
636                     }
637                     break;
638                 case "top_right":
639                     switch(rotation) {
640                         case Surface.ROTATION_0:
641                             return "top_right";
642                         case Surface.ROTATION_90:
643                             return "top_vertical_left";
644                         case Surface.ROTATION_180:
645                             return "bottom_left";
646                         case Surface.ROTATION_270:
647                             return "bottom_vertical_right";
648                     }
649                     break;
650                 case "top_vertical_right":
651                     switch(rotation) {
652                         case Surface.ROTATION_0:
653                             return "top_vertical_right";
654                         case Surface.ROTATION_90:
655                             return "top_left";
656                         case Surface.ROTATION_180:
657                             return "bottom_vertical_left";
658                         case Surface.ROTATION_270:
659                             return "bottom_right";
660                     }
661                     break;
662             }
663         }
664
665         return position;
666     }
667
668     private static int getMaxNumOfColumns(Context context) {
669         SharedPreferences pref = getSharedPreferences(context);
670         DisplayMetrics metrics = context.getResources().getDisplayMetrics();
671         float baseTaskbarSize = context.getResources().getDimension(pref.getBoolean("dashboard", false) ? R.dimen.base_taskbar_size_dashboard : R.dimen.base_taskbar_size) / metrics.density;
672         int numOfColumns = 0;
673
674         float maxScreenSize = getTaskbarPosition(context).contains("vertical")
675                 ? (metrics.heightPixels - getStatusBarHeight(context)) / metrics.density
676                 : metrics.widthPixels / metrics.density;
677
678         float iconSize = context.getResources().getDimension(R.dimen.icon_size) / metrics.density;
679
680         int userMaxNumOfColumns = Integer.valueOf(pref.getString("max_num_of_recents", "10"));
681
682         while(baseTaskbarSize + iconSize < maxScreenSize
683                 && numOfColumns < userMaxNumOfColumns) {
684             baseTaskbarSize = baseTaskbarSize + iconSize;
685             numOfColumns++;
686         }
687
688         return numOfColumns;
689     }
690
691     public static int getMaxNumOfEntries(Context context) {
692         SharedPreferences pref = getSharedPreferences(context);
693         return pref.getBoolean("disable_scrolling_list", false)
694                 ? getMaxNumOfColumns(context)
695                 : Integer.valueOf(pref.getString("max_num_of_recents", "10"));
696     }
697
698     public static int getStatusBarHeight(Context context) {
699         int statusBarHeight = 0;
700         int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
701         if(resourceId > 0)
702             statusBarHeight = context.getResources().getDimensionPixelSize(resourceId);
703
704         return statusBarHeight;
705     }
706
707     public static void refreshPinnedIcons(Context context) {
708         IconCache.getInstance(context).clearCache();
709
710         PinnedBlockedApps pba = PinnedBlockedApps.getInstance(context);
711         List<AppEntry> pinnedAppsList = new ArrayList<>(pba.getPinnedApps());
712         List<AppEntry> blockedAppsList = new ArrayList<>(pba.getBlockedApps());
713         PackageManager pm = context.getPackageManager();
714
715         pba.clear(context);
716
717         for(AppEntry entry : pinnedAppsList) {
718             UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
719             LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
720
721             final List<UserHandle> userHandles = userManager.getUserProfiles();
722             LauncherActivityInfo appInfo = null;
723
724             for(UserHandle handle : userHandles) {
725                 List<LauncherActivityInfo> list = launcherApps.getActivityList(entry.getPackageName(), handle);
726                 if(!list.isEmpty()) {
727                     // Google App workaround
728                     if(!entry.getPackageName().equals("com.google.android.googlequicksearchbox"))
729                         appInfo = list.get(0);
730                     else {
731                         boolean added = false;
732                         for(LauncherActivityInfo info : list) {
733                             if(info.getName().equals("com.google.android.googlequicksearchbox.SearchActivity")) {
734                                 appInfo = info;
735                                 added = true;
736                             }
737                         }
738
739                         if(!added) appInfo = list.get(0);
740                     }
741
742                     break;
743                 }
744             }
745
746             if(appInfo != null) {
747                 AppEntry newEntry = new AppEntry(
748                         entry.getPackageName(),
749                         entry.getComponentName(),
750                         entry.getLabel(),
751                         IconCache.getInstance(context).getIcon(context, pm, appInfo),
752                         true);
753
754                 newEntry.setUserId(entry.getUserId(context));
755                 pba.addPinnedApp(context, newEntry);
756             }
757         }
758
759         for(AppEntry entry : blockedAppsList) {
760             pba.addBlockedApp(context, entry);
761         }
762     }
763
764     public static Intent getShortcutIntent(Context context) {
765         Intent shortcutIntent = new Intent(context, ShortcutActivity.class);
766         shortcutIntent.setAction(Intent.ACTION_MAIN);
767         shortcutIntent.putExtra("is_launching_shortcut", true);
768
769         BitmapDrawable drawable = (BitmapDrawable) context.getDrawable(R.mipmap.ic_freeform_mode);
770
771         Intent intent = new Intent();
772         intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
773         if(drawable != null) intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, drawable.getBitmap());
774         intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, context.getString(R.string.pref_header_freeform));
775
776         return intent;
777     }
778
779     public static boolean hasFreeformSupport(Context context) {
780         return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
781                 && (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT)
782                 || Settings.Global.getInt(context.getContentResolver(), "enable_freeform_support", -1) == 1
783                 || Settings.Global.getInt(context.getContentResolver(), "force_resizable_activities", -1) == 1);
784     }
785
786     public static boolean isServiceRunning(Context context, Class<? extends Service> cls) {
787         ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
788         for(ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
789             if(cls.getName().equals(service.service.getClassName()))
790                 return true;
791         }
792
793         return false;
794     }
795
796     public static int getBackgroundTint(Context context) {
797         SharedPreferences pref = getSharedPreferences(context);
798
799         // Import old background tint preference
800         if(pref.contains("show_background")) {
801             SharedPreferences.Editor editor = pref.edit();
802
803             if(!pref.getBoolean("show_background", true))
804                 editor.putInt("background_tint", 0).apply();
805
806             editor.remove("show_background");
807             editor.apply();
808         }
809
810         return pref.getInt("background_tint", context.getResources().getInteger(R.integer.translucent_gray));
811     }
812
813     public static int getAccentColor(Context context) {
814         SharedPreferences pref = getSharedPreferences(context);
815         return pref.getInt("accent_color", context.getResources().getInteger(R.integer.translucent_white));
816     }
817 }