1 /* Copyright 2016 Braden Farmer
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 package com.farmerbb.taskbar.util;
18 import android.annotation.TargetApi;
19 import android.app.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.res.Configuration;
34 import android.graphics.Rect;
35 import android.graphics.drawable.BitmapDrawable;
36 import android.hardware.display.DisplayManager;
37 import android.net.Uri;
38 import android.os.Build;
39 import android.os.Bundle;
40 import android.os.Handler;
41 import android.os.Process;
42 import android.os.UserHandle;
43 import android.os.UserManager;
44 import android.provider.Settings;
45 import android.support.v4.content.LocalBroadcastManager;
46 import android.util.DisplayMetrics;
47 import android.view.Display;
48 import android.view.Surface;
49 import android.view.WindowManager;
50 import android.widget.Toast;
52 import com.farmerbb.taskbar.BuildConfig;
53 import com.farmerbb.taskbar.R;
54 import com.farmerbb.taskbar.activity.DummyActivity;
55 import com.farmerbb.taskbar.activity.InvisibleActivityFreeform;
56 import com.farmerbb.taskbar.activity.ShortcutActivity;
57 import com.farmerbb.taskbar.receiver.LockDeviceReceiver;
59 import java.util.ArrayList;
60 import java.util.List;
66 private static SharedPreferences pref;
67 private static Toast toast;
68 private static Integer cachedRotation;
70 private static final int FULLSCREEN = 0;
71 private static final int LEFT = -1;
72 private static final int RIGHT = 1;
74 public static final int HIDDEN = 0;
75 public static final int TOP_APPS = 1;
77 public static SharedPreferences getSharedPreferences(Context context) {
78 if(pref == null) pref = context.getSharedPreferences(BuildConfig.APPLICATION_ID + "_preferences", Context.MODE_PRIVATE);
82 @TargetApi(Build.VERSION_CODES.M)
83 public static void showPermissionDialog(final Context context) {
84 AlertDialog.Builder builder = new AlertDialog.Builder(context);
85 builder.setTitle(R.string.permission_dialog_title)
86 .setMessage(R.string.permission_dialog_message)
87 .setPositiveButton(R.string.action_grant_permission, new DialogInterface.OnClickListener() {
89 public void onClick(DialogInterface dialog, int which) {
91 context.startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION));
92 } catch (ActivityNotFoundException e) {
93 showErrorDialog(context, "SYSTEM_ALERT_WINDOW");
98 AlertDialog dialog = builder.create();
100 dialog.setCancelable(false);
103 public static void showErrorDialog(final Context context, String appopCmd) {
104 AlertDialog.Builder builder = new AlertDialog.Builder(context);
105 builder.setTitle(R.string.error_dialog_title)
106 .setMessage(context.getString(R.string.error_dialog_message, BuildConfig.APPLICATION_ID, appopCmd))
107 .setPositiveButton(R.string.action_ok, null);
109 AlertDialog dialog = builder.create();
113 public static void lockDevice(Context context) {
114 ComponentName component = new ComponentName(BuildConfig.APPLICATION_ID, LockDeviceReceiver.class.getName());
115 context.getPackageManager().setComponentEnabledSetting(component, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
116 PackageManager.DONT_KILL_APP);
118 DevicePolicyManager mDevicePolicyManager = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
119 if(mDevicePolicyManager.isAdminActive(component))
120 mDevicePolicyManager.lockNow();
122 Intent intent = new Intent(context, DummyActivity.class);
123 intent.putExtra("device_admin", true);
124 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
125 context.startActivity(intent);
129 public static void showToast(Context context, int message) {
130 showToast(context, context.getString(message), Toast.LENGTH_SHORT);
133 public static void showToastLong(Context context, int message) {
134 showToast(context, context.getString(message), Toast.LENGTH_LONG);
137 public static void showToast(Context context, String message, int length) {
138 if(toast != null) toast.cancel();
140 toast = Toast.makeText(context, message, length);
144 public static void launchApp(final Context context,
145 final String packageName,
146 final String componentName,
147 final long userId, final String windowSize,
148 final boolean launchedFromTaskbar,
149 final boolean padStatusBar,
150 final boolean openInNewWindow) {
151 boolean shouldDelay = false;
153 SharedPreferences pref = getSharedPreferences(context);
154 boolean openInFullscreen = pref.getBoolean("open_in_fullscreen", true);
155 boolean freeformHackActive = openInNewWindow
156 ? FreeformHackHelper.getInstance().isInFreeformWorkspace()
158 ? FreeformHackHelper.getInstance().isInFreeformWorkspace()
159 : FreeformHackHelper.getInstance().isFreeformHackActive());
161 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
162 && pref.getBoolean("freeform_hack", false)
163 && !freeformHackActive) {
166 new Handler().postDelayed(new Runnable() {
169 startFreeformHack(context, launchedFromTaskbar);
171 new Handler().postDelayed(new Runnable() {
174 continueLaunchingApp(context, packageName, componentName, userId,
175 windowSize, launchedFromTaskbar, padStatusBar, openInNewWindow);
179 }, launchedFromTaskbar ? 0 : 100);
182 if(!FreeformHackHelper.getInstance().isFreeformHackActive()) {
184 continueLaunchingApp(context, packageName, componentName, userId,
185 windowSize, launchedFromTaskbar, padStatusBar, openInNewWindow);
186 } else if(FreeformHackHelper.getInstance().isInFreeformWorkspace() || !openInFullscreen)
187 continueLaunchingApp(context, packageName, componentName, userId,
188 windowSize, launchedFromTaskbar, padStatusBar, openInNewWindow);
191 @SuppressWarnings("deprecation")
192 @TargetApi(Build.VERSION_CODES.N)
193 public static void startFreeformHack(Context context, boolean launchedFromTaskbar) {
194 Intent freeformHackIntent = new Intent(context, InvisibleActivityFreeform.class);
195 freeformHackIntent.putExtra("check_multiwindow", true);
196 freeformHackIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
198 if(launchedFromTaskbar) {
199 SharedPreferences pref = getSharedPreferences(context);
200 if(pref.getBoolean("disable_animations", false))
201 freeformHackIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
204 DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
205 Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
207 context.startActivity(freeformHackIntent, ActivityOptions.makeBasic().setLaunchBounds(new Rect(
210 display.getWidth() + 1,
211 display.getHeight() + 1
213 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
216 @TargetApi(Build.VERSION_CODES.N)
217 private static void continueLaunchingApp(Context context,
219 String componentName,
222 boolean launchedFromTaskbar,
223 boolean padStatusBar,
224 boolean openInNewWindow) {
225 SharedPreferences pref = getSharedPreferences(context);
226 Intent intent = new Intent();
227 intent.setComponent(ComponentName.unflattenFromString(componentName));
228 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
229 intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
231 if(launchedFromTaskbar) {
232 if(pref.getBoolean("disable_animations", false))
233 intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
236 if(openInNewWindow) {
237 intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
239 ActivityInfo activityInfo = intent.resolveActivityInfo(context.getPackageManager(), 0);
240 if(activityInfo != null) {
241 switch(activityInfo.launchMode) {
242 case ActivityInfo.LAUNCH_SINGLE_TASK:
243 case ActivityInfo.LAUNCH_SINGLE_INSTANCE:
244 intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
250 if(windowSize == null) {
251 if(pref.getBoolean("save_window_sizes", true))
252 windowSize = SavedWindowSizes.getInstance(context).getWindowSize(context, packageName);
254 windowSize = pref.getString("window_size", "standard");
257 if(Build.VERSION.SDK_INT < Build.VERSION_CODES.N || !pref.getBoolean("freeform_hack", false)) {
258 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
259 if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
261 context.startActivity(intent, null);
262 } catch (ActivityNotFoundException e) {
263 launchAndroidForWork(context, intent.getComponent(), null, userId);
264 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
266 launchAndroidForWork(context, intent.getComponent(), null, userId);
267 } else switch(windowSize) {
269 if(FreeformHackHelper.getInstance().isInFreeformWorkspace()) {
270 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
271 if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
273 context.startActivity(intent);
274 } catch (ActivityNotFoundException e) {
275 launchAndroidForWork(context, intent.getComponent(), null, userId);
276 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
278 launchAndroidForWork(context, intent.getComponent(), null, userId);
280 launchMode1(context, intent, 1, userId);
283 launchMode1(context, intent, 2, userId);
286 launchMode2(context, intent, padStatusBar, FULLSCREEN, userId);
289 launchMode2(context, intent, padStatusBar, LEFT, userId);
292 launchMode2(context, intent, padStatusBar, RIGHT, userId);
295 launchMode3(context, intent, userId);
299 if(pref.getBoolean("hide_taskbar", true) && !FreeformHackHelper.getInstance().isInFreeformWorkspace())
300 LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_TASKBAR"));
302 LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.farmerbb.taskbar.HIDE_START_MENU"));
305 @SuppressWarnings("deprecation")
306 @TargetApi(Build.VERSION_CODES.N)
307 private static void launchMode1(Context context, Intent intent, int factor, long userId) {
308 DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
309 Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
311 int width1 = display.getWidth() / (4 * factor);
312 int width2 = display.getWidth() - width1;
313 int height1 = display.getHeight() / (4 * factor);
314 int height2 = display.getHeight() - height1;
316 Bundle bundle = ActivityOptions.makeBasic().setLaunchBounds(new Rect(
323 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
324 if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
326 context.startActivity(intent, bundle);
327 } catch (ActivityNotFoundException e) {
328 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
329 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
331 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
334 @SuppressWarnings("deprecation")
335 @TargetApi(Build.VERSION_CODES.N)
336 private static void launchMode2(Context context, Intent intent, boolean padStatusBar, int launchType, long userId) {
337 DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
338 Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
340 int statusBarHeight = getStatusBarHeight(context);
342 String position = getTaskbarPosition(context);
343 boolean overridePad = position.equals("top_left") || position.equals("top_right");
345 boolean isPortrait = context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
346 boolean isLandscape = context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
348 int left = launchType == RIGHT && isLandscape
349 ? display.getWidth() / 2
353 if(launchType == RIGHT && isPortrait) {
354 top = (display.getHeight() / 2)
355 + (!padStatusBar && overridePad ? statusBarHeight / 2 : 0)
356 + (!padStatusBar && !overridePad ? statusBarHeight / 2 : 0);
358 top = padStatusBar || overridePad ? statusBarHeight : 0;
361 int right = launchType == LEFT && isLandscape
362 ? display.getWidth() / 2
363 : display.getWidth();
366 if(launchType == LEFT && isPortrait) {
367 bottom = display.getHeight() / 2
368 + (!padStatusBar && overridePad ? statusBarHeight / 2 : 0)
369 - (!padStatusBar && !overridePad ? statusBarHeight / 2 : 0);
371 bottom = display.getHeight()
372 + ((!padStatusBar && overridePad) || (!padStatusBar && launchType == RIGHT && isPortrait)
377 int iconSize = context.getResources().getDimensionPixelSize(R.dimen.icon_size);
379 if(position.contains("vertical_left")) {
380 if(launchType != RIGHT || isPortrait) left = left + iconSize;
381 } else if(position.contains("vertical_right")) {
382 if(launchType != LEFT || isPortrait) right = right - iconSize;
383 } else if(position.contains("bottom")) {
384 if(isLandscape || (launchType != LEFT && isPortrait))
385 bottom = bottom - iconSize;
386 } else if(isLandscape || (launchType != RIGHT && isPortrait))
387 top = top + iconSize;
389 Bundle bundle = ActivityOptions.makeBasic().setLaunchBounds(new Rect(
396 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
397 if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
399 context.startActivity(intent, bundle);
400 } catch (ActivityNotFoundException e) {
401 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
402 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
404 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
407 @SuppressWarnings("deprecation")
408 @TargetApi(Build.VERSION_CODES.N)
409 private static void launchMode3(Context context, Intent intent, long userId) {
410 DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
411 Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
413 int width1 = display.getWidth() / 2;
414 int width2 = context.getResources().getDimensionPixelSize(R.dimen.phone_size_width) / 2;
415 int height1 = display.getHeight() / 2;
416 int height2 = context.getResources().getDimensionPixelSize(R.dimen.phone_size_height) / 2;
418 Bundle bundle = ActivityOptions.makeBasic().setLaunchBounds(new Rect(
425 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
426 if(userId == userManager.getSerialNumberForUser(Process.myUserHandle())) {
428 context.startActivity(intent, bundle);
429 } catch (ActivityNotFoundException e) {
430 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
431 } catch (IllegalArgumentException e) { /* Gracefully fail */ }
433 launchAndroidForWork(context, intent.getComponent(), bundle, userId);
436 private static void launchAndroidForWork(Context context, ComponentName componentName, Bundle bundle, long userId) {
437 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
438 LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
440 launcherApps.startMainActivity(componentName, userManager.getUserForSerialNumber(userId), null, bundle);
443 public static void checkForUpdates(Context context) {
446 context.getPackageManager().getPackageInfo("com.android.vending", 0);
447 url = "https://play.google.com/store/apps/details?id=" + BuildConfig.APPLICATION_ID;
448 } catch (PackageManager.NameNotFoundException e) {
449 url = "https://f-droid.org/repository/browse/?fdid=" + BuildConfig.BASE_APPLICATION_ID;
452 Intent intent = new Intent(Intent.ACTION_VIEW);
453 intent.setData(Uri.parse(url));
454 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
457 context.startActivity(intent);
458 } catch (ActivityNotFoundException e) { /* Gracefully fail */ }
461 public static boolean launcherIsDefault(Context context) {
462 Intent homeIntent = new Intent(Intent.ACTION_MAIN);
463 homeIntent.addCategory(Intent.CATEGORY_HOME);
464 ResolveInfo defaultLauncher = context.getPackageManager().resolveActivity(homeIntent, PackageManager.MATCH_DEFAULT_ONLY);
466 return defaultLauncher.activityInfo.packageName.equals(BuildConfig.APPLICATION_ID);
469 public static void setCachedRotation(int cachedRotation) {
470 U.cachedRotation = cachedRotation;
473 public static String getTaskbarPosition(Context context) {
474 SharedPreferences pref = getSharedPreferences(context);
475 String position = pref.getString("position", "bottom_left");
477 if(pref.getBoolean("anchor", false)) {
478 WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
479 int rotation = cachedRotation != null ? cachedRotation : windowManager.getDefaultDisplay().getRotation();
484 case Surface.ROTATION_0:
485 return "bottom_left";
486 case Surface.ROTATION_90:
487 return "bottom_vertical_right";
488 case Surface.ROTATION_180:
490 case Surface.ROTATION_270:
491 return "top_vertical_left";
494 case "bottom_vertical_left":
496 case Surface.ROTATION_0:
497 return "bottom_vertical_left";
498 case Surface.ROTATION_90:
499 return "bottom_right";
500 case Surface.ROTATION_180:
501 return "top_vertical_right";
502 case Surface.ROTATION_270:
508 case Surface.ROTATION_0:
509 return "bottom_right";
510 case Surface.ROTATION_90:
511 return "top_vertical_right";
512 case Surface.ROTATION_180:
514 case Surface.ROTATION_270:
515 return "bottom_vertical_left";
518 case "bottom_vertical_right":
520 case Surface.ROTATION_0:
521 return "bottom_vertical_right";
522 case Surface.ROTATION_90:
524 case Surface.ROTATION_180:
525 return "top_vertical_left";
526 case Surface.ROTATION_270:
527 return "bottom_left";
532 case Surface.ROTATION_0:
534 case Surface.ROTATION_90:
535 return "bottom_vertical_left";
536 case Surface.ROTATION_180:
537 return "bottom_right";
538 case Surface.ROTATION_270:
539 return "top_vertical_right";
542 case "top_vertical_left":
544 case Surface.ROTATION_0:
545 return "top_vertical_left";
546 case Surface.ROTATION_90:
547 return "bottom_left";
548 case Surface.ROTATION_180:
549 return "bottom_vertical_right";
550 case Surface.ROTATION_270:
556 case Surface.ROTATION_0:
558 case Surface.ROTATION_90:
559 return "top_vertical_left";
560 case Surface.ROTATION_180:
561 return "bottom_left";
562 case Surface.ROTATION_270:
563 return "bottom_vertical_right";
566 case "top_vertical_right":
568 case Surface.ROTATION_0:
569 return "top_vertical_right";
570 case Surface.ROTATION_90:
572 case Surface.ROTATION_180:
573 return "bottom_vertical_left";
574 case Surface.ROTATION_270:
575 return "bottom_right";
584 public static int getMaxNumOfColumns(Context context) {
585 // The base Taskbar size without any recent apps added.
586 // Someday this might be automatically calculated, but today is not that day.
587 float baseTaskbarSize = 92;
588 int numOfColumns = 0;
590 DisplayMetrics metrics = context.getResources().getDisplayMetrics();
591 float maxScreenSize = getTaskbarPosition(context).contains("vertical")
592 ? (metrics.heightPixels - getStatusBarHeight(context)) / metrics.density
593 : metrics.widthPixels / metrics.density;
595 float iconSize = context.getResources().getDimension(R.dimen.icon_size) / metrics.density;
597 SharedPreferences pref = getSharedPreferences(context);
598 int userMaxNumOfColumns = Integer.valueOf(pref.getString("max_num_of_recents", "10"));
600 while(baseTaskbarSize + iconSize < maxScreenSize
601 && numOfColumns < userMaxNumOfColumns) {
602 baseTaskbarSize = baseTaskbarSize + iconSize;
609 public static int getMaxNumOfEntries(Context context) {
610 SharedPreferences pref = getSharedPreferences(context);
611 return pref.getBoolean("disable_scrolling_list", false)
612 ? getMaxNumOfColumns(context)
613 : Integer.valueOf(pref.getString("max_num_of_recents", "10"));
616 public static int getStatusBarHeight(Context context) {
617 int statusBarHeight = 0;
618 int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
620 statusBarHeight = context.getResources().getDimensionPixelSize(resourceId);
622 return statusBarHeight;
625 public static void refreshPinnedIcons(Context context) {
626 IconCache.getInstance(context).clearCache();
628 PinnedBlockedApps pba = PinnedBlockedApps.getInstance(context);
629 List<AppEntry> pinnedAppsList = new ArrayList<>(pba.getPinnedApps());
630 List<AppEntry> blockedAppsList = new ArrayList<>(pba.getBlockedApps());
631 PackageManager pm = context.getPackageManager();
635 for(AppEntry entry : pinnedAppsList) {
636 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
637 LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
639 final List<UserHandle> userHandles = userManager.getUserProfiles();
640 LauncherActivityInfo appInfo = null;
642 for(UserHandle handle : userHandles) {
643 List<LauncherActivityInfo> list = launcherApps.getActivityList(entry.getPackageName(), handle);
644 if(!list.isEmpty()) {
645 appInfo = list.get(0);
650 if(appInfo != null) {
651 AppEntry newEntry = new AppEntry(
652 entry.getPackageName(),
653 entry.getComponentName(),
655 IconCache.getInstance(context).getIcon(context, pm, appInfo),
658 newEntry.setUserId(entry.getUserId(context));
659 pba.addPinnedApp(context, newEntry);
663 for(AppEntry entry : blockedAppsList) {
664 pba.addBlockedApp(context, entry);
668 public static Intent getShortcutIntent(Context context) {
669 Intent shortcutIntent = new Intent(context, ShortcutActivity.class);
670 shortcutIntent.setAction(Intent.ACTION_MAIN);
671 shortcutIntent.putExtra("is_launching_shortcut", true);
673 BitmapDrawable drawable = (BitmapDrawable) context.getDrawable(R.mipmap.ic_freeform_mode);
675 Intent intent = new Intent();
676 intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
677 if(drawable != null) intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, drawable.getBitmap());
678 intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, context.getString(R.string.pref_header_freeform));
683 public static boolean hasFreeformSupport(Context context) {
684 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
685 && (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT)
686 || Settings.Global.getInt(context.getContentResolver(), "enable_freeform_support", -1) == 1
687 || Settings.Global.getInt(context.getContentResolver(), "force_resizable_activities", -1) == 1);