From 5174bbf4149b4fdcd2e62a5ebd397bd5ebde6e2f Mon Sep 17 00:00:00 2001 From: Markus Fisch Date: Thu, 11 Apr 2024 22:48:31 +0200 Subject: [PATCH] Add optional app drawer icon to pie menu As an alternative way to open the app listing, instead of tapping the home screen. --- .../activity/PickIconActivity.java | 8 +- .../activity/PreferencesActivity.java | 15 +++ .../android/pielauncher/content/AppMenu.java | 68 ++++++++--- .../pielauncher/graphics/Converter.java | 15 +++ .../android/pielauncher/io/Menu.java | 2 +- .../pielauncher/preference/Preferences.java | 13 +++ .../pielauncher/widget/AppPieView.java | 106 +++++++++++------- app/src/main/res/drawable/ic_drawer.xml | 9 ++ .../main/res/layout/activity_preferences.xml | 4 + app/src/main/res/values-de/strings.xml | 3 + app/src/main/res/values-fr/strings.xml | 3 + app/src/main/res/values-ru/strings.xml | 3 + app/src/main/res/values-sv/strings.xml | 3 + app/src/main/res/values-uk/strings.xml | 3 + app/src/main/res/values-zh-rCN/strings.xml | 3 + app/src/main/res/values/strings.xml | 3 + svg/ic_drawer.svg | 4 + 17 files changed, 206 insertions(+), 59 deletions(-) create mode 100644 app/src/main/res/drawable/ic_drawer.xml create mode 100644 svg/ic_drawer.svg diff --git a/app/src/main/java/de/markusfisch/android/pielauncher/activity/PickIconActivity.java b/app/src/main/java/de/markusfisch/android/pielauncher/activity/PickIconActivity.java index 80e4553..26720dd 100644 --- a/app/src/main/java/de/markusfisch/android/pielauncher/activity/PickIconActivity.java +++ b/app/src/main/java/de/markusfisch/android/pielauncher/activity/PickIconActivity.java @@ -227,8 +227,12 @@ public class PickIconActivity extends Activity { private void initHide(String packageName) { View hideButton = findViewById(R.id.hide_app); - hideButton.setOnClickListener((v) -> askToHide( - this, packageName, this::finish)); + if (PieLauncherApp.appMenu.isDrawerPackageName(packageName)) { + hideButton.setVisibility(View.INVISIBLE); + } else { + hideButton.setOnClickListener((v) -> askToHide( + this, packageName, this::finish)); + } } private void initSwitchPack() { diff --git a/app/src/main/java/de/markusfisch/android/pielauncher/activity/PreferencesActivity.java b/app/src/main/java/de/markusfisch/android/pielauncher/activity/PreferencesActivity.java index 06235b9..abb2d91 100644 --- a/app/src/main/java/de/markusfisch/android/pielauncher/activity/PreferencesActivity.java +++ b/app/src/main/java/de/markusfisch/android/pielauncher/activity/PreferencesActivity.java @@ -158,6 +158,14 @@ public class PreferencesActivity extends Activity { PreferencesActivity::getDeadZoneOptions, () -> prefs.getDeadZone(), (value) -> prefs.setDeadZone(value)); + initPreference(R.id.use_drawer_icon, + R.string.use_drawer_icon, + PreferencesActivity::getUseDrawerIconOptions, + () -> prefs.useDrawerIcon(), + (value) -> { + prefs.setUseDrawerIcon(value); + PieLauncherApp.appMenu.updateIconsAsync(this); + }); initPreference(R.id.display_keyboard, R.string.display_keyboard, PreferencesActivity::getDisplayKeyboardOptions, @@ -372,6 +380,13 @@ public class PreferencesActivity extends Activity { return map; } + private static Map getUseDrawerIconOptions() { + Map map = new LinkedHashMap<>(); + map.put(Boolean.TRUE, R.string.use_drawer_icon_yes); + map.put(Boolean.FALSE, R.string.use_drawer_icon_no); + return map; + } + private static Map getDisplayKeyboardOptions() { Map map = new LinkedHashMap<>(); map.put(Boolean.TRUE, R.string.display_keyboard_yes); diff --git a/app/src/main/java/de/markusfisch/android/pielauncher/content/AppMenu.java b/app/src/main/java/de/markusfisch/android/pielauncher/content/AppMenu.java index ef33fe2..37d69c4 100644 --- a/app/src/main/java/de/markusfisch/android/pielauncher/content/AppMenu.java +++ b/app/src/main/java/de/markusfisch/android/pielauncher/content/AppMenu.java @@ -34,6 +34,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.Executors; +import de.markusfisch.android.pielauncher.R; import de.markusfisch.android.pielauncher.app.PieLauncherApp; import de.markusfisch.android.pielauncher.graphics.CanvasPieMenu; import de.markusfisch.android.pielauncher.graphics.Converter; @@ -84,15 +85,24 @@ public class AppMenu extends CanvasPieMenu { private UpdateListener updateListener; private LauncherApps launcherApps; + private String drawerPackageName; private boolean indexing = false; - public boolean launchSelectedApp(Context context) { - int selectedIcon = getSelectedIcon(); - if (selectedIcon > -1 && selectedIcon < icons.size()) { - launchApp(context, ((AppIcon) icons.get(selectedIcon))); - return true; - } - return false; + public AppIcon getSelectedApp() { + int index = getSelectedIcon(); + return index > -1 && index < icons.size() + ? (AppIcon) icons.get(index) + : null; + } + + public boolean isDrawerIcon(AppIcon icon) { + return icon != null && + isDrawerPackageName(icon.componentName.getPackageName()); + } + + public boolean isDrawerPackageName(String packageName) { + return drawerPackageName != null && + drawerPackageName.equals(packageName); } public void launchApp(Context context, AppIcon icon) { @@ -250,7 +260,8 @@ public class AppMenu extends CanvasPieMenu { userHandleRestriction, hideApps, newApps); - List newIcons = createMenu(context, newApps); + List newIcons = createMenu(context, newApps, + PieLauncherApp.getPrefs(context).useDrawerIcon()); handler.post(() -> { apps.clear(); apps.putAll(newApps); @@ -368,22 +379,51 @@ public class AppMenu extends CanvasPieMenu { } } - private static void addApp(Map allApps, + private static AppIcon addApp(Map allApps, ComponentName componentName, String label, Drawable icon, UserHandle userHandle) { - allApps.put(new LauncherItemKey(componentName, userHandle), - new AppIcon(componentName, label, icon, userHandle)); + AppIcon appIcon = new AppIcon(componentName, label, icon, userHandle); + allApps.put(new LauncherItemKey(componentName, userHandle), appIcon); + return appIcon; } - private static List createMenu(Context context, - Map allApps) { - List menu = Menu.restore(context, allApps); + private List createMenu(Context context, + Map allApps, + boolean useDrawerIcon) { + AppMenu.Icon drawerIcon = useDrawerIcon + ? addDrawerIcon(context, allApps) + : null; + ArrayList menu = Menu.restore(context, allApps); if (menu.isEmpty()) { createInitialMenu(menu, allApps, context.getPackageManager()); } + if (drawerIcon != null) { + if (!menu.contains(drawerIcon)) { + menu.add(0, drawerIcon); + } + removePackageFromApps(allApps, drawerPackageName, null); + } else { + drawerPackageName = null; + } return menu; } + private AppMenu.Icon addDrawerIcon(Context context, + Map allApps) { + String appPackageName = context.getPackageName(); + drawerPackageName = appPackageName + ".drawer"; + Drawable icon = PieLauncherApp.iconPack.getIcon(drawerPackageName); + if (icon == null) { + icon = Converter.getDrawable( + context.getResources(), R.drawable.ic_drawer); + } + return addApp(allApps, + new ComponentName(drawerPackageName, "Drawer"), + "Drawer", + icon, + null); + } + private static void createInitialMenu(List menu, Map allApps, PackageManager pm) { diff --git a/app/src/main/java/de/markusfisch/android/pielauncher/graphics/Converter.java b/app/src/main/java/de/markusfisch/android/pielauncher/graphics/Converter.java index 53aeaf9..601a164 100644 --- a/app/src/main/java/de/markusfisch/android/pielauncher/graphics/Converter.java +++ b/app/src/main/java/de/markusfisch/android/pielauncher/graphics/Converter.java @@ -1,9 +1,11 @@ package de.markusfisch.android.pielauncher.graphics; +import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.os.Build; public class Converter { // Limit the icon size, as some apps incorrectly use too large resources @@ -35,4 +37,17 @@ public class Converter { drawable.draw(canvas); return bitmap; } + + public static Bitmap getBitmapFromDrawable(Resources res, int resId) { + return getBitmapFromDrawable(getDrawable(res, resId)); + } + + public static Drawable getDrawable(Resources res, int resId) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + return res.getDrawable(resId, null); + } else { + //noinspection deprecation + return res.getDrawable(resId); + } + } } diff --git a/app/src/main/java/de/markusfisch/android/pielauncher/io/Menu.java b/app/src/main/java/de/markusfisch/android/pielauncher/io/Menu.java index b702b7f..2affba9 100644 --- a/app/src/main/java/de/markusfisch/android/pielauncher/io/Menu.java +++ b/app/src/main/java/de/markusfisch/android/pielauncher/io/Menu.java @@ -20,7 +20,7 @@ import de.markusfisch.android.pielauncher.graphics.PieMenu; public class Menu { private static final String MENU_FILE = "menu"; - public static List restore(Context context, + public static ArrayList restore(Context context, Map allApps) { ArrayList icons = new ArrayList<>(); try { diff --git a/app/src/main/java/de/markusfisch/android/pielauncher/preference/Preferences.java b/app/src/main/java/de/markusfisch/android/pielauncher/preference/Preferences.java index f4f4a71..928759e 100644 --- a/app/src/main/java/de/markusfisch/android/pielauncher/preference/Preferences.java +++ b/app/src/main/java/de/markusfisch/android/pielauncher/preference/Preferences.java @@ -32,6 +32,7 @@ public class Preferences { private static final String DARKEN_BACKGROUND = "darken_background"; private static final String BLUR_BACKGROUND = "blur_background"; private static final String DEAD_ZONE = "dead_zone"; + private static final String USE_DRAWER_ICON = "use_drawer_icon"; private static final String DISPLAY_KEYBOARD = "display_keyboard"; private static final String DOUBE_SPACE_LAUNCH = "space_action_double_launch"; private static final String AUTO_LAUNCH_MATCHING = "auto_launch_matching"; @@ -51,6 +52,7 @@ public class Preferences { private boolean darkenBackground = false; private boolean blurBackground = false; private int deadZone = DEAD_ZONE_BOTH; + private boolean useDrawerIcon = false; private boolean displayKeyboard = true; private boolean doubleSpaceLaunch = false; private boolean autoLaunchMatching = false; @@ -78,6 +80,8 @@ public class Preferences { blurBackground = preferences.getBoolean(BLUR_BACKGROUND, blurBackground); deadZone = preferences.getInt(DEAD_ZONE, deadZone); + useDrawerIcon = preferences.getBoolean(USE_DRAWER_ICON, + useDrawerIcon); displayKeyboard = preferences.getBoolean(DISPLAY_KEYBOARD, displayKeyboard); doubleSpaceLaunch = preferences.getBoolean(DOUBE_SPACE_LAUNCH, @@ -164,6 +168,15 @@ public class Preferences { put(DEAD_ZONE, deadZone).commit(); } + public boolean useDrawerIcon() { + return useDrawerIcon; + } + + public void setUseDrawerIcon(boolean useDrawerIcon) { + this.useDrawerIcon = useDrawerIcon; + put(USE_DRAWER_ICON, useDrawerIcon).apply(); + } + public boolean displayKeyboard() { return displayKeyboard; } diff --git a/app/src/main/java/de/markusfisch/android/pielauncher/widget/AppPieView.java b/app/src/main/java/de/markusfisch/android/pielauncher/widget/AppPieView.java index 025d7fc..864b85b 100644 --- a/app/src/main/java/de/markusfisch/android/pielauncher/widget/AppPieView.java +++ b/app/src/main/java/de/markusfisch/android/pielauncher/widget/AppPieView.java @@ -10,7 +10,6 @@ import android.graphics.Paint; import android.graphics.Point; import android.graphics.PorterDuff; import android.graphics.Rect; -import android.graphics.drawable.Drawable; import android.os.Build; import android.os.SystemClock; import android.text.TextPaint; @@ -197,14 +196,17 @@ public class AppPieView extends View { textOffset = (textHeight / 2) - paintText.descent(); translucentBackgroundColor = res.getColor(R.color.bg_ui); - iconAdd = getBitmapFromDrawable(res, R.drawable.ic_add); - iconEdit = getBitmapFromDrawable(res, R.drawable.ic_edit); - iconHide = getBitmapFromDrawable(res, R.drawable.ic_hide); - iconRemove = getBitmapFromDrawable(res, R.drawable.ic_remove); - iconDetails = getBitmapFromDrawable(res, R.drawable.ic_details); - iconDone = getBitmapFromDrawable(res, R.drawable.ic_done); - iconPreferences = getBitmapFromDrawable(res, R.drawable.ic_preferences); - iconLaunchFirst = getBitmapFromDrawable(res, + iconAdd = Converter.getBitmapFromDrawable(res, R.drawable.ic_add); + iconEdit = Converter.getBitmapFromDrawable(res, R.drawable.ic_edit); + iconHide = Converter.getBitmapFromDrawable(res, R.drawable.ic_hide); + iconRemove = Converter.getBitmapFromDrawable(res, + R.drawable.ic_remove); + iconDetails = Converter.getBitmapFromDrawable(res, + R.drawable.ic_details); + iconDone = Converter.getBitmapFromDrawable(res, R.drawable.ic_done); + iconPreferences = Converter.getBitmapFromDrawable(res, + R.drawable.ic_preferences); + iconLaunchFirst = Converter.getBitmapFromDrawable(res, R.drawable.ic_launch_first); iconLaunchFirstHalf = iconLaunchFirst.getWidth() >> 1; updateChangeTwistIcon(); @@ -398,19 +400,6 @@ public class AppPieView extends View { return getScrollY(); } - private static Bitmap getBitmapFromDrawable(Resources res, int resId) { - return Converter.getBitmapFromDrawable(getDrawable(res, resId)); - } - - private static Drawable getDrawable(Resources res, int resId) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - return res.getDrawable(resId, null); - } else { - //noinspection deprecation - return res.getDrawable(resId); - } - } - private void initTouchListener() { setOnTouchListener(new OnTouchListener() { private final FlingRunnable flingRunnable = new FlingRunnable(); @@ -977,16 +966,7 @@ public class AppPieView extends View { private boolean performAction(Context context, Point at, boolean wasTap) { if (mode == MODE_PIE && fadePie.isVisible()) { fadeOutMode(); - boolean result = false; - if (wasTap) { - if (listListener != null) { - listListener.onOpenList(false); - } - } else if (PieLauncherApp.appMenu.launchSelectedApp(context)) { - ripple.set(at); - result = true; - } - return result; + return performPieAction(context, at, wasTap); } else if (mode == MODE_LIST && wasTap) { return performListAction(context, at); } else if (mode == MODE_EDIT) { @@ -998,6 +978,31 @@ public class AppPieView extends View { return false; } + private boolean performPieAction(Context context, Point at, + boolean wasTap) { + boolean result = false; + boolean openList = false; + AppMenu.AppIcon appIcon = PieLauncherApp.appMenu.getSelectedApp(); + if (prefs.useDrawerIcon()) { + result = openList = PieLauncherApp.appMenu.isDrawerIcon( + appIcon); + } else if (wasTap) { + openList = true; + } + if (openList) { + if (listListener != null) { + listListener.onOpenList(false); + } + } else if (appIcon != null) { + PieLauncherApp.appMenu.launchApp(context, appIcon); + result = true; + } + if (result) { + ripple.set(at); + } + return result; + } + private boolean performListAction(Context context, Point at) { AppMenu.AppIcon appIcon = getListIconAt(at.x, at.y); if (appIcon != null) { @@ -1047,11 +1052,9 @@ public class AppPieView extends View { ((Activity) context).onBackPressed(); } else { ripple.set(touch); - PieLauncherApp.appMenu.icons.remove(grabbedIcon); - // Undo any rotation if the menu has not otherwise changed. - if (sameOrder(backup, PieLauncherApp.appMenu.icons)) { - rollback(); - } + removeIconFromPie(grabbedIcon, + PieLauncherApp.appMenu.isDrawerIcon( + (AppMenu.AppIcon) grabbedIcon)); } return true; } else if (contains(iconCenterRect, touch)) { @@ -1067,6 +1070,9 @@ public class AppPieView extends View { } if (PieLauncherApp.iconPack.hasPacks()) { changeIcon(context, grabbedIcon); + } else if (PieLauncherApp.appMenu.isDrawerIcon( + (AppMenu.AppIcon) grabbedIcon)) { + removeIconFromPie(grabbedIcon, true); } else { PickIconActivity.askToHide(context, ((AppMenu.AppIcon) grabbedIcon) @@ -1081,14 +1087,30 @@ public class AppPieView extends View { ripple.set(touch); rollback(); fadeOutMode(); - PieLauncherApp.appMenu.launchAppInfo(context, - (AppMenu.AppIcon) grabbedIcon); + if (PieLauncherApp.appMenu.isDrawerIcon( + (AppMenu.AppIcon) grabbedIcon)) { + removeIconFromPie(grabbedIcon, true); + } else { + PieLauncherApp.appMenu.launchAppInfo(context, + (AppMenu.AppIcon) grabbedIcon); + } } return true; } return false; } + private void removeIconFromPie(AppMenu.Icon icon, boolean isDrawerIcon) { + if (isDrawerIcon) { + prefs.setUseDrawerIcon(false); + } + PieLauncherApp.appMenu.icons.remove(icon); + // Undo any rotation if the menu has not otherwise changed. + if (sameOrder(backup, PieLauncherApp.appMenu.icons)) { + rollback(); + } + } + private void rollback() { PieLauncherApp.appMenu.icons.clear(); PieLauncherApp.appMenu.icons.addAll(backup); @@ -1122,7 +1144,7 @@ public class AppPieView extends View { } private void updateChangeTwistIcon() { - iconChangeTwist = getBitmapFromDrawable(getResources(), + iconChangeTwist = Converter.getBitmapFromDrawable(getResources(), getDrawableForTwist(twist)); } @@ -1152,7 +1174,7 @@ public class AppPieView extends View { } private void updateChangeIconScaleIcon() { - iconChangeIconScale = getBitmapFromDrawable(getResources(), + iconChangeIconScale = Converter.getBitmapFromDrawable(getResources(), getDrawableForIconScale(iconScale)); } @@ -1163,7 +1185,7 @@ public class AppPieView extends View { } private void updateChangeRadiusIcon() { - iconChangeRadius = getBitmapFromDrawable(getResources(), + iconChangeRadius = Converter.getBitmapFromDrawable(getResources(), getDrawableForRadius(radius)); } diff --git a/app/src/main/res/drawable/ic_drawer.xml b/app/src/main/res/drawable/ic_drawer.xml new file mode 100644 index 0000000..4ea7821 --- /dev/null +++ b/app/src/main/res/drawable/ic_drawer.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_preferences.xml b/app/src/main/res/layout/activity_preferences.xml index 6f085dc..3261783 100644 --- a/app/src/main/res/layout/activity_preferences.xml +++ b/app/src/main/res/layout/activity_preferences.xml @@ -58,6 +58,10 @@ + Nur Unten Oben und unten (Standard) App Liste + Öffnet durch + Icon in Pie-Menu + Tipp auf den Startbildschirm (Standard) Tastatur automatisch öffnen Ja (Standard) Nein diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 29891b2..b5ea7eb 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -26,6 +26,9 @@ En bas de l\'écran En haut et en bas de l\'écran (d\'usine) Liste d\'apps + Ouvert par + Icône dans le menu + Tapez sur l\'écran d\'accueil (d\'usine) Affichage automatique du clavier Oui (d\'usine) Non diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 00ede6b..72431e2 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -26,6 +26,9 @@ Снизу Сверху и снизу (Стандартно) Список приложений + Открывается через + Иконка в меню + Нажмите на главный экран (Стандартно) Автоматически показывать клавиатуру Да (Стандартно) Нет diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index f6cc18e..452c548 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -26,6 +26,9 @@ Längst ner Högst upp och längst ner (standard) Applåda + Öppnar genom + Ikon i menyn + Tryck på startskärmen (standard) Visa tangentbordet automatiskt Ja (standard) Nej diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 27a94be..26cb3f0 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -26,6 +26,9 @@ Внизу Вгорі і внизу (за замовчуванням) Список додатків + Відкривається через + Іконка в меню + Натисніть на головному екрані (за замовчуванням) Автоматично показувати клавіатуру Так (за замовчуванням) Ні diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index bbbd59f..30427ec 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -26,6 +26,9 @@ 屏幕底部 在屏幕顶部和底部 (默认) 应用程序列表 + 通过 + 菜单中的图标 + 点击主屏幕 (默认) 自动显示键盘 是 (默认) 没有 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 532530e..2818a97 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -26,6 +26,9 @@ At the bottom At the top and bottom (Default) App Drawer + Opens with + Icon in pie menu + Tap on home screen (Default) Show keyboard automatically Yes (Default) No diff --git a/svg/ic_drawer.svg b/svg/ic_drawer.svg new file mode 100644 index 0000000..5bdf078 --- /dev/null +++ b/svg/ic_drawer.svg @@ -0,0 +1,4 @@ + + + +