OSDN Git Service

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