Loading .idea/deploymentTargetDropDown.xml +6 −6 Original line number Diff line number Diff line <?xml version="1.0" encoding="UTF-8"?> <project version="4"> <component name="deploymentTargetDropDown"> <runningDeviceTargetSelectedWithDropDown> <targetSelectedWithDropDown> <Target> <type value="RUNNING_DEVICE_TARGET" /> <type value="QUICK_BOOT_TARGET" /> <deviceKey> <Key> <type value="SERIAL_NUMBER" /> <value value="ZF65256BV3" /> <type value="VIRTUAL_DEVICE_PATH" /> <value value="$USER_HOME$/.android/avd/Pixel_3a_XL_API_29.avd" /> </Key> </deviceKey> </Target> </runningDeviceTargetSelectedWithDropDown> <timeTargetWasSelectedWithDropDown value="2021-09-30T08:05:54.967084Z" /> </targetSelectedWithDropDown> <timeTargetWasSelectedWithDropDown value="2021-09-30T08:57:06.401616Z" /> </component> </project> No newline at end of file app/src/main/AndroidManifest.xml +1 −1 Original line number Diff line number Diff line Loading @@ -90,7 +90,7 @@ </intent-filter> </activity> <activity android:name=".features.shortcuts.AddItemActivity" android:name=".features.test.dragndrop.AddItemActivity" android:autoRemoveFromRecents="true" android:excludeFromRecents="true" android:label="@string/action_add_to_workspace" Loading app/src/main/java/foundation/e/blisslauncher/core/Utilities.java +23 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.PowerManager; Loading Loading @@ -589,4 +590,26 @@ public class Utilities { float progress = getProgress(t, fromMin, fromMax); return mapRange(interpolator.getInterpolation(progress), toMin, toMax); } /** * Returns true if the intent is a valid launch intent for a launcher activity of an app. * This is used to identify shortcuts which are different from the ones exposed by the * applications' manifest file. * * @param launchIntent The intent that will be launched when the shortcut is clicked. */ public static boolean isLauncherAppTarget(Intent launchIntent) { if (launchIntent != null && Intent.ACTION_MAIN.equals(launchIntent.getAction()) && launchIntent.getComponent() != null && launchIntent.getCategories() != null && launchIntent.getCategories().size() == 1 && launchIntent.hasCategory(Intent.CATEGORY_LAUNCHER) && TextUtils.isEmpty(launchIntent.getDataString())) { // An app target can either have no extra or have ItemInfo.EXTRA_PROFILE. Bundle extras = launchIntent.getExtras(); return extras == null || extras.keySet().isEmpty(); } return false; } } app/src/main/java/foundation/e/blisslauncher/core/customviews/LauncherPagedView.java +280 −12 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ import static foundation.e.blisslauncher.features.test.dragndrop.DragLayer.ALPHA import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.LayoutTransition; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; Loading @@ -14,6 +15,7 @@ import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.app.WallpaperManager; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Paint; import android.graphics.Point; Loading @@ -23,6 +25,7 @@ import android.os.UserHandle; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.util.MutableInt; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; Loading @@ -31,6 +34,7 @@ import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.OvershootInterpolator; import android.widget.GridLayout; import android.widget.Toast; import foundation.e.blisslauncher.BuildConfig; Loading @@ -51,6 +55,9 @@ import foundation.e.blisslauncher.core.utils.IntegerArray; import foundation.e.blisslauncher.core.utils.PackageUserKey; import foundation.e.blisslauncher.features.launcher.Hotseat; import foundation.e.blisslauncher.features.notification.FolderDotInfo; import foundation.e.blisslauncher.features.shortcuts.DeepShortcutManager; import foundation.e.blisslauncher.features.shortcuts.InstallShortcutReceiver; import foundation.e.blisslauncher.features.shortcuts.ShortcutKey; import foundation.e.blisslauncher.features.test.Alarm; import foundation.e.blisslauncher.features.test.CellLayout; import foundation.e.blisslauncher.features.test.IconTextView; Loading @@ -62,6 +69,7 @@ import foundation.e.blisslauncher.features.test.VariantDeviceProfile; import foundation.e.blisslauncher.features.test.WorkspaceStateTransitionAnimation; import foundation.e.blisslauncher.features.test.anim.AnimatorSetBuilder; import foundation.e.blisslauncher.features.test.anim.Interpolators; import foundation.e.blisslauncher.features.test.anim.PropertyListBuilder; import foundation.e.blisslauncher.features.test.dragndrop.DragController; import foundation.e.blisslauncher.features.test.dragndrop.DragOptions; import foundation.e.blisslauncher.features.test.dragndrop.DragSource; Loading @@ -71,8 +79,11 @@ import foundation.e.blisslauncher.features.test.dragndrop.SpringLoadedDragContro import foundation.e.blisslauncher.features.test.graphics.DragPreviewProvider; import foundation.e.blisslauncher.features.test.uninstall.UninstallHelper; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Predicate; import org.jetbrains.annotations.NotNull; Loading Loading @@ -116,6 +127,12 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V final static float MAX_SWIPE_ANGLE = (float) Math.PI / 3; final static float TOUCH_SLOP_DAMPING_FACTOR = 4; // How long to wait before the new-shortcut animation automatically pans the workspace private static final int NEW_APPS_PAGE_MOVE_DELAY = 500; private static final int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5; static final int NEW_APPS_ANIMATION_DELAY = 500; private static final float BOUNCE_ANIMATION_TENSION = 1.3f; private final static Paint sPaint = new Paint(); Runnable mRemoveEmptyScreenRunnable; Loading Loading @@ -176,6 +193,11 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V private Alarm wobbleExpireAlarm = new Alarm(); private static final int WOBBLE_EXPIRATION_TIMEOUT = 25000; /** * Map of ShortcutKey to the number of times it is pinned. */ public final Map<ShortcutKey, MutableInt> pinnedShortcutCounts = new HashMap<>(); public LauncherPagedView(Context context, AttributeSet attributeSet) { this(context, attributeSet, 0); } Loading Loading @@ -297,8 +319,14 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V } } public void bindItems(@NotNull List<? extends LauncherItem> launcherItems) { for (LauncherItem launcherItem : launcherItems) { public void bindItems( @NotNull List<? extends LauncherItem> launcherItems, boolean animateIcons ) { final Collection<Animator> bounceAnims = new ArrayList<>(); int newItemsScreenId = -1; for (int i = 0; i < launcherItems.size(); i++) { LauncherItem launcherItem = launcherItems.get(i); IconTextView appView = (IconTextView) LayoutInflater.from(getContext()) .inflate(R.layout.app_icon, null, false); appView.applyFromShortcutItem(launcherItem); Loading @@ -317,7 +345,6 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V iconLayoutParams.width = mLauncher.getDeviceProfile().getCellWidthPx(); appView.setLayoutParams(iconLayoutParams); appView.setTextVisibility(true); addInScreenFromBind(appView, launcherItem); } else if (launcherItem.container == Constants.CONTAINER_HOTSEAT) { GridLayout.Spec rowSpec = GridLayout.spec(GridLayout.UNDEFINED); GridLayout.Spec colSpec = GridLayout.spec(GridLayout.UNDEFINED); Loading @@ -326,11 +353,254 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V iconLayoutParams.height = mLauncher.getDeviceProfile().getHotseatCellHeightPx(); iconLayoutParams.width = mLauncher.getDeviceProfile().getCellWidthPx(); appView.setLayoutParams(iconLayoutParams); } addInScreenFromBind(appView, launcherItem); if (animateIcons) { // Animate all the applications up now appView.setAlpha(0f); appView.setScaleX(0f); appView.setScaleY(0f); bounceAnims.add(createNewAppBounceAnimation(appView, i)); newItemsScreenId = launcherItem.screenId; } } // Animate to the correct page if (animateIcons && newItemsScreenId > -1) { AnimatorSet anim = new AnimatorSet(); anim.playTogether(bounceAnims); int currentScreenId = getScreenIdForPageIndex(getNextPage()); final int newScreenIndex = getPageIndexForScreenId(newItemsScreenId); final Runnable startBounceAnimRunnable = anim::start; if (newItemsScreenId != currentScreenId) { // We post the animation slightly delayed to prevent slowdowns // when we are loading right after we return to launcher. this.postDelayed((Runnable) () -> { AbstractFloatingView.closeAllOpenViews(mLauncher, false); snapToPage(newScreenIndex); postDelayed( startBounceAnimRunnable, NEW_APPS_ANIMATION_DELAY ); }, NEW_APPS_PAGE_MOVE_DELAY); } else { postDelayed(startBounceAnimRunnable, NEW_APPS_ANIMATION_DELAY); } } requestLayout(); } public void bindItemsAdded(@NotNull List<? extends LauncherItem> items) { final ArrayList<LauncherItem> addedItemsFinal = new ArrayList<>(); final IntegerArray addedWorkspaceScreensFinal = new IntegerArray(); List<LauncherItem> filteredItems = new ArrayList<>(); for (LauncherItem item : items) { if (item.itemType == Constants.ITEM_TYPE_APPLICATION || item.itemType == Constants.ITEM_TYPE_SHORTCUT ) { // Short-circuit this logic if the icon exists somewhere on the workspace if (shortcutExists(item.getIntent(), item.user.getRealHandle())) { continue; } } if (item != null) { filteredItems.add(item); } } for (LauncherItem item : filteredItems) { // Find appropriate space for the item. int[] coords = findSpaceForItem(addedWorkspaceScreensFinal); int screenId = coords[0]; LauncherItem itemInfo; if (item instanceof ApplicationItem || item instanceof ShortcutItem || item instanceof FolderItem) { itemInfo = item; itemInfo.screenId = screenId; itemInfo.cell = coords[1]; itemInfo.container = Constants.CONTAINER_DESKTOP; } else { throw new RuntimeException("Unexpected info type"); } if(item.itemType == Constants.ITEM_TYPE_SHORTCUT) { // Increment the count for the given shortcut ShortcutKey pinnedShortcut = ShortcutKey.fromItem((ShortcutItem) item); MutableInt count = pinnedShortcutCounts.get(pinnedShortcut); if (count == null) { count = new MutableInt(1); pinnedShortcutCounts.put(pinnedShortcut, count); } else { count.value++; } // Since this is a new item, pin the shortcut in the system server. if (count.value == 1) { DeepShortcutManager.getInstance(getContext()).pinShortcut(pinnedShortcut); } } // Save the WorkspaceItemInfo for binding in the workspace addedItemsFinal.add(itemInfo); } if (!addedItemsFinal.isEmpty()) { final ArrayList<LauncherItem> addAnimated = new ArrayList<>(); final ArrayList<LauncherItem> addNotAnimated = new ArrayList<>(); if (!addedItemsFinal.isEmpty()) { LauncherItem info = addedItemsFinal.get(addedItemsFinal.size() - 1); int lastScreenId = info.screenId; for (LauncherItem i : addedItemsFinal) { if (i.screenId == lastScreenId) { addAnimated.add(i); } else { addNotAnimated.add(i); } } } if (!addedWorkspaceScreensFinal.isEmpty()) { bindScreens(addedWorkspaceScreensFinal); } // We add the items without animation on non-visible pages, and with // animations on the new page (which we will try and snap to). if (addNotAnimated != null && !addNotAnimated.isEmpty()) { bindItems(addNotAnimated, false); } if (addAnimated != null && !addAnimated.isEmpty()) { bindItems(addAnimated, true); } // Remove the extra empty screen removeExtraEmptyScreen(false, false); updateDatabase(getWorkspaceAndHotseatCellLayouts()); } } private int[] findSpaceForItem(IntegerArray addedWorkspaceScreensFinal) { // Find appropriate space for the item. int screenId = 0; int cell = 0; boolean found = false; int screenCount = getChildCount(); for (int screen = 0; screen < screenCount; screen++) { View child = getChildAt(screen); if (child instanceof CellLayout) { CellLayout cellLayout = (CellLayout) child; int index = mWorkspaceScreens.indexOfValue(cellLayout); screenId = mWorkspaceScreens.keyAt(index); if (cellLayout.getChildCount() < cellLayout.getMaxChildCount()) { found = true; cell = cellLayout.getChildCount(); break; } } } if (!found) { screenId = screenId + 1; addedWorkspaceScreensFinal.add(screenId); cell = 0; } return new int[]{screenId, cell}; } /** * Returns true if the shortcuts already exists on the workspace. This must be called after * the workspace has been loaded. We identify a shortcut by its intent. */ protected boolean shortcutExists(Intent intent, UserHandle user) { final String compPkgName, intentWithPkg, intentWithoutPkg; if (intent == null) { // Skip items with null intents return true; } if (intent.getComponent() != null) { // If component is not null, an intent with null package will produce // the same result and should also be a match. compPkgName = intent.getComponent().getPackageName(); if (intent.getPackage() != null) { intentWithPkg = intent.toUri(0); intentWithoutPkg = new Intent(intent).setPackage(null).toUri(0); } else { intentWithPkg = new Intent(intent).setPackage(compPkgName).toUri(0); intentWithoutPkg = intent.toUri(0); } } else { compPkgName = null; intentWithPkg = intent.toUri(0); intentWithoutPkg = intent.toUri(0); } boolean isLauncherAppTarget = Utilities.isLauncherAppTarget(intent); for (CellLayout layout : getWorkspaceAndHotseatCellLayouts()) { // map over all the shortcuts on the workspace final int itemCount = layout.getChildCount(); for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) { View item = layout.getChildAt(itemIdx); LauncherItem info = (LauncherItem) item.getTag(); if (info instanceof FolderItem) { FolderItem folder = (FolderItem) info; List<LauncherItem> folderChildren = folder.items; // map over all the children in the folder final int childCount = folder.items.size(); for (int childIdx = 0; childIdx < childCount; childIdx++) { LauncherItem childItem = folderChildren.get(childIdx); if (childItem.getIntent() != null && childItem.user.equals(user)) { Intent copyIntent = new Intent(childItem.getIntent()); copyIntent.setSourceBounds(intent.getSourceBounds()); String s = copyIntent.toUri(0); if (intentWithPkg.equals(s) || intentWithoutPkg.equals(s)) { return true; } // checking for existing promise icon with same package name if (isLauncherAppTarget && childItem.getTargetComponent() != null && compPkgName != null && compPkgName .equals(childItem.getTargetComponent().getPackageName())) { return true; } } } } else { if (info.getIntent() != null && info.user.equals(user)) { Intent copyIntent = new Intent(info.getIntent()); copyIntent.setSourceBounds(intent.getSourceBounds()); String s = copyIntent.toUri(0); if (intentWithPkg.equals(s) || intentWithoutPkg.equals(s)) { return true; } // checking for existing promise icon with same package name if (isLauncherAppTarget && info.getTargetComponent() != null && compPkgName != null && compPkgName.equals(info.getTargetComponent().getPackageName())) { return true; } } } } } return false; } private ValueAnimator createNewAppBounceAnimation(View v, int i) { ValueAnimator bounceAnim = new PropertyListBuilder().alpha(1).scale(1).build(v) .setDuration(InstallShortcutReceiver.NEW_SHORTCUT_BOUNCE_DURATION); bounceAnim.setStartDelay(i * InstallShortcutReceiver.NEW_SHORTCUT_STAGGER_DELAY); bounceAnim.setInterpolator(new OvershootInterpolator(BOUNCE_ANIMATION_TENSION)); return bounceAnim; } public GridLayout insertNewWorkspaceScreen(int screenId) { return insertNewWorkspaceScreen(screenId, getChildCount()); } Loading Loading @@ -637,7 +907,7 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V return indexOfChild(mWorkspaceScreens.get(screenId)); } public long getScreenIdForPageIndex(int index) { public int getScreenIdForPageIndex(int index) { if (0 <= index && index < mScreenOrder.size()) { return mScreenOrder.get(index); } Loading Loading @@ -2466,8 +2736,6 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V computeScrollHelper(false); } public interface ItemOperator { /** * Process the next itemInfo, possibly with side-effect on the next item. Loading app/src/main/java/foundation/e/blisslauncher/core/executors/MainThreadExecutor.java +0 −7 Original line number Diff line number Diff line package foundation.e.blisslauncher.core.executors; import android.os.Handler; import android.os.Looper; import androidx.annotation.NonNull; import java.util.List; import java.util.concurrent.AbstractExecutorService; import java.util.concurrent.TimeUnit; public class MainThreadExecutor extends LooperExecutor { public MainThreadExecutor() { super(Looper.getMainLooper()); } } Loading
.idea/deploymentTargetDropDown.xml +6 −6 Original line number Diff line number Diff line <?xml version="1.0" encoding="UTF-8"?> <project version="4"> <component name="deploymentTargetDropDown"> <runningDeviceTargetSelectedWithDropDown> <targetSelectedWithDropDown> <Target> <type value="RUNNING_DEVICE_TARGET" /> <type value="QUICK_BOOT_TARGET" /> <deviceKey> <Key> <type value="SERIAL_NUMBER" /> <value value="ZF65256BV3" /> <type value="VIRTUAL_DEVICE_PATH" /> <value value="$USER_HOME$/.android/avd/Pixel_3a_XL_API_29.avd" /> </Key> </deviceKey> </Target> </runningDeviceTargetSelectedWithDropDown> <timeTargetWasSelectedWithDropDown value="2021-09-30T08:05:54.967084Z" /> </targetSelectedWithDropDown> <timeTargetWasSelectedWithDropDown value="2021-09-30T08:57:06.401616Z" /> </component> </project> No newline at end of file
app/src/main/AndroidManifest.xml +1 −1 Original line number Diff line number Diff line Loading @@ -90,7 +90,7 @@ </intent-filter> </activity> <activity android:name=".features.shortcuts.AddItemActivity" android:name=".features.test.dragndrop.AddItemActivity" android:autoRemoveFromRecents="true" android:excludeFromRecents="true" android:label="@string/action_add_to_workspace" Loading
app/src/main/java/foundation/e/blisslauncher/core/Utilities.java +23 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.PowerManager; Loading Loading @@ -589,4 +590,26 @@ public class Utilities { float progress = getProgress(t, fromMin, fromMax); return mapRange(interpolator.getInterpolation(progress), toMin, toMax); } /** * Returns true if the intent is a valid launch intent for a launcher activity of an app. * This is used to identify shortcuts which are different from the ones exposed by the * applications' manifest file. * * @param launchIntent The intent that will be launched when the shortcut is clicked. */ public static boolean isLauncherAppTarget(Intent launchIntent) { if (launchIntent != null && Intent.ACTION_MAIN.equals(launchIntent.getAction()) && launchIntent.getComponent() != null && launchIntent.getCategories() != null && launchIntent.getCategories().size() == 1 && launchIntent.hasCategory(Intent.CATEGORY_LAUNCHER) && TextUtils.isEmpty(launchIntent.getDataString())) { // An app target can either have no extra or have ItemInfo.EXTRA_PROFILE. Bundle extras = launchIntent.getExtras(); return extras == null || extras.keySet().isEmpty(); } return false; } }
app/src/main/java/foundation/e/blisslauncher/core/customviews/LauncherPagedView.java +280 −12 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ import static foundation.e.blisslauncher.features.test.dragndrop.DragLayer.ALPHA import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.LayoutTransition; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; Loading @@ -14,6 +15,7 @@ import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.app.WallpaperManager; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Paint; import android.graphics.Point; Loading @@ -23,6 +25,7 @@ import android.os.UserHandle; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.util.MutableInt; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; Loading @@ -31,6 +34,7 @@ import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.OvershootInterpolator; import android.widget.GridLayout; import android.widget.Toast; import foundation.e.blisslauncher.BuildConfig; Loading @@ -51,6 +55,9 @@ import foundation.e.blisslauncher.core.utils.IntegerArray; import foundation.e.blisslauncher.core.utils.PackageUserKey; import foundation.e.blisslauncher.features.launcher.Hotseat; import foundation.e.blisslauncher.features.notification.FolderDotInfo; import foundation.e.blisslauncher.features.shortcuts.DeepShortcutManager; import foundation.e.blisslauncher.features.shortcuts.InstallShortcutReceiver; import foundation.e.blisslauncher.features.shortcuts.ShortcutKey; import foundation.e.blisslauncher.features.test.Alarm; import foundation.e.blisslauncher.features.test.CellLayout; import foundation.e.blisslauncher.features.test.IconTextView; Loading @@ -62,6 +69,7 @@ import foundation.e.blisslauncher.features.test.VariantDeviceProfile; import foundation.e.blisslauncher.features.test.WorkspaceStateTransitionAnimation; import foundation.e.blisslauncher.features.test.anim.AnimatorSetBuilder; import foundation.e.blisslauncher.features.test.anim.Interpolators; import foundation.e.blisslauncher.features.test.anim.PropertyListBuilder; import foundation.e.blisslauncher.features.test.dragndrop.DragController; import foundation.e.blisslauncher.features.test.dragndrop.DragOptions; import foundation.e.blisslauncher.features.test.dragndrop.DragSource; Loading @@ -71,8 +79,11 @@ import foundation.e.blisslauncher.features.test.dragndrop.SpringLoadedDragContro import foundation.e.blisslauncher.features.test.graphics.DragPreviewProvider; import foundation.e.blisslauncher.features.test.uninstall.UninstallHelper; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Predicate; import org.jetbrains.annotations.NotNull; Loading Loading @@ -116,6 +127,12 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V final static float MAX_SWIPE_ANGLE = (float) Math.PI / 3; final static float TOUCH_SLOP_DAMPING_FACTOR = 4; // How long to wait before the new-shortcut animation automatically pans the workspace private static final int NEW_APPS_PAGE_MOVE_DELAY = 500; private static final int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5; static final int NEW_APPS_ANIMATION_DELAY = 500; private static final float BOUNCE_ANIMATION_TENSION = 1.3f; private final static Paint sPaint = new Paint(); Runnable mRemoveEmptyScreenRunnable; Loading Loading @@ -176,6 +193,11 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V private Alarm wobbleExpireAlarm = new Alarm(); private static final int WOBBLE_EXPIRATION_TIMEOUT = 25000; /** * Map of ShortcutKey to the number of times it is pinned. */ public final Map<ShortcutKey, MutableInt> pinnedShortcutCounts = new HashMap<>(); public LauncherPagedView(Context context, AttributeSet attributeSet) { this(context, attributeSet, 0); } Loading Loading @@ -297,8 +319,14 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V } } public void bindItems(@NotNull List<? extends LauncherItem> launcherItems) { for (LauncherItem launcherItem : launcherItems) { public void bindItems( @NotNull List<? extends LauncherItem> launcherItems, boolean animateIcons ) { final Collection<Animator> bounceAnims = new ArrayList<>(); int newItemsScreenId = -1; for (int i = 0; i < launcherItems.size(); i++) { LauncherItem launcherItem = launcherItems.get(i); IconTextView appView = (IconTextView) LayoutInflater.from(getContext()) .inflate(R.layout.app_icon, null, false); appView.applyFromShortcutItem(launcherItem); Loading @@ -317,7 +345,6 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V iconLayoutParams.width = mLauncher.getDeviceProfile().getCellWidthPx(); appView.setLayoutParams(iconLayoutParams); appView.setTextVisibility(true); addInScreenFromBind(appView, launcherItem); } else if (launcherItem.container == Constants.CONTAINER_HOTSEAT) { GridLayout.Spec rowSpec = GridLayout.spec(GridLayout.UNDEFINED); GridLayout.Spec colSpec = GridLayout.spec(GridLayout.UNDEFINED); Loading @@ -326,11 +353,254 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V iconLayoutParams.height = mLauncher.getDeviceProfile().getHotseatCellHeightPx(); iconLayoutParams.width = mLauncher.getDeviceProfile().getCellWidthPx(); appView.setLayoutParams(iconLayoutParams); } addInScreenFromBind(appView, launcherItem); if (animateIcons) { // Animate all the applications up now appView.setAlpha(0f); appView.setScaleX(0f); appView.setScaleY(0f); bounceAnims.add(createNewAppBounceAnimation(appView, i)); newItemsScreenId = launcherItem.screenId; } } // Animate to the correct page if (animateIcons && newItemsScreenId > -1) { AnimatorSet anim = new AnimatorSet(); anim.playTogether(bounceAnims); int currentScreenId = getScreenIdForPageIndex(getNextPage()); final int newScreenIndex = getPageIndexForScreenId(newItemsScreenId); final Runnable startBounceAnimRunnable = anim::start; if (newItemsScreenId != currentScreenId) { // We post the animation slightly delayed to prevent slowdowns // when we are loading right after we return to launcher. this.postDelayed((Runnable) () -> { AbstractFloatingView.closeAllOpenViews(mLauncher, false); snapToPage(newScreenIndex); postDelayed( startBounceAnimRunnable, NEW_APPS_ANIMATION_DELAY ); }, NEW_APPS_PAGE_MOVE_DELAY); } else { postDelayed(startBounceAnimRunnable, NEW_APPS_ANIMATION_DELAY); } } requestLayout(); } public void bindItemsAdded(@NotNull List<? extends LauncherItem> items) { final ArrayList<LauncherItem> addedItemsFinal = new ArrayList<>(); final IntegerArray addedWorkspaceScreensFinal = new IntegerArray(); List<LauncherItem> filteredItems = new ArrayList<>(); for (LauncherItem item : items) { if (item.itemType == Constants.ITEM_TYPE_APPLICATION || item.itemType == Constants.ITEM_TYPE_SHORTCUT ) { // Short-circuit this logic if the icon exists somewhere on the workspace if (shortcutExists(item.getIntent(), item.user.getRealHandle())) { continue; } } if (item != null) { filteredItems.add(item); } } for (LauncherItem item : filteredItems) { // Find appropriate space for the item. int[] coords = findSpaceForItem(addedWorkspaceScreensFinal); int screenId = coords[0]; LauncherItem itemInfo; if (item instanceof ApplicationItem || item instanceof ShortcutItem || item instanceof FolderItem) { itemInfo = item; itemInfo.screenId = screenId; itemInfo.cell = coords[1]; itemInfo.container = Constants.CONTAINER_DESKTOP; } else { throw new RuntimeException("Unexpected info type"); } if(item.itemType == Constants.ITEM_TYPE_SHORTCUT) { // Increment the count for the given shortcut ShortcutKey pinnedShortcut = ShortcutKey.fromItem((ShortcutItem) item); MutableInt count = pinnedShortcutCounts.get(pinnedShortcut); if (count == null) { count = new MutableInt(1); pinnedShortcutCounts.put(pinnedShortcut, count); } else { count.value++; } // Since this is a new item, pin the shortcut in the system server. if (count.value == 1) { DeepShortcutManager.getInstance(getContext()).pinShortcut(pinnedShortcut); } } // Save the WorkspaceItemInfo for binding in the workspace addedItemsFinal.add(itemInfo); } if (!addedItemsFinal.isEmpty()) { final ArrayList<LauncherItem> addAnimated = new ArrayList<>(); final ArrayList<LauncherItem> addNotAnimated = new ArrayList<>(); if (!addedItemsFinal.isEmpty()) { LauncherItem info = addedItemsFinal.get(addedItemsFinal.size() - 1); int lastScreenId = info.screenId; for (LauncherItem i : addedItemsFinal) { if (i.screenId == lastScreenId) { addAnimated.add(i); } else { addNotAnimated.add(i); } } } if (!addedWorkspaceScreensFinal.isEmpty()) { bindScreens(addedWorkspaceScreensFinal); } // We add the items without animation on non-visible pages, and with // animations on the new page (which we will try and snap to). if (addNotAnimated != null && !addNotAnimated.isEmpty()) { bindItems(addNotAnimated, false); } if (addAnimated != null && !addAnimated.isEmpty()) { bindItems(addAnimated, true); } // Remove the extra empty screen removeExtraEmptyScreen(false, false); updateDatabase(getWorkspaceAndHotseatCellLayouts()); } } private int[] findSpaceForItem(IntegerArray addedWorkspaceScreensFinal) { // Find appropriate space for the item. int screenId = 0; int cell = 0; boolean found = false; int screenCount = getChildCount(); for (int screen = 0; screen < screenCount; screen++) { View child = getChildAt(screen); if (child instanceof CellLayout) { CellLayout cellLayout = (CellLayout) child; int index = mWorkspaceScreens.indexOfValue(cellLayout); screenId = mWorkspaceScreens.keyAt(index); if (cellLayout.getChildCount() < cellLayout.getMaxChildCount()) { found = true; cell = cellLayout.getChildCount(); break; } } } if (!found) { screenId = screenId + 1; addedWorkspaceScreensFinal.add(screenId); cell = 0; } return new int[]{screenId, cell}; } /** * Returns true if the shortcuts already exists on the workspace. This must be called after * the workspace has been loaded. We identify a shortcut by its intent. */ protected boolean shortcutExists(Intent intent, UserHandle user) { final String compPkgName, intentWithPkg, intentWithoutPkg; if (intent == null) { // Skip items with null intents return true; } if (intent.getComponent() != null) { // If component is not null, an intent with null package will produce // the same result and should also be a match. compPkgName = intent.getComponent().getPackageName(); if (intent.getPackage() != null) { intentWithPkg = intent.toUri(0); intentWithoutPkg = new Intent(intent).setPackage(null).toUri(0); } else { intentWithPkg = new Intent(intent).setPackage(compPkgName).toUri(0); intentWithoutPkg = intent.toUri(0); } } else { compPkgName = null; intentWithPkg = intent.toUri(0); intentWithoutPkg = intent.toUri(0); } boolean isLauncherAppTarget = Utilities.isLauncherAppTarget(intent); for (CellLayout layout : getWorkspaceAndHotseatCellLayouts()) { // map over all the shortcuts on the workspace final int itemCount = layout.getChildCount(); for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) { View item = layout.getChildAt(itemIdx); LauncherItem info = (LauncherItem) item.getTag(); if (info instanceof FolderItem) { FolderItem folder = (FolderItem) info; List<LauncherItem> folderChildren = folder.items; // map over all the children in the folder final int childCount = folder.items.size(); for (int childIdx = 0; childIdx < childCount; childIdx++) { LauncherItem childItem = folderChildren.get(childIdx); if (childItem.getIntent() != null && childItem.user.equals(user)) { Intent copyIntent = new Intent(childItem.getIntent()); copyIntent.setSourceBounds(intent.getSourceBounds()); String s = copyIntent.toUri(0); if (intentWithPkg.equals(s) || intentWithoutPkg.equals(s)) { return true; } // checking for existing promise icon with same package name if (isLauncherAppTarget && childItem.getTargetComponent() != null && compPkgName != null && compPkgName .equals(childItem.getTargetComponent().getPackageName())) { return true; } } } } else { if (info.getIntent() != null && info.user.equals(user)) { Intent copyIntent = new Intent(info.getIntent()); copyIntent.setSourceBounds(intent.getSourceBounds()); String s = copyIntent.toUri(0); if (intentWithPkg.equals(s) || intentWithoutPkg.equals(s)) { return true; } // checking for existing promise icon with same package name if (isLauncherAppTarget && info.getTargetComponent() != null && compPkgName != null && compPkgName.equals(info.getTargetComponent().getPackageName())) { return true; } } } } } return false; } private ValueAnimator createNewAppBounceAnimation(View v, int i) { ValueAnimator bounceAnim = new PropertyListBuilder().alpha(1).scale(1).build(v) .setDuration(InstallShortcutReceiver.NEW_SHORTCUT_BOUNCE_DURATION); bounceAnim.setStartDelay(i * InstallShortcutReceiver.NEW_SHORTCUT_STAGGER_DELAY); bounceAnim.setInterpolator(new OvershootInterpolator(BOUNCE_ANIMATION_TENSION)); return bounceAnim; } public GridLayout insertNewWorkspaceScreen(int screenId) { return insertNewWorkspaceScreen(screenId, getChildCount()); } Loading Loading @@ -637,7 +907,7 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V return indexOfChild(mWorkspaceScreens.get(screenId)); } public long getScreenIdForPageIndex(int index) { public int getScreenIdForPageIndex(int index) { if (0 <= index && index < mScreenOrder.size()) { return mScreenOrder.get(index); } Loading Loading @@ -2466,8 +2736,6 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V computeScrollHelper(false); } public interface ItemOperator { /** * Process the next itemInfo, possibly with side-effect on the next item. Loading
app/src/main/java/foundation/e/blisslauncher/core/executors/MainThreadExecutor.java +0 −7 Original line number Diff line number Diff line package foundation.e.blisslauncher.core.executors; import android.os.Handler; import android.os.Looper; import androidx.annotation.NonNull; import java.util.List; import java.util.concurrent.AbstractExecutorService; import java.util.concurrent.TimeUnit; public class MainThreadExecutor extends LooperExecutor { public MainThreadExecutor() { super(Looper.getMainLooper()); } }