ids, Boolean matchDefault) {
+ return (info, cn) -> ids.get(Integer.parseInt(info.id), matchDefault);
+ }
+}
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/folder/FolderAnimationManager.java b/app/src/main/java/foundation/e/blisslauncher/features/folder/FolderAnimationManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ebe57f1034ed94845b716a3d80b8fe1d39413e0
--- /dev/null
+++ b/app/src/main/java/foundation/e/blisslauncher/features/folder/FolderAnimationManager.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package foundation.e.blisslauncher.features.folder;
+
+import static foundation.e.blisslauncher.features.test.anim.LauncherAnimUtils.SCALE_PROPERTY;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.GradientDrawable;
+import android.util.Property;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import androidx.viewpager.widget.ViewPager;
+import foundation.e.blisslauncher.R;
+import foundation.e.blisslauncher.core.customviews.Folder;
+import foundation.e.blisslauncher.features.test.TestActivity;
+import foundation.e.blisslauncher.features.test.dragndrop.DragLayer;
+
+/**
+ * Manages the opening and closing animations for a {@link Folder}.
+ *
+ * All of the animations are done in the Folder.
+ * ie. When the user taps on the FolderIcon, we immediately hide the FolderIcon and show the Folder
+ * in its place before starting the animation.
+ */
+public class FolderAnimationManager {
+
+ private Folder mFolder;
+ private ViewPager mContent;
+ private GradientDrawable mFolderBackground;
+
+ private FolderIcon mFolderIcon;
+
+ private Context mContext;
+ private TestActivity mLauncher;
+
+ private final boolean mIsOpening;
+
+ private final int mDuration;
+ private final int mDelay;
+
+ private final TimeInterpolator mFolderInterpolator;
+
+ public FolderAnimationManager(Folder folder, boolean isOpening) {
+ mFolder = folder;
+ mContent = folder.mContent;
+
+ mFolderIcon = folder.getFolderIcon();
+
+ mContext = folder.getContext();
+ mLauncher = folder.getLauncher();
+
+ mIsOpening = isOpening;
+
+ Resources res = mContent.getResources();
+ mDuration = res.getInteger(R.integer.config_materialFolderExpandDuration);
+ mDelay = res.getInteger(R.integer.config_folderDelay);
+
+ mFolderInterpolator = AnimationUtils.loadInterpolator(
+ mContext,
+ R.anim.folder_interpolator
+ );
+ }
+
+ /**
+ * Prepares the Folder for animating between open / closed states.
+ */
+ public AnimatorSet getAnimator() {
+ final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) mFolder.getLayoutParams();
+
+ // Match position of the FolderIcon
+ final Rect folderIconPos = new Rect();
+ float scaleRelativeToDragLayer = mLauncher.getDragLayer()
+ .getDescendantRectRelativeToSelf(mFolderIcon, folderIconPos);
+ // Calculate the starting and ending bounds for the zoomed-in image.
+ // This step involves lots of math. Yay, math.
+ Rect dragLayerBounds = new Rect();
+ Point globalOffset = new Point();
+
+ mLauncher.getDragLayer()
+ .getGlobalVisibleRect(dragLayerBounds, globalOffset);
+ float startScale = ((float) folderIconPos.width() / dragLayerBounds.width());
+ float startHeight = startScale * dragLayerBounds.height();
+ float deltaHeight = (startHeight - folderIconPos.height()) / 2;
+ folderIconPos.top -= deltaHeight;
+ folderIconPos.bottom += deltaHeight;
+ float initialScale = (float) folderIconPos.height() / dragLayerBounds.height();
+ final float finalScale = 1f;
+ float scale = mIsOpening ? initialScale : finalScale;
+ float initialAlpha = 0f;
+ float finalAlpha = 1f;
+ mFolder.setScaleX(scale);
+ mFolder.setScaleY(scale);
+ mFolder.setPivotX(0);
+ mFolder.setPivotY(0);
+
+ // Create the animators.
+ AnimatorSet a = new AnimatorSet();
+
+ play(
+ a,
+ getAnimator(mFolder,
+ View.X,
+ folderIconPos.left,
+ dragLayerBounds.left
+ )
+ );
+ play(a, getAnimator(mFolder, View.Y, folderIconPos.top, dragLayerBounds.top));
+ play(a, getAnimator(mFolder, SCALE_PROPERTY, initialScale, finalScale));
+ play(a, getAnimator(mFolder, View.ALPHA, initialAlpha, finalAlpha));
+ // play(a, getAnimator(mFolderBackground, "color", initialColor, finalColor));
+
+ // Animate the elevation midway so that the shadow is not noticeable in the background.
+ int midDuration = mDuration / 2;
+ Animator z = getAnimator(mFolder, View.TRANSLATION_Z, -mFolder.getElevation(), 0);
+ play(a, z, mIsOpening ? midDuration : 0, midDuration);
+
+ a.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ mFolder.setVisibility(View.VISIBLE);
+ mFolder.setPivotX(0f);
+ mFolder.setPivotY(0f);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ if (mIsOpening) {
+ mFolder.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ mFolder.setScaleX(1f);
+ mFolder.setScaleY(1f);
+ if (!mIsOpening) {
+ mFolder.setVisibility(View.GONE);
+ }
+ }
+ });
+ return a;
+ }
+
+ private void play(AnimatorSet as, Animator a) {
+ play(as, a, a.getStartDelay(), mDuration);
+ }
+
+ private void play(AnimatorSet as, Animator a, long startDelay, int duration) {
+ a.setStartDelay(startDelay);
+ a.setDuration(duration);
+ as.play(a);
+ }
+
+ private TimeInterpolator getPreviewItemInterpolator() {
+ return mFolderInterpolator;
+ }
+
+ private Animator getAnimator(View view, Property property, float v1, float v2) {
+ return mIsOpening
+ ? ObjectAnimator.ofFloat(view, property, v1, v2)
+ : ObjectAnimator.ofFloat(view, property, v2, v1);
+ }
+
+ private Animator getAnimator(GradientDrawable drawable, String property, int v1, int v2) {
+ return mIsOpening
+ ? ObjectAnimator.ofArgb(drawable, property, v1, v2)
+ : ObjectAnimator.ofArgb(drawable, property, v2, v1);
+ }
+}
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/folder/FolderIcon.kt b/app/src/main/java/foundation/e/blisslauncher/features/folder/FolderIcon.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f6d3e4d87e99925b56c885c7dd87eb82632ff989
--- /dev/null
+++ b/app/src/main/java/foundation/e/blisslauncher/features/folder/FolderIcon.kt
@@ -0,0 +1,122 @@
+package foundation.e.blisslauncher.features.folder
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import foundation.e.blisslauncher.core.customviews.Folder
+import foundation.e.blisslauncher.core.database.model.FolderItem
+import foundation.e.blisslauncher.core.database.model.LauncherItem
+import foundation.e.blisslauncher.core.touch.ItemClickHandler
+import foundation.e.blisslauncher.core.utils.GraphicsUtil
+import foundation.e.blisslauncher.features.notification.FolderDotInfo
+import foundation.e.blisslauncher.features.test.IconTextView
+
+/**
+ * A text view which displays an icon on top side of it.
+ */
+@SuppressLint("AppCompatCustomView")
+class FolderIcon @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyle: Int = 0
+) : IconTextView(context, attrs, defStyle), FolderItem.FolderListener {
+
+ private lateinit var folderItem: FolderItem
+ var folder: Folder? = null
+
+ companion object {
+ fun fromXml(
+ resId: Int,
+ group: ViewGroup,
+ folderInfo: FolderItem
+ ): FolderIcon {
+ val icon = LayoutInflater.from(group.context)
+ .inflate(resId, group, false) as FolderIcon
+ icon.tag = folderInfo
+ icon.setOnClickListener(ItemClickHandler.INSTANCE)
+ icon.folderItem = folderInfo
+ val folder = Folder.fromXml(icon.launcher).apply {
+ this.dragController = launcher.dragController
+ this.folderIcon = icon
+ }
+ folder.bind(folderInfo)
+ icon.folder = folder
+ folderInfo.addListener(icon)
+ return icon
+ }
+ }
+
+ override fun onAdd(item: LauncherItem?) {
+ if (mDotInfo is FolderDotInfo) {
+ (mDotInfo as FolderDotInfo).let {
+ val wasDotted: Boolean = it.hasDot()
+ it.addDotInfo(launcher.getDotInfoForItem(item))
+ val isDotted: Boolean = it.hasDot()
+ updateDotScale(wasDotted, isDotted, true)
+ invalidate()
+ requestLayout()
+ }
+ }
+ }
+
+ override fun onTitleChanged(title: CharSequence?) {
+ text = title
+ }
+
+ override fun onRemove(item: LauncherItem?) {
+ if (mDotInfo is FolderDotInfo) {
+ (mDotInfo as FolderDotInfo).let {
+ val wasDotted: Boolean = it.hasDot()
+ it.subtractDotInfo(launcher.getDotInfoForItem(item))
+ val isDotted: Boolean = it.hasDot()
+ updateDotScale(wasDotted, isDotted, true)
+ invalidate()
+ requestLayout()
+ }
+ }
+ }
+
+ override fun onItemsChanged(animate: Boolean) {
+ updateFolderIcon()
+ invalidate()
+ requestLayout()
+ }
+
+ private fun updateFolderIcon() {
+ folderItem.icon = GraphicsUtil(context).generateFolderIcon(context, folderItem)
+ applyFromFolderItem(folderItem)
+ }
+
+ fun applyFromFolderItem(item: FolderItem) {
+ applyFromShortcutItem(item)
+ folderItem = item
+ }
+
+ fun setDotInfo(dotInfo: FolderDotInfo) {
+ val wasDotted = mDotInfo is FolderDotInfo && (mDotInfo as FolderDotInfo).hasDot()
+ updateDotScale(wasDotted, dotInfo.hasDot(), true)
+ mDotInfo = dotInfo
+ }
+
+ override fun hasDot(): Boolean {
+ return mDotInfo != null && (mDotInfo as FolderDotInfo).hasDot()
+ }
+
+ fun removeListeners() {
+ folderItem.removeListener(this)
+ }
+
+ fun acceptDrop(): Boolean {
+ return !(folder?.isDestroyed() ?: true)
+ }
+
+ fun addItem(item: LauncherItem) {
+ addItem(item, true)
+ }
+
+ fun addItem(item: LauncherItem?, animate: Boolean) {
+ folderItem.add(item, animate)
+ }
+}
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/folder/FolderPagerAdapter.java b/app/src/main/java/foundation/e/blisslauncher/features/folder/FolderPagerAdapter.java
index e636db0beab635ad987198f66a306a0109338a14..8c1c4380854974adeecca44bb32b707775e9ab29 100644
--- a/app/src/main/java/foundation/e/blisslauncher/features/folder/FolderPagerAdapter.java
+++ b/app/src/main/java/foundation/e/blisslauncher/features/folder/FolderPagerAdapter.java
@@ -1,6 +1,7 @@
package foundation.e.blisslauncher.features.folder;
import android.content.Context;
+import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -12,6 +13,7 @@ import androidx.annotation.NonNull;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
+import java.util.ArrayList;
import java.util.List;
import foundation.e.blisslauncher.R;
@@ -28,6 +30,7 @@ public class FolderPagerAdapter extends PagerAdapter {
private Context mContext;
private List mFolderAppItems;
private VariantDeviceProfile mDeviceProfile;
+ private List grids = new ArrayList<>();
public FolderPagerAdapter(
Context context,
@@ -72,6 +75,7 @@ public class FolderPagerAdapter extends PagerAdapter {
viewGroup.addView(appView);
i++;
}
+ grids.add(viewGroup);
container.addView(viewGroup);
return viewGroup;
}
@@ -93,4 +97,9 @@ public class FolderPagerAdapter extends PagerAdapter {
) {
container.removeView((View) object);
}
+
+ @Override
+ public void notifyDataSetChanged() {
+ super.notifyDataSetChanged();
+ }
}
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/folder/FolderViewPager.kt b/app/src/main/java/foundation/e/blisslauncher/features/folder/FolderViewPager.kt
new file mode 100644
index 0000000000000000000000000000000000000000..673226c945755dccdf97843efe76658a2d8bea07
--- /dev/null
+++ b/app/src/main/java/foundation/e/blisslauncher/features/folder/FolderViewPager.kt
@@ -0,0 +1,78 @@
+package foundation.e.blisslauncher.features.folder
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewGroup
+import android.widget.GridLayout
+import androidx.core.view.get
+import androidx.viewpager.widget.ViewPager
+import foundation.e.blisslauncher.core.customviews.LauncherPagedView
+import foundation.e.blisslauncher.core.database.model.LauncherItem
+
+class FolderViewPager @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null
+) : ViewPager(context, attrs) {
+
+ fun getFirstItem(): View? {
+ if (childCount < 1) {
+ return null
+ }
+ val currContainer: GridLayout = getChildAt(currentItem) as GridLayout
+ return if (currContainer.childCount > 0) {
+ currContainer[0]
+ } else {
+ null
+ }
+ }
+
+ fun getLastItem(): View? {
+ if (childCount < 1) {
+ return null
+ }
+ val currContainer: GridLayout = getChildAt(currentItem) as GridLayout
+ val lastRank = currContainer.childCount - 1
+ return if (currContainer.childCount > 0) {
+ currContainer[lastRank]
+ } else {
+ null
+ }
+ }
+
+ fun iterateOverItems(op: LauncherPagedView.ItemOperator): View? {
+ for (k in 0 until childCount) {
+ val page: GridLayout = getChildAt(k) as GridLayout
+ for (j in 0 until page.childCount) {
+ val v: View? = page.getChildAt(j)
+ if (v != null && op.evaluate(v.tag as LauncherItem, v, j)) {
+ return v
+ }
+ }
+ }
+ return null
+ }
+
+ fun removeItem(v: View?) {
+ for (i in childCount - 1 downTo 0) {
+ val page: GridLayout = getChildAt(i) as GridLayout
+ page.removeView(v)
+ }
+ }
+
+ fun getItemCount(): Int {
+ val lastPageIndex = childCount - 1
+ return if (lastPageIndex < 0) {
+ 0
+ } else {
+ (getChildAt(lastPageIndex) as GridLayout).childCount + lastPageIndex * 9 // maxItems per page
+ }
+ }
+
+ /**
+ * Sets the focus on the first visible child.
+ */
+ fun setFocusOnFirstChild() {
+ (getChildAt(currentItem) as ViewGroup?)?.getChildAt(0)?.requestFocus()
+ }
+}
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/launcher/AppProvider.java b/app/src/main/java/foundation/e/blisslauncher/features/launcher/AppProvider.java
index 2c7afc100158b8547a2d04edc40cf8ba6b25c5a9..e1b6685a29c60ac488fa6d9754f379ae1d071417 100644
--- a/app/src/main/java/foundation/e/blisslauncher/features/launcher/AppProvider.java
+++ b/app/src/main/java/foundation/e/blisslauncher/features/launcher/AppProvider.java
@@ -1,6 +1,5 @@
package foundation.e.blisslauncher.features.launcher;
-
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -18,10 +17,12 @@ import android.os.UserManager;
import android.provider.MediaStore;
import android.util.Log;
import android.util.LongSparseArray;
+
+import androidx.core.content.ContextCompat;
+
import foundation.e.blisslauncher.BlissLauncher;
import foundation.e.blisslauncher.R;
import foundation.e.blisslauncher.core.Utilities;
-import foundation.e.blisslauncher.core.broadcast.PackageAddedRemovedHandler;
import foundation.e.blisslauncher.core.database.DatabaseManager;
import foundation.e.blisslauncher.core.database.model.ApplicationItem;
import foundation.e.blisslauncher.core.database.model.FolderItem;
@@ -38,6 +39,7 @@ import foundation.e.blisslauncher.features.launcher.tasks.LoadDatabaseTask;
import foundation.e.blisslauncher.features.launcher.tasks.LoadShortcutTask;
import foundation.e.blisslauncher.features.shortcuts.DeepShortcutManager;
import foundation.e.blisslauncher.features.shortcuts.ShortcutInfoCompat;
+
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collection;
@@ -46,7 +48,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
-
// TODO: Find better solution instead of excessively using volatile and synchronized.
// - and use RxJava instead of bad async tasks.
public class AppProvider {
@@ -56,6 +57,11 @@ public class AppProvider {
*/
List mLauncherItems;
+ /**
+ * Represents all items including the ones which are added when launcher is not running.
+ */
+ AppsRepository.AllItems allItems;
+
/**
* Represents networkItems stored in database.
*/
@@ -80,6 +86,7 @@ public class AppProvider {
private static final String MICROG_PACKAGE = "com.google.android.gms";
private static final String MUPDF_PACKAGE = "com.artifex.mupdf.mini.app";
private static final String PDF_VIEWER_PACKAGE = "com.gsnathan.pdfviewer";
+ private static final String PDF_VIEWER_E_PACKAGE = "foundation.e.pdfviewer";
private static final String OPENKEYCHAIN_PACKAGE = "org.sufficientlysecure.keychain";
private static final String LIBREOFFICE_PACKAGE = "org.documentfoundation.libreoffice";
@@ -91,6 +98,7 @@ public class AppProvider {
DISABLED_PACKAGES.add(MICROG_PACKAGE);
DISABLED_PACKAGES.add(MUPDF_PACKAGE);
DISABLED_PACKAGES.add(PDF_VIEWER_PACKAGE);
+ DISABLED_PACKAGES.add(PDF_VIEWER_E_PACKAGE);
DISABLED_PACKAGES.add(OPENKEYCHAIN_PACKAGE);
DISABLED_PACKAGES.add(LIBREOFFICE_PACKAGE);
}
@@ -116,86 +124,8 @@ public class AppProvider {
assert manager != null;
final LauncherApps launcher = (LauncherApps) mContext.getSystemService(
- Context.LAUNCHER_APPS_SERVICE);
+ Context.LAUNCHER_APPS_SERVICE);
assert launcher != null;
-
- launcher.registerCallback(new LauncherApps.Callback() {
- @Override
- public void onPackageRemoved(String packageName, android.os.UserHandle user) {
- if (packageName.equalsIgnoreCase(MICROG_PACKAGE) || packageName.equalsIgnoreCase(
- MUPDF_PACKAGE)) {
- return;
- }
-
- PackageAddedRemovedHandler.handleEvent(mContext,
- "android.intent.action.PACKAGE_REMOVED",
- packageName, new UserHandle(manager.getSerialNumberForUser(user), user),
- false
- );
- }
-
- @Override
- public void onPackageAdded(String packageName, android.os.UserHandle user) {
- if (packageName.equalsIgnoreCase(MICROG_PACKAGE) || packageName.equalsIgnoreCase(
- MUPDF_PACKAGE)) {
- return;
- }
-
- PackageAddedRemovedHandler.handleEvent(mContext,
- "android.intent.action.PACKAGE_ADDED",
- packageName, new UserHandle(manager.getSerialNumberForUser(user), user),
- false
- );
- }
-
- @Override
- public void onPackageChanged(String packageName, android.os.UserHandle user) {
- if (packageName.equalsIgnoreCase(MICROG_PACKAGE) || packageName.equalsIgnoreCase(
- MUPDF_PACKAGE)) {
- return;
- }
-
- PackageAddedRemovedHandler.handleEvent(mContext,
- "android.intent.action.PACKAGE_CHANGED",
- packageName, new UserHandle(manager.getSerialNumberForUser(user), user),
- true
- );
- }
-
- @Override
- public void onPackagesAvailable(String[] packageNames, android.os.UserHandle user,
- boolean replacing) {
- Log.d(TAG, "onPackagesAvailable() called with: packageNames = [" + packageNames + "], user = [" + user + "], replacing = [" + replacing + "]");
- for (String packageName : packageNames) {
- PackageAddedRemovedHandler.handleEvent(mContext,
- "android.intent.action.MEDIA_MOUNTED",
- packageName, new UserHandle(manager.getSerialNumberForUser(user), user), false
- );
- }
- }
-
- @Override
- public void onPackagesUnavailable(String[] packageNames, android.os.UserHandle user,
- boolean replacing) {
- Log.d(TAG, "onPackagesUnavailable() called with: packageNames = [" + packageNames + "], user = [" + user + "], replacing = [" + replacing + "]");
- PackageAddedRemovedHandler.handleEvent(mContext,
- "android.intent.action.MEDIA_UNMOUNTED",
- null, new UserHandle(manager.getSerialNumberForUser(user), user), false
- );
- }
-
- @Override
- public void onPackagesSuspended(String[] packageNames, android.os.UserHandle user) {
- Log.d(TAG, "onPackagesSuspended() called with: packageNames = [" + packageNames + "], user = [" + user + "]");
- }
-
- @Override
- public void onPackagesUnsuspended(String[] packageNames, android.os.UserHandle user) {
- super.onPackagesUnsuspended(packageNames, user);
- Log.d(TAG, "onPackagesUnsuspended() called with: packageNames = [" + packageNames + "], user = [" + user + "]");
- }
- });
-
mAppsRepository = AppsRepository.getAppsRepository();
}
@@ -269,7 +199,11 @@ public class AppProvider {
}
public synchronized void loadDatabaseOver(List databaseItems) {
- Log.d(TAG, "loadDatabaseOver() called with: databaseItems = [" + Thread.currentThread().getName() + "]" + mStopped);
+ Log.d(
+ TAG,
+ "loadDatabaseOver() called with: databaseItems = [" + Thread.currentThread()
+ .getName() + "]" + mStopped
+ );
this.mDatabaseItems = databaseItems;
databaseLoaded = true;
handleAllProviderLoaded();
@@ -278,19 +212,19 @@ public class AppProvider {
private synchronized void handleAllProviderLoaded() {
if (appsLoaded && shortcutsLoaded && databaseLoaded) {
if (mDatabaseItems == null || mDatabaseItems.size() <= 0) {
- mLauncherItems = prepareDefaultLauncherItems();
+ allItems = prepareDefaultLauncherItems();
} else {
- mLauncherItems = prepareLauncherItems();
+ allItems = prepareLauncherItems();
}
- mAppsRepository.updateAppsRelay(mLauncherItems);
+ mAppsRepository.updateAllAppsRelay(allItems);
}
}
- private List prepareLauncherItems() {
+ private AppsRepository.AllItems prepareLauncherItems() {
Log.d(TAG, "prepareLauncherItems() called");
- /**
- * Indices of folder in {@link #mLauncherItems}.
+ /*
+ Indices of folder in {@link #mLauncherItems}.
*/
LongSparseArray foldersIndex = new LongSparseArray<>();
List mLauncherItems = new ArrayList<>();
@@ -306,7 +240,13 @@ public class AppProvider {
if ((isAppOnSdcard(databaseItem.packageName, userHandle) || !isSdCardReady
) && !DISABLED_PACKAGES.contains(databaseItem.packageName)) {
Log.d(TAG, "Missing package: " + databaseItem.packageName);
- Log.d(TAG, "Is App on Sdcard " + isAppOnSdcard(databaseItem.packageName, userHandle));
+ Log.d(
+ TAG,
+ "Is App on Sdcard " + isAppOnSdcard(
+ databaseItem.packageName,
+ userHandle
+ )
+ );
Log.d(TAG, "Is Sdcard ready " + isSdCardReady);
pendingPackages.addToList(userHandle, databaseItem.packageName);
@@ -316,7 +256,8 @@ public class AppProvider {
applicationItem.user = userHandle;
applicationItem.componentName = databaseItem.getTargetComponent();
applicationItem.packageName = databaseItem.packageName;
- applicationItem.icon = getContext().getDrawable(R.drawable.default_icon);
+ applicationItem.icon =
+ ContextCompat.getDrawable(getContext(), R.drawable.default_icon);
applicationItem.isDisabled = true;
} else {
DatabaseManager.getManager(mContext).removeLauncherItem(databaseItem.id);
@@ -329,7 +270,7 @@ public class AppProvider {
applicationItem.cell = databaseItem.cell;
applicationItem.keyId = databaseItem.keyId;
if (applicationItem.container == Constants.CONTAINER_DESKTOP
- || applicationItem.container == Constants.CONTAINER_HOTSEAT) {
+ || applicationItem.container == Constants.CONTAINER_HOTSEAT) {
mLauncherItems.add(applicationItem);
} else {
Integer index = foldersIndex.get(applicationItem.container);
@@ -352,12 +293,12 @@ public class AppProvider {
}
if (shortcutItem.container == Constants.CONTAINER_DESKTOP
- || shortcutItem.container == Constants.CONTAINER_HOTSEAT) {
+ || shortcutItem.container == Constants.CONTAINER_HOTSEAT) {
mLauncherItems.add(shortcutItem);
} else {
FolderItem folderItem =
- (FolderItem) mLauncherItems.get(
- foldersIndex.get(shortcutItem.container));
+ (FolderItem) mLauncherItems.get(
+ foldersIndex.get(shortcutItem.container));
if (folderItem.items == null) {
folderItem.items = new ArrayList<>();
}
@@ -379,43 +320,49 @@ public class AppProvider {
if (foldersIndex.size() > 0) {
for (int i = 0; i < foldersIndex.size(); i++) {
FolderItem folderItem =
- (FolderItem) mLauncherItems.get(foldersIndex.get(foldersIndex.keyAt(i)));
+ (FolderItem) mLauncherItems.get(foldersIndex.get(foldersIndex.keyAt(i)));
if (folderItem.items == null || folderItem.items.size() == 0) {
DatabaseManager.getManager(mContext).removeLauncherItem(folderItem.id);
mLauncherItems.remove((int) foldersIndex.get(foldersIndex.keyAt(i)));
} else {
- folderItem.icon = new GraphicsUtil(mContext).generateFolderIcon(mContext,
- folderItem);
+ folderItem.icon = new GraphicsUtil(mContext).generateFolderIcon(
+ mContext,
+ folderItem
+ );
}
}
}
for (LauncherItem mLauncherItem : mLauncherItems) {
- Log.i(TAG, "prepareLauncherItems: "+mLauncherItem);
+ Log.i(TAG, "prepareLauncherItems: " + mLauncherItem);
}
+
applicationItems.removeAll(mDatabaseItems);
- List mutableList = new ArrayList<>(applicationItems);
- Collections.sort(mutableList, (app1, app2) -> {
+ List mutableList = new ArrayList<>(applicationItems);
+ mutableList.sort((app1, app2) -> {
Collator collator = Collator.getInstance();
return collator.compare(app1.title.toString(), app2.title.toString());
});
- mLauncherItems.addAll(mutableList);
- return mLauncherItems;
+
+ return new AppsRepository.AllItems(mLauncherItems, mutableList);
}
private boolean isAppOnSdcard(String packageName, UserHandle userHandle) {
- ApplicationInfo info = null;
+ ApplicationInfo info;
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
info = ((LauncherApps) mContext.getSystemService(
- Context.LAUNCHER_APPS_SERVICE)).getApplicationInfo(
- packageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userHandle.getRealHandle());
+ Context.LAUNCHER_APPS_SERVICE)).getApplicationInfo(
+ packageName,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES,
+ userHandle.getRealHandle()
+ );
return info != null && (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
} else {
info = getContext().getPackageManager()
- .getApplicationInfo(packageName, PackageManager.MATCH_UNINSTALLED_PACKAGES);
- return info != null && info.enabled;
+ .getApplicationInfo(packageName, PackageManager.MATCH_UNINSTALLED_PACKAGES);
+ return info.enabled;
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
@@ -430,7 +377,8 @@ public class AppProvider {
shortcutItem.title = databaseItem.title.toString();
shortcutItem.icon_blob = databaseItem.icon_blob;
Bitmap bitmap = BitmapFactory.decodeByteArray(databaseItem.icon_blob, 0,
- databaseItem.icon_blob.length);
+ databaseItem.icon_blob.length
+ );
shortcutItem.icon = new BitmapDrawable(mContext.getResources(), bitmap);
shortcutItem.launchIntent = databaseItem.getIntent();
shortcutItem.launchIntentUri = databaseItem.launchIntentUri;
@@ -444,8 +392,10 @@ public class AppProvider {
private ShortcutItem prepareShortcutForOreo(LauncherItem databaseItem) {
ShortcutInfoCompat info = mShortcutInfoCompats.get(databaseItem.id);
if (info == null) {
- Log.d(TAG,
- "prepareShortcutForOreo() called with: databaseItem = [" + databaseItem + "]");
+ Log.d(
+ TAG,
+ "prepareShortcutForOreo() called with: databaseItem = [" + databaseItem + "]"
+ );
return null;
}
@@ -453,10 +403,12 @@ public class AppProvider {
shortcutItem.id = info.getId();
shortcutItem.packageName = info.getPackage();
shortcutItem.title = info.getShortLabel().toString();
- Drawable icon = DeepShortcutManager.getInstance(mContext).getShortcutIconDrawable(info,
- mContext.getResources().getDisplayMetrics().densityDpi);
+ Drawable icon = DeepShortcutManager.getInstance(mContext).getShortcutIconDrawable(
+ info,
+ mContext.getResources().getDisplayMetrics().densityDpi
+ );
shortcutItem.icon = BlissLauncher.getApplication(
- mContext).getIconsHandler().convertIcon(icon);
+ mContext).getIconsHandler().convertIcon(icon);
shortcutItem.launchIntent = info.makeIntent();
shortcutItem.container = databaseItem.container;
shortcutItem.screenId = databaseItem.screenId;
@@ -465,25 +417,27 @@ public class AppProvider {
return shortcutItem;
}
- private List prepareDefaultLauncherItems() {
+ private AppsRepository.AllItems prepareDefaultLauncherItems() {
List mLauncherItems = new ArrayList<>();
List pinnedItems = new ArrayList<>();
PackageManager pm = mContext.getPackageManager();
Intent[] intents = {
- new Intent(Intent.ACTION_DIAL),
- new Intent(Intent.ACTION_VIEW, Uri.parse("sms:")),
- new Intent(Intent.ACTION_VIEW, Uri.parse("http:")),
- new Intent(MediaStore.ACTION_IMAGE_CAPTURE)
+ new Intent(Intent.ACTION_DIAL),
+ new Intent(Intent.ACTION_VIEW, Uri.parse("sms:")),
+ new Intent(Intent.ACTION_VIEW, Uri.parse("http:")),
+ new Intent(MediaStore.ACTION_IMAGE_CAPTURE)
};
for (int i = 0; i < intents.length; i++) {
String packageName = AppUtils.getPackageNameForIntent(intents[i], pm);
LauncherApps launcherApps = (LauncherApps) mContext.getSystemService(
- Context.LAUNCHER_APPS_SERVICE);
- List list = launcherApps.getActivityList(packageName,
- Process.myUserHandle());
+ Context.LAUNCHER_APPS_SERVICE);
+ List list = launcherApps.getActivityList(
+ packageName,
+ Process.myUserHandle()
+ );
for (LauncherActivityInfo launcherActivityInfo : list) {
ApplicationItem applicationItem = mApplicationItems.get(
- launcherActivityInfo.getComponentName().flattenToString());
+ launcherActivityInfo.getComponentName().flattenToString());
if (applicationItem != null) {
applicationItem.container = Constants.CONTAINER_HOTSEAT;
applicationItem.cell = i;
@@ -494,19 +448,19 @@ public class AppProvider {
}
for (Map.Entry stringApplicationItemEntry : mApplicationItems
- .entrySet()) {
+ .entrySet()) {
if (!pinnedItems.contains(stringApplicationItemEntry.getValue())) {
mLauncherItems.add(stringApplicationItemEntry.getValue());
}
}
- Collections.sort(mLauncherItems, (app1, app2) -> {
+ mLauncherItems.sort((app1, app2) -> {
Collator collator = Collator.getInstance();
return collator.compare(app1.title.toString(), app2.title.toString());
});
mLauncherItems.addAll(pinnedItems);
- return mLauncherItems;
+ return new AppsRepository.AllItems(mLauncherItems, Collections.emptyList());
}
public AppsRepository getAppsRepository() {
@@ -514,7 +468,7 @@ public class AppProvider {
}
public void clear() {
- this.sInstance = null;
+ sInstance = null;
mLauncherItems = new ArrayList<>();
mAppsRepository.updateAppsRelay(Collections.emptyList());
}
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/launcher/AppsRepository.java b/app/src/main/java/foundation/e/blisslauncher/features/launcher/AppsRepository.java
index cf4e5cbc7471522da15f3fe92c9a7784c7f209ff..8e0f05a4456616585a4f1091b2a46b4e41e24cdb 100644
--- a/app/src/main/java/foundation/e/blisslauncher/features/launcher/AppsRepository.java
+++ b/app/src/main/java/foundation/e/blisslauncher/features/launcher/AppsRepository.java
@@ -3,17 +3,22 @@ package foundation.e.blisslauncher.features.launcher;
import com.jakewharton.rxrelay2.BehaviorRelay;
import foundation.e.blisslauncher.core.database.model.LauncherItem;
+
import java.util.List;
public class AppsRepository {
private static final String TAG = "AppsRepository";
+
+ @Deprecated
private BehaviorRelay> appsRelay;
+ private BehaviorRelay allItems;
private static AppsRepository sAppsRepository;
private AppsRepository() {
appsRelay = BehaviorRelay.create();
+ allItems = BehaviorRelay.create();
}
public static AppsRepository getAppsRepository() {
@@ -25,13 +30,43 @@ public class AppsRepository {
public void clearAll(){
appsRelay = BehaviorRelay.create();
+ allItems = BehaviorRelay.create();
}
public void updateAppsRelay(List launcherItems) {
this.appsRelay.accept(launcherItems);
}
+ public void updateAllAppsRelay(AllItems allItems) {
+ this.allItems.accept(allItems);
+ }
+
public BehaviorRelay> getAppsRelay() {
return appsRelay;
}
-}
+
+ public BehaviorRelay getAllItemsRelay() {
+ return allItems;
+ }
+
+ public static class AllItems {
+ private final List items;
+ private final List newAddedItems;
+
+ public AllItems(
+ List items,
+ List newAddedItems
+ ) {
+ this.items = items;
+ this.newAddedItems = newAddedItems;
+ }
+
+ public List getItems() {
+ return items;
+ }
+
+ public List getNewAddedItems() {
+ return newAddedItems;
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/launcher/Hotseat.java b/app/src/main/java/foundation/e/blisslauncher/features/launcher/Hotseat.java
index a3d7389542bb68eacbfcc472b6e82526cb040553..df84dd3ae64522440e07033049dd615201c46fe1 100644
--- a/app/src/main/java/foundation/e/blisslauncher/features/launcher/Hotseat.java
+++ b/app/src/main/java/foundation/e/blisslauncher/features/launcher/Hotseat.java
@@ -17,7 +17,9 @@
package foundation.e.blisslauncher.features.launcher;
import android.content.Context;
+import android.graphics.Canvas;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
@@ -27,16 +29,26 @@ import android.view.ViewGroup;
import android.view.WindowInsets;
import android.widget.FrameLayout;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.logging.Handler;
+
import foundation.e.blisslauncher.R;
+import foundation.e.blisslauncher.core.blur.BlurWallpaperProvider;
+import foundation.e.blisslauncher.core.blur.ShaderBlurDrawable;
import foundation.e.blisslauncher.core.customviews.Insettable;
import foundation.e.blisslauncher.core.customviews.InsettableFrameLayout;
+import foundation.e.blisslauncher.core.executors.MainThreadExecutor;
+import foundation.e.blisslauncher.core.utils.MultiValueAlpha;
import foundation.e.blisslauncher.features.test.CellLayout;
import foundation.e.blisslauncher.features.test.TestActivity;
import foundation.e.blisslauncher.features.test.VariantDeviceProfile;
-public class Hotseat extends CellLayout implements Insettable {
+public class Hotseat extends CellLayout implements Insettable, BlurWallpaperProvider.Listener {
private final TestActivity mLauncher;
+ private final MultiValueAlpha mMultiValueAlpha;
private CellLayout mContent;
private static final String TAG = "Hotseat";
@@ -44,6 +56,30 @@ public class Hotseat extends CellLayout implements Insettable {
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mHasVerticalHotseat;
+ private final BlurWallpaperProvider blurWallpaperProvider;
+ private ShaderBlurDrawable fullBlurDrawable = null;
+ private int blurAlpha = 255;
+ private final Drawable.Callback blurDrawableCallback = new Drawable.Callback() {
+ @Override
+ public void invalidateDrawable(@NonNull Drawable who) {
+ new MainThreadExecutor().execute(() -> invalidate());
+ }
+
+ @Override
+ public void scheduleDrawable(
+ @NonNull Drawable who, @NonNull Runnable what, long when
+ ) {
+
+ }
+
+ @Override
+ public void unscheduleDrawable(
+ @NonNull Drawable who, @NonNull Runnable what
+ ) {
+
+ }
+ };
+
public Hotseat(Context context) {
this(context, null);
}
@@ -55,7 +91,20 @@ public class Hotseat extends CellLayout implements Insettable {
public Hotseat(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mLauncher = TestActivity.Companion.getLauncher(context);
- setBackgroundColor(0x33000000);
+ setWillNotDraw(false);
+ blurWallpaperProvider = BlurWallpaperProvider.Companion.getInstance(getContext());
+ createBlurDrawable();
+ mMultiValueAlpha = new MultiValueAlpha(this, 1);
+ }
+
+ private void createBlurDrawable() {
+ if (isAttachedToWindow() && fullBlurDrawable != null) {
+ fullBlurDrawable.stopListening();
+ }
+ fullBlurDrawable = blurWallpaperProvider.createDrawable();
+ fullBlurDrawable.setCallback(blurDrawableCallback);
+ fullBlurDrawable.setBounds(getLeft(), getTop(), getRight(), getBottom());
+ if (isAttachedToWindow()) fullBlurDrawable.startListening();
}
// TODO: Remove this later.
@@ -70,6 +119,44 @@ public class Hotseat extends CellLayout implements Insettable {
setGridSize(idp.getInv().getNumHotseatIcons(), 1);
}
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ BlurWallpaperProvider.Companion.getInstance(getContext()).addListener(this);
+ if (fullBlurDrawable != null) {
+ fullBlurDrawable.startListening();
+ }
+ }
+
+ public MultiValueAlpha.AlphaProperty getAlphaProperty(int index) {
+ return mMultiValueAlpha.getProperty(index);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ BlurWallpaperProvider.Companion.getInstance(getContext()).removeListener(this);
+ if (fullBlurDrawable != null) {
+ fullBlurDrawable.stopListening();
+ }
+ }
+
+ @Override
+ protected void onDraw(@Nullable Canvas canvas) {
+ if (fullBlurDrawable != null) {
+ fullBlurDrawable.draw(canvas);
+ }
+ super.onDraw(canvas);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (changed && fullBlurDrawable != null) {
+ fullBlurDrawable.setBounds(left, top, right, bottom);
+ }
+ super.onLayout(changed, left, top, right, bottom);
+ }
+
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// We don't want any clicks to go through to the hotseat unless the workspace is in
@@ -96,4 +183,27 @@ public class Hotseat extends CellLayout implements Insettable {
// Don't let if follow through to workspace
return true;
}
+
+ @Override
+ public void onWallpaperChanged() {
+
+ }
+
+ @Override
+ public void onEnabledChanged() {
+ createBlurDrawable();
+ }
+
+ /**
+ * We only need to change left bound for hotseat blur layer.
+ */
+ public void changeBlurBounds(float factor, boolean reset) {
+ if(fullBlurDrawable != null) {
+ if(reset) {
+ factor = 0f;
+ }
+ fullBlurDrawable.setBounds((int) ((getRight() - getLeft()) * factor), getTop(), getRight(), getBottom());
+ fullBlurDrawable.invalidateSelf();
+ }
+ }
}
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/launcher/SearchInputDisposableObserver.java b/app/src/main/java/foundation/e/blisslauncher/features/launcher/SearchInputDisposableObserver.java
index fd0ad5010ffc7d662d82db89e32e58848b155a19..1aa6a0ff2607e2380aeb3e54d3108ea72c524998 100644
--- a/app/src/main/java/foundation/e/blisslauncher/features/launcher/SearchInputDisposableObserver.java
+++ b/app/src/main/java/foundation/e/blisslauncher/features/launcher/SearchInputDisposableObserver.java
@@ -43,7 +43,7 @@ public class SearchInputDisposableObserver extends DisposableObserver(),
suggestionsResults.queryText);
}
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/suggestions/AutoCompleteAdapter.java b/app/src/main/java/foundation/e/blisslauncher/features/suggestions/AutoCompleteAdapter.java
index 65943ddcfd3d4902e21a9ee772ee222499b7496a..dbf4e95730aac2f61f949f915cfcd044d272e929 100755
--- a/app/src/main/java/foundation/e/blisslauncher/features/suggestions/AutoCompleteAdapter.java
+++ b/app/src/main/java/foundation/e/blisslauncher/features/suggestions/AutoCompleteAdapter.java
@@ -16,6 +16,7 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import foundation.e.blisslauncher.R;
+import foundation.e.blisslauncher.core.customviews.LauncherPagedView;
import foundation.e.blisslauncher.features.launcher.LauncherActivity;
import foundation.e.blisslauncher.features.test.TestActivity;
@@ -32,7 +33,13 @@ public class AutoCompleteAdapter extends
public AutoCompleteAdapter(Context context) {
super();
- mOnSuggestionClickListener = (TestActivity) context;
+ mOnSuggestionClickListener = null;
+ mInflater = LayoutInflater.from(context);
+ }
+
+ public AutoCompleteAdapter(Context context, LauncherPagedView workspace) {
+ super();
+ mOnSuggestionClickListener = workspace;
mInflater = LayoutInflater.from(context);
}
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/test/BaseActivity.java b/app/src/main/java/foundation/e/blisslauncher/features/test/BaseActivity.java
index a84799e2e6904848ee498885df92eb192e5fce73..ec246472ed2acd2af47c05487af93c93bf4c02e9 100644
--- a/app/src/main/java/foundation/e/blisslauncher/features/test/BaseActivity.java
+++ b/app/src/main/java/foundation/e/blisslauncher/features/test/BaseActivity.java
@@ -24,6 +24,7 @@ import android.content.ContextWrapper;
import android.content.Intent;
import android.view.View.AccessibilityDelegate;
import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
import foundation.e.blisslauncher.core.utils.ViewCache;
import java.lang.annotation.Retention;
import java.util.ArrayList;
@@ -87,6 +88,7 @@ public abstract class BaseActivity extends Activity {
return mViewCache;
}
+ @NonNull
public VariantDeviceProfile getDeviceProfile() {
return mDeviceProfile;
}
@@ -137,6 +139,10 @@ public abstract class BaseActivity extends Activity {
mActivityFlags &= ~ACTIVITY_STATE_STARTED & ~ACTIVITY_STATE_USER_ACTIVE;
mForceInvisible = 0;
super.onStop();
+
+ // Reset the overridden sysui flags used for the task-swipe launch animation, this is a
+ // catch all for if we do not get resumed (and therefore not paused below)
+ getSystemUiController().updateUiState(SystemUiController.UI_STATE_OVERVIEW, 0);
}
@Override
@@ -148,7 +154,7 @@ public abstract class BaseActivity extends Activity {
// here instead of at the end of the animation because the start of the new activity does
// not happen immediately, which would cause us to reset to launcher's sysui flags and then
// back to the new app (causing a flash)
- getSystemUiController().updateUiState(SystemUiController.UI_STATE_NORMAL, 0);
+ getSystemUiController().updateUiState(SystemUiController.UI_STATE_OVERVIEW, 0);
}
public boolean isStarted() {
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/test/CellLayout.kt b/app/src/main/java/foundation/e/blisslauncher/features/test/CellLayout.kt
index 7931a580827c153dc1dda58d6562dfb7bb6df00a..94dbf46bdcd9a1d9e9ef7d5dedcb35c0598b2909 100644
--- a/app/src/main/java/foundation/e/blisslauncher/features/test/CellLayout.kt
+++ b/app/src/main/java/foundation/e/blisslauncher/features/test/CellLayout.kt
@@ -15,6 +15,8 @@ import android.os.Handler
import android.os.Looper
import android.util.ArrayMap
import android.util.AttributeSet
+import android.util.Log
+import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.view.animation.AnimationUtils
@@ -22,12 +24,14 @@ import android.widget.GridLayout
import androidx.annotation.IntDef
import foundation.e.blisslauncher.R
import foundation.e.blisslauncher.core.Utilities
+import foundation.e.blisslauncher.core.database.model.ApplicationItem
import foundation.e.blisslauncher.core.database.model.LauncherItem
+import foundation.e.blisslauncher.core.database.model.ShortcutItem
import foundation.e.blisslauncher.core.utils.Constants
-import foundation.e.blisslauncher.features.launcher.Hotseat
import foundation.e.blisslauncher.features.test.anim.Interpolators
import foundation.e.blisslauncher.features.test.dragndrop.DropTarget
import foundation.e.blisslauncher.features.test.graphics.DragPreviewProvider
+import foundation.e.blisslauncher.features.test.uninstall.UninstallHelper.isUninstallDisabled
import java.lang.Double.MAX_VALUE
import java.util.ArrayList
import java.util.Arrays
@@ -109,6 +113,8 @@ open class CellLayout @JvmOverloads constructor(
const val WORKSPACE = 0
const val HOTSEAT = 1
+
+ private val paint = Paint()
}
init {
@@ -190,13 +196,21 @@ open class CellLayout @JvmOverloads constructor(
}
}
+ override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
+ Log.d(
+ TAG,
+ "onLayout() called with: changed = $changed, left = $left, top = $top, right = $right, bottom = $bottom, ${Utilities.dpiFromPx(60, context.resources.displayMetrics)}"
+ )
+ super.onLayout(changed, left, top, right, bottom)
+ }
+
fun getContainerType() = mContainerType
open fun getCellContentHeight(): Int {
return Math.min(
measuredHeight,
launcher.deviceProfile
- .getCellHeight(if (parent is Hotseat) Constants.CONTAINER_HOTSEAT else Constants.CONTAINER_DESKTOP)
+ .getCellHeight(mContainerType)
)
}
@@ -211,10 +225,6 @@ open class CellLayout @JvmOverloads constructor(
requestLayout()
}
- override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
- super.onLayout(changed, left, top, right, bottom)
- }
-
fun measureChild(child: View) {
val lp = child.layoutParams as LayoutParams
lp.rowSpec = spec(UNDEFINED)
@@ -254,6 +264,17 @@ open class CellLayout @JvmOverloads constructor(
return false
}
+ open fun enableHardwareLayer(hasLayer: Boolean) {
+ setLayerType(
+ if (hasLayer) LAYER_TYPE_HARDWARE else LAYER_TYPE_NONE,
+ paint
+ )
+ }
+
+ open fun isHardwareLayerEnabled(): Boolean {
+ return layerType == LAYER_TYPE_HARDWARE
+ }
+
override fun cancelLongPress() {
super.cancelLongPress()
// Cancel long press for all children
@@ -811,19 +832,26 @@ open class CellLayout @JvmOverloads constructor(
result[1] = index / mCountX
}
- // appView.findViewById(R.id.app_label).setVisibility(GONE);
+ val genericLp: ViewGroup.LayoutParams = dragView.layoutParams
val rowSpec = spec(UNDEFINED)
val colSpec = spec(UNDEFINED)
- val iconLayoutParams = LayoutParams(rowSpec, colSpec)
- // iconLayoutParams.setGravity(Gravity.CENTER)
- iconLayoutParams.height = if (mContainerType == HOTSEAT)
- dp.hotseatCellHeightPx else dp.cellHeightPx
- iconLayoutParams.width = dp.cellWidthPx
- dragView.also {
- if (it is IconTextView) it.setTextVisibility(mContainerType != HOTSEAT)
+ val lp: LayoutParams
+ if (genericLp !is LayoutParams) {
+ lp = LayoutParams(rowSpec, colSpec)
+ } else {
+ lp = genericLp
+ lp.rowSpec = rowSpec
+ lp.columnSpec = colSpec
+ }
+ lp.setGravity(Gravity.CENTER)
+
+ // Get the canonical child id to uniquely represent this view in this screen
+
+ val childId: Int = launcher.getViewIdForItem(dragView.tag as LauncherItem)
+ dragView.apply {
+ if (this is IconTextView) setTextVisibility(mContainerType != HOTSEAT)
}
- dragView.layoutParams = iconLayoutParams
- addView(dragView, index)
+ addViewToCellLayout(dragView, index, childId, lp, true)
// Update item info after reordering so that we always save correct state in database.
// TODO: May optimize this
@@ -867,6 +895,26 @@ open class CellLayout @JvmOverloads constructor(
)
)
}
+
+ val info: LauncherItem = dragView.getTag() as LauncherItem
+ if ((info is ApplicationItem || info is ShortcutItem) && !isUninstallDisabled(
+ info.user.realHandle,
+ context
+ )
+ ) {
+ // Return early if this app is system app
+ if (info is ApplicationItem) {
+ if (info.isSystemApp != ApplicationItem.FLAG_SYSTEM_UNKNOWN) {
+ if (info.isSystemApp and ApplicationItem.FLAG_SYSTEM_NO != 0) {
+ dragView.applyUninstallIconState(true)
+ }
+ } else {
+ dragView.applyUninstallIconState(true)
+ }
+ } else if (info is ShortcutItem) {
+ dragView.applyUninstallIconState(true)
+ }
+ }
}
}
}
@@ -926,7 +974,7 @@ open class CellLayout @JvmOverloads constructor(
return if (cellIdx < mOccupied.cells.size) {
mOccupied.cells[cellIdx]
} else {
- throw RuntimeException("Position exceeds the bound of this CellLayout")
+ true
}
}
}
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/test/IconTextView.kt b/app/src/main/java/foundation/e/blisslauncher/features/test/IconTextView.kt
index dae87c1d82e8d938f5a4f0bdde62643250d0f645..87c4096dc79c7c2d79f11a2d2e4c264f9a770c0e 100644
--- a/app/src/main/java/foundation/e/blisslauncher/features/test/IconTextView.kt
+++ b/app/src/main/java/foundation/e/blisslauncher/features/test/IconTextView.kt
@@ -27,7 +27,6 @@ import foundation.e.blisslauncher.core.database.model.ShortcutItem
import foundation.e.blisslauncher.core.utils.Constants
import foundation.e.blisslauncher.features.notification.DotInfo
import foundation.e.blisslauncher.features.notification.DotRenderer
-import foundation.e.blisslauncher.features.notification.FolderDotInfo
import foundation.e.blisslauncher.features.test.uninstall.UninstallButtonRenderer
import kotlin.math.roundToInt
@@ -35,7 +34,7 @@ import kotlin.math.roundToInt
* A text view which displays an icon on top side of it.
*/
@SuppressLint("AppCompatCustomView")
-class IconTextView @JvmOverloads constructor(
+open class IconTextView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet?,
defStyle: Int
@@ -43,7 +42,6 @@ class IconTextView @JvmOverloads constructor(
companion object {
private const val DISPLAY_WORKSPACE = 1
- private const val DISPLAY_FOLDER = 2
private val STATE_PRESSED = intArrayOf(android.R.attr.state_pressed)
private const val TAG = "IconTextView"
@@ -98,7 +96,7 @@ class IconTextView @JvmOverloads constructor(
val bottom = top + defaultIconSize
return Rect(left, top, right, bottom)
}
- private val launcher: TestActivity = TestActivity.getLauncher(context)
+ val launcher: TestActivity = TestActivity.getLauncher(context)
private val dp = launcher.deviceProfile
private val defaultIconSize = dp.iconSizePx
@@ -115,7 +113,7 @@ class IconTextView @JvmOverloads constructor(
private var longPressHelper: CheckLongPressHelper
- private var mDotInfo: DotInfo? = null
+ protected var mDotInfo: DotInfo? = null
private var mDotScaleAnim: Animator? = null
private var mForceHideDot = false
@@ -134,6 +132,7 @@ class IconTextView @JvmOverloads constructor(
compoundDrawablePadding = dp.iconDrawablePaddingPx
ellipsize = TruncateAt.END
longPressHelper = CheckLongPressHelper(this)
+ setTextAlpha(1f)
}
override fun onFocusChanged(
@@ -153,7 +152,7 @@ class IconTextView @JvmOverloads constructor(
override fun setTextColor(colors: ColorStateList) {
mTextColor = colors.defaultColor
- if (java.lang.Float.compare(mTextAlpha, 1f) == 0) {
+ if (mTextAlpha.compareTo(1f) == 0) {
super.setTextColor(colors)
} else {
super.setTextColor(getModifiedColor())
@@ -198,13 +197,7 @@ class IconTextView @JvmOverloads constructor(
}
}
- fun setDotInfo(item: FolderItem, dotInfo: FolderDotInfo) {
- val wasDotted = mDotInfo is FolderDotInfo && (mDotInfo as FolderDotInfo).hasDot()
- updateDotScale(wasDotted, dotInfo.hasDot(), true)
- mDotInfo = dotInfo
- }
-
- private fun updateDotScale(wasDotted: Boolean, isDotted: Boolean, animate: Boolean) {
+ protected fun updateDotScale(wasDotted: Boolean, isDotted: Boolean, animate: Boolean) {
val newDotScale: Float = if (isDotted) 1f else 0f
mDotRenderer = mActivity.deviceProfile.mDotRenderer
if (wasDotted || isDotted) {
@@ -241,12 +234,12 @@ class IconTextView @JvmOverloads constructor(
mDotScaleAnim?.cancel()
}
- private fun animateDotScale(dotScales: Float) {
+ fun animateDotScale(vararg dotScales: Float) {
cancelDotScaleAnim()
mDotScaleAnim = ObjectAnimator.ofFloat(
this,
DOT_SCALE_PROPERTY,
- dotScales
+ *dotScales
).apply {
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
@@ -354,10 +347,7 @@ class IconTextView @JvmOverloads constructor(
}
}
- private fun hasDot(): Boolean {
- if (mDotInfo != null && mDotInfo is FolderDotInfo) {
- return (mDotInfo as FolderDotInfo).hasDot()
- }
+ open fun hasDot(): Boolean {
return mDotInfo != null
}
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/test/LauncherAppState.java b/app/src/main/java/foundation/e/blisslauncher/features/test/LauncherAppState.java
index 829cba995b4ea989934976563e074a5b6e65a9e4..e40c638ca353afc148e87834f777e064efdc6741 100644
--- a/app/src/main/java/foundation/e/blisslauncher/features/test/LauncherAppState.java
+++ b/app/src/main/java/foundation/e/blisslauncher/features/test/LauncherAppState.java
@@ -22,14 +22,20 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
import android.os.Looper;
+import android.os.UserHandle;
+import android.util.ArrayMap;
import android.util.Log;
+import androidx.annotation.NonNull;
import foundation.e.blisslauncher.core.ConfigMonitor;
import foundation.e.blisslauncher.core.UserManagerCompat;
import foundation.e.blisslauncher.core.executors.MainThreadExecutor;
import foundation.e.blisslauncher.core.utils.Preconditions;
import foundation.e.blisslauncher.core.utils.SecureSettingsObserver;
import foundation.e.blisslauncher.features.notification.NotificationListener;
+import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
@@ -45,6 +51,8 @@ public class LauncherAppState {
// We do not need any synchronization for this variable as its only written on UI thread.
private static LauncherAppState INSTANCE;
+ private LauncherApps launcherApps;
+
private final Context mContext;
private final InvariantDeviceProfile mInvariantDeviceProfile;
@@ -52,6 +60,9 @@ public class LauncherAppState {
private TestActivity launcher;
private LauncherModel mModel;
+ private final ArrayMap mCallbacks =
+ new ArrayMap<>();
+
public static LauncherAppState getInstance(final Context context) {
if (INSTANCE == null) {
if (Looper.myLooper() == Looper.getMainLooper()) {
@@ -82,6 +93,7 @@ public class LauncherAppState {
private LauncherAppState(Context context) {
+ launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
Log.v(TestActivity.TAG, "LauncherAppState initiated");
Preconditions.assertUIThread();
mContext = context;
@@ -89,6 +101,11 @@ public class LauncherAppState {
mInvariantDeviceProfile = new InvariantDeviceProfile(mContext);
mModel = new LauncherModel(this);
+ WrappedCallback wrappedCallback = new WrappedCallback(mModel);
+ synchronized (mCallbacks) {
+ mCallbacks.put(mModel, wrappedCallback);
+ }
+ launcherApps.registerCallback(wrappedCallback);
// Register intent receivers
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_LOCALE_CHANGED);
@@ -129,6 +146,13 @@ public class LauncherAppState {
if (mNotificationDotsObserver != null) {
mNotificationDotsObserver.unregister();
}
+ final WrappedCallback wrappedCallback;
+ synchronized (mCallbacks) {
+ wrappedCallback = mCallbacks.remove(mModel);
+ }
+ if (wrappedCallback != null) {
+ launcherApps.unregisterCallback(wrappedCallback);
+ }
}
LauncherModel setLauncher(TestActivity launcher) {
@@ -153,4 +177,54 @@ public class LauncherAppState {
}
+ private static class WrappedCallback extends LauncherApps.Callback {
+ private final OnAppsChangedCallback mCallback;
+
+ public WrappedCallback(OnAppsChangedCallback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void onPackageRemoved(String packageName, UserHandle user) {
+ mCallback.onPackageRemoved(packageName, user);
+ }
+
+ @Override
+ public void onPackageAdded(String packageName, UserHandle user) {
+ mCallback.onPackageAdded(packageName, user);
+ }
+
+ @Override
+ public void onPackageChanged(String packageName, UserHandle user) {
+ mCallback.onPackageChanged(packageName, user);
+ }
+
+ @Override
+ public void onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing) {
+ mCallback.onPackagesAvailable(packageNames, user, replacing);
+ }
+
+ @Override
+ public void onPackagesUnavailable(String[] packageNames, UserHandle user,
+ boolean replacing) {
+ mCallback.onPackagesUnavailable(packageNames, user, replacing);
+ }
+
+ @Override
+ public void onPackagesSuspended(String[] packageNames, UserHandle user) {
+ mCallback.onPackagesSuspended(packageNames, user);
+ }
+
+ @Override
+ public void onPackagesUnsuspended(String[] packageNames, UserHandle user) {
+ mCallback.onPackagesUnsuspended(packageNames, user);
+ }
+
+ @Override
+ public void onShortcutsChanged(@NonNull String packageName,
+ @NonNull List shortcuts,
+ @NonNull UserHandle user) {
+ mCallback.onShortcutsChanged(packageName, shortcuts, user);
+ }
+ }
}
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/test/LauncherItemMatcher.java b/app/src/main/java/foundation/e/blisslauncher/features/test/LauncherItemMatcher.java
index a40b0dd9ca32e5795a3a8a3a38a3d60b336c4415..88f43c8c80fb4eb30d7dd9f4aa620426f184be4d 100644
--- a/app/src/main/java/foundation/e/blisslauncher/features/test/LauncherItemMatcher.java
+++ b/app/src/main/java/foundation/e/blisslauncher/features/test/LauncherItemMatcher.java
@@ -5,6 +5,7 @@ import android.os.UserHandle;
import java.util.HashSet;
+import foundation.e.blisslauncher.core.database.model.ApplicationItem;
import foundation.e.blisslauncher.core.database.model.FolderItem;
import foundation.e.blisslauncher.core.database.model.LauncherItem;
import foundation.e.blisslauncher.core.database.model.ShortcutItem;
@@ -22,7 +23,13 @@ public abstract class LauncherItemMatcher {
public final HashSet filterItemInfos(Iterable infos) {
HashSet filtered = new HashSet<>();
for (LauncherItem i : infos) {
- if (i instanceof ShortcutItem) {
+ if (i instanceof ApplicationItem) {
+ ApplicationItem info = (ApplicationItem) i;
+ ComponentName cn = info.getTargetComponent();
+ if (cn != null && matches(info, cn)) {
+ filtered.add(info);
+ }
+ } else if (i instanceof ShortcutItem) {
ShortcutItem info = (ShortcutItem) i;
ComponentName cn = info.getTargetComponent();
if (cn != null && matches(info, cn)) {
@@ -106,7 +113,7 @@ public abstract class LauncherItemMatcher {
return new LauncherItemMatcher() {
@Override
public boolean matches(LauncherItem info, ComponentName cn) {
- return packageNames.contains(cn.getPackageName()) && info.user.equals(user);
+ return packageNames.contains(cn.getPackageName()) && info.user.getRealHandle().equals(user);
}
};
}
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/test/LauncherModel.java b/app/src/main/java/foundation/e/blisslauncher/features/test/LauncherModel.java
index 46557bc4cfddd340c7d935c3eaa67f8dfc861076..5d051c3b06ed5527712dd10b139b76767056a108 100644
--- a/app/src/main/java/foundation/e/blisslauncher/features/test/LauncherModel.java
+++ b/app/src/main/java/foundation/e/blisslauncher/features/test/LauncherModel.java
@@ -1,48 +1,152 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package foundation.e.blisslauncher.features.test;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.LauncherActivityInfo;
+import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Process;
-import android.telecom.Call;
+import android.os.UserHandle;
import android.util.Log;
import android.util.Pair;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
+import foundation.e.blisslauncher.core.UserManagerCompat;
+import foundation.e.blisslauncher.core.Utilities;
+import foundation.e.blisslauncher.core.database.model.ApplicationItem;
import foundation.e.blisslauncher.core.database.model.LauncherItem;
import foundation.e.blisslauncher.core.executors.MainThreadExecutor;
+import foundation.e.blisslauncher.core.utils.AppUtils;
import foundation.e.blisslauncher.core.utils.Constants;
+import foundation.e.blisslauncher.core.utils.FlagOp;
+import foundation.e.blisslauncher.core.utils.ItemInfoMatcher;
import foundation.e.blisslauncher.core.utils.Preconditions;
-import foundation.e.blisslauncher.features.shortcuts.DeepShortcutManager;
+import foundation.e.blisslauncher.features.shortcuts.InstallShortcutReceiver;
-public class LauncherModel extends BroadcastReceiver {
+public class LauncherModel extends BroadcastReceiver implements
+ OnAppsChangedCallback {
private static final boolean DEBUG_RECEIVER = false;
static final String TAG = "Launcher.Model";
private final MainThreadExecutor mUiExecutor = new MainThreadExecutor();
- final LauncherAppState mApp;
+ final LauncherAppState mApp;
final Object mLock = new Object();
WeakReference mCallbacks;
static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
private static final Looper mWorkerLooper;
+
static {
sWorkerThread.start();
mWorkerLooper = sWorkerThread.getLooper();
}
+
static final Handler sWorker = new Handler(mWorkerLooper);
+ @Override
+ public void onPackageRemoved(String packageName, UserHandle user) {
+ // TODO: Handle package removed here.
+ onPackagesRemoved(user, packageName);
+ }
+
+ public void onPackagesRemoved(UserHandle user, String... packages) {
+ final HashSet removedPackages = new HashSet<>();
+ Collections.addAll(removedPackages, packages);
+ if (!removedPackages.isEmpty()) {
+ LauncherItemMatcher removeMatch = LauncherItemMatcher.ofPackages(removedPackages, user);
+ deleteAndBindComponentsRemoved(removeMatch);
+
+ // Remove any queued items from the install queue
+ if (sWorkerThread.getThreadId() == Process.myTid()) {
+ } else {
+ // If we are not on the worker thread, then post to the worker handler
+ sWorker.post(() -> InstallShortcutReceiver
+ .removeFromInstallQueue(mApp.getContext(), removedPackages, user));
+ }
+ }
+ }
+
+ private void deleteAndBindComponentsRemoved(LauncherItemMatcher removeMatch) {
+ mCallbacks.get().bindWorkspaceComponentsRemoved(removeMatch);
+ }
+
+ @Override
+ public void onPackageAdded(String packageName, UserHandle user) {
+ final Context context = mApp.getContext();
+ FlagOp flagOp = FlagOp.NO_OP;
+ final HashSet packageSet = new HashSet<>(Arrays.asList(packageName));
+ ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(packageSet, user);
+
+ final List added = new ArrayList<>();
+ added.addAll(AppUtils.createAppItems(context,
+ packageName,
+ new foundation.e.blisslauncher.core.utils.UserHandle(UserManagerCompat
+ .getInstance(context).getSerialNumberForUser(user), user)
+ ));
+ mUiExecutor.execute(() -> mCallbacks.get().bindAppsAdded(added));
+ }
+
+ @Override
+ public void onPackageChanged(String packageName, UserHandle user) {
+
+ }
+
+ @Override
+ public void onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing) {
+
+ }
+
+ @Override
+ public void onPackagesUnavailable(String[] packageNames, UserHandle user, boolean replacing) {
+
+ }
+
+ @Override
+ public void onPackagesSuspended(String[] packageNames, UserHandle user) {
+
+ }
+
+ @Override
+ public void onPackagesUnsuspended(String[] packageNames, UserHandle user) {
+
+ }
+
+ @Override
+ public void onShortcutsChanged(
+ String packageName, List shortcuts, UserHandle user
+ ) {
+
+ }
+
// Runnable to check if the shortcuts permission has changed.
/*private final Runnable mShortcutPermissionCheckRunnable = new Runnable() {
@Override
@@ -59,6 +163,8 @@ public class LauncherModel extends BroadcastReceiver {
public interface Callbacks {
void bindAppsAdded(List items);
+
+ void bindWorkspaceComponentsRemoved(LauncherItemMatcher matcher);
}
LauncherModel(LauncherAppState app) {
@@ -87,13 +193,12 @@ public class LauncherModel extends BroadcastReceiver {
Callbacks callbacks = getCallback();
if (callbacks != null) {
//callbacks.preAddApps();
- List items = new ArrayList<>();
+ List items = new ArrayList<>();
for (Pair entry : itemList) {
items.add(entry.first);
}
mUiExecutor.execute(() -> callbacks.bindAppsAdded(items));
}
-
}
public Callbacks getCallback() {
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/test/LauncherRootView.java b/app/src/main/java/foundation/e/blisslauncher/features/test/LauncherRootView.java
index e763b81f45d7ebbfb454c0e6efde9576fc465735..69e9f33d0eea6363c1423d6d137abe9012f08b37 100644
--- a/app/src/main/java/foundation/e/blisslauncher/features/test/LauncherRootView.java
+++ b/app/src/main/java/foundation/e/blisslauncher/features/test/LauncherRootView.java
@@ -10,18 +10,28 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
+import android.util.IntProperty;
+import android.util.Log;
+import android.util.Property;
import android.view.View;
import android.view.ViewDebug;
import android.view.WindowInsets;
+import androidx.annotation.NonNull;
import foundation.e.blisslauncher.core.Utilities;
+import foundation.e.blisslauncher.core.blur.BlurWallpaperProvider;
+import foundation.e.blisslauncher.core.blur.ShaderBlurDrawable;
import foundation.e.blisslauncher.core.customviews.InsettableFrameLayout;
+import foundation.e.blisslauncher.core.executors.MainThreadExecutor;
+import foundation.e.blisslauncher.features.test.anim.Interpolators;
import java.util.Collections;
import java.util.List;
import org.jetbrains.annotations.Nullable;
-public class LauncherRootView extends InsettableFrameLayout {
+public class LauncherRootView extends InsettableFrameLayout implements
+ BlurWallpaperProvider.Listener {
private final Rect mTempRect = new Rect();
@@ -39,6 +49,53 @@ public class LauncherRootView extends InsettableFrameLayout {
private WindowStateListener mWindowStateListener;
private boolean mDisallowBackGesture;
+ private BlurWallpaperProvider blurWallpaperProvider;
+ private ShaderBlurDrawable fullBlurDrawable;
+ MainThreadExecutor mainThreadExecutor = new MainThreadExecutor();
+ private Drawable.Callback blurDrawableCallback = new Drawable.Callback() {
+ @Override
+ public void invalidateDrawable(@NonNull Drawable who) {
+ mainThreadExecutor.execute(() -> invalidate());
+ }
+
+ @Override
+ public void scheduleDrawable(
+ @NonNull Drawable who, @NonNull Runnable what, long when
+ ) {
+
+ }
+
+ @Override
+ public void unscheduleDrawable(
+ @NonNull Drawable who, @NonNull Runnable what
+ ) {
+
+ }
+ };
+
+ /**
+ * A Property wrapper around the blur alpha functionality.
+ *
+ * Note: Blur alpha values varies between 0 to 255.
+ */
+ public static final Property BLUR_ALPHA =
+ new IntProperty("blur_alpha") {
+ @Override
+ public Integer get(LauncherRootView object) {
+ Log.d("LauncherRootView", "get() called with: object = [" + object + "]");
+ return object.getBlurAlpha();
+ }
+
+ @Override
+ public void setValue(LauncherRootView object, int value) {
+ Log.d(
+ "LauncherRootView",
+ "setValue() called with: object = [" + object + "], value = [" + value + "]"
+ );
+ object.setBlurAlpha(value);
+ }
+ };
+
public LauncherRootView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -46,7 +103,44 @@ public class LauncherRootView extends InsettableFrameLayout {
mOpaquePaint.setColor(Color.BLACK);
mOpaquePaint.setStyle(Paint.Style.FILL);
+ setWillNotDraw(false);
mLauncher = TestActivity.Companion.getLauncher(context);
+ blurWallpaperProvider = BlurWallpaperProvider.Companion.getInstance(context);
+ createBlurDrawable();
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ blurWallpaperProvider.addListener(this);
+ if (fullBlurDrawable != null) {
+ fullBlurDrawable.startListening();
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ blurWallpaperProvider.removeListener(this);
+ if (fullBlurDrawable != null) {
+ fullBlurDrawable.stopListening();
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (fullBlurDrawable != null) {
+ fullBlurDrawable.draw(canvas);
+ }
+ super.onDraw(canvas);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (changed && fullBlurDrawable != null) {
+ fullBlurDrawable.setBounds(left, top, right, bottom);
+ }
}
@Override
@@ -69,7 +163,7 @@ public class LauncherRootView extends InsettableFrameLayout {
mConsumedInsets.bottom = insets.bottom;
insets.set(0, insets.top, 0, 0);
drawInsetBar = true;
- } else if ((insets.right > 0 || insets.left > 0) &&
+ } else if ((insets.right > 0 || insets.left > 0) &&
getContext().getSystemService(ActivityManager.class).isLowRamDevice()) {
mConsumedInsets.left = insets.left;
mConsumedInsets.right = insets.right;
@@ -106,12 +200,14 @@ public class LauncherRootView extends InsettableFrameLayout {
@Override
public WindowInsets onApplyWindowInsets(@Nullable WindowInsets insets) {
mTempRect.set(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(),
- insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
+ insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()
+ );
handleSystemWindowInsets(mTempRect);
if (Utilities.ATLEAST_Q) {
return insets.inset(mConsumedInsets.left, mConsumedInsets.top,
- mConsumedInsets.right, mConsumedInsets.bottom);
+ mConsumedInsets.right, mConsumedInsets.bottom
+ );
} else {
return insets.replaceSystemWindowInsets(mTempRect);
}
@@ -180,6 +276,54 @@ public class LauncherRootView extends InsettableFrameLayout {
: Collections.emptyList());
}
+ @Override
+ public void onEnabledChanged() {
+ createBlurDrawable();
+ }
+
+ @Override
+ public void onWallpaperChanged() {
+
+ }
+
+ private void createBlurDrawable() {
+ if (isAttachedToWindow() && fullBlurDrawable != null) {
+ fullBlurDrawable.stopListening();
+ }
+ fullBlurDrawable = blurWallpaperProvider.createDrawable();
+ fullBlurDrawable.setCallback(blurDrawableCallback);
+ fullBlurDrawable.setBounds(getLeft(), getTop(), getRight(), getBottom());
+ if (isAttachedToWindow() && fullBlurDrawable != null)
+ fullBlurDrawable.startListening();
+ }
+
+ /**
+ * We only need to change left bound for hotseat blur layer.
+ */
+ public void changeBlurBounds(float factor, boolean isReset) {
+ if (fullBlurDrawable != null) {
+ float alpha = Interpolators.DEACCEL_1_5.getInterpolation(factor);
+ if(isReset) {
+ factor = 1;
+ }
+ fullBlurDrawable.setBounds(getLeft(),
+ getTop(),
+ (int) ((getRight() - getLeft()) * factor),
+ getBottom()
+ );
+ setBlurAlpha((int) (255 * alpha));
+ }
+ }
+
+ public void setBlurAlpha(int alpha) {
+ Log.d("LauncherRootView", "setBlurAlpha() called with: alpha = [" + alpha + "]");
+ fullBlurDrawable.setAlpha(alpha);
+ }
+
+ public int getBlurAlpha() {
+ return fullBlurDrawable.getAlpha();
+ }
+
public interface WindowStateListener {
void onWindowFocusChanged(boolean hasFocus);
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/test/OnAppsChangedCallback.java b/app/src/main/java/foundation/e/blisslauncher/features/test/OnAppsChangedCallback.java
new file mode 100644
index 0000000000000000000000000000000000000000..9c5433320f938895e921372c26633a3280ddb549
--- /dev/null
+++ b/app/src/main/java/foundation/e/blisslauncher/features/test/OnAppsChangedCallback.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package foundation.e.blisslauncher.features.test;
+
+import android.content.pm.ShortcutInfo;
+import android.os.UserHandle;
+
+import java.util.List;
+
+public interface OnAppsChangedCallback {
+ void onPackageRemoved(String packageName, UserHandle user);
+ void onPackageAdded(String packageName, UserHandle user);
+ void onPackageChanged(String packageName, UserHandle user);
+ void onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing);
+ void onPackagesUnavailable(String[] packageNames, UserHandle user, boolean replacing);
+ void onPackagesSuspended(String[] packageNames, UserHandle user);
+ void onPackagesUnsuspended(String[] packageNames, UserHandle user);
+ void onShortcutsChanged(String packageName, List shortcuts,
+ UserHandle user);
+}
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/test/TestActivity.kt b/app/src/main/java/foundation/e/blisslauncher/features/test/TestActivity.kt
index e946064eee1000bd5107ec7d302ca9b44bcafd1c..3d885c576cd2b37b1d2f1d5a7da007e98e7e4247 100644
--- a/app/src/main/java/foundation/e/blisslauncher/features/test/TestActivity.kt
+++ b/app/src/main/java/foundation/e/blisslauncher/features/test/TestActivity.kt
@@ -1,29 +1,21 @@
package foundation.e.blisslauncher.features.test
import android.Manifest
-import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
-import android.animation.AnimatorSet
-import android.animation.ObjectAnimator
-import android.animation.ValueAnimator
import android.app.ActivityOptions
import android.app.AlertDialog
-import android.app.usage.UsageStats
+import android.app.WallpaperManager
import android.appwidget.AppWidgetManager
-import android.appwidget.AppWidgetProviderInfo
-import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
-import android.content.IntentFilter
import android.content.pm.ActivityInfo
import android.content.pm.ApplicationInfo
import android.content.pm.LauncherActivityInfo
import android.content.pm.LauncherApps
+import android.content.pm.PackageManager
import android.content.res.Configuration
import android.graphics.Point
-import android.graphics.Rect
import android.location.LocationManager
import android.net.Uri
import android.os.Bundle
@@ -33,107 +25,62 @@ import android.os.Process
import android.os.StrictMode
import android.os.StrictMode.VmPolicy
import android.provider.Settings
-import android.text.Editable
-import android.text.TextWatcher
import android.util.Log
import android.view.ContextThemeWrapper
-import android.view.KeyEvent
import android.view.LayoutInflater
-import android.view.MotionEvent
import android.view.View
-import android.view.ViewGroup
-import android.view.animation.AccelerateDecelerateInterpolator
-import android.view.animation.LinearInterpolator
-import android.view.inputmethod.EditorInfo
+import android.view.View.OnAttachStateChangeListener
import android.view.inputmethod.InputMethodManager
import android.widget.GridLayout
-import android.widget.ImageView
-import android.widget.LinearLayout
-import android.widget.RelativeLayout
-import android.widget.SeekBar
-import android.widget.TextView
import android.widget.Toast
-import androidx.core.view.isVisible
-import androidx.localbroadcastmanager.content.LocalBroadcastManager
-import androidx.recyclerview.widget.DividerItemDecoration
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
-import androidx.viewpager.widget.ViewPager
-import com.jakewharton.rxbinding3.widget.textChanges
+import androidx.core.app.ActivityCompat
import foundation.e.blisslauncher.BlissLauncher
import foundation.e.blisslauncher.R
import foundation.e.blisslauncher.core.Preferences
import foundation.e.blisslauncher.core.Utilities
+import foundation.e.blisslauncher.core.blur.BlurWallpaperProvider
+import foundation.e.blisslauncher.core.broadcast.WallpaperChangeReceiver
import foundation.e.blisslauncher.core.customviews.AbstractFloatingView
import foundation.e.blisslauncher.core.customviews.BlissFrameLayout
-import foundation.e.blisslauncher.core.customviews.BlissInput
-import foundation.e.blisslauncher.core.customviews.InsettableFrameLayout
import foundation.e.blisslauncher.core.customviews.LauncherPagedView
import foundation.e.blisslauncher.core.customviews.RoundedWidgetView
import foundation.e.blisslauncher.core.customviews.SquareFrameLayout
import foundation.e.blisslauncher.core.customviews.WidgetHost
-import foundation.e.blisslauncher.core.database.DatabaseManager
import foundation.e.blisslauncher.core.database.model.ApplicationItem
-import foundation.e.blisslauncher.core.database.model.FolderItem
import foundation.e.blisslauncher.core.database.model.LauncherItem
import foundation.e.blisslauncher.core.database.model.ShortcutItem
-import foundation.e.blisslauncher.core.executors.AppExecutors
-import foundation.e.blisslauncher.core.utils.AppUtils
import foundation.e.blisslauncher.core.utils.Constants
import foundation.e.blisslauncher.core.utils.IntSet
import foundation.e.blisslauncher.core.utils.IntegerArray
-import foundation.e.blisslauncher.core.utils.ListUtil
import foundation.e.blisslauncher.core.utils.PackageUserKey
-import foundation.e.blisslauncher.core.utils.UserHandle
-import foundation.e.blisslauncher.features.folder.FolderPagerAdapter
+import foundation.e.blisslauncher.features.launcher.AppsRepository
import foundation.e.blisslauncher.features.launcher.Hotseat
-import foundation.e.blisslauncher.features.launcher.SearchInputDisposableObserver
import foundation.e.blisslauncher.features.notification.DotInfo
import foundation.e.blisslauncher.features.notification.NotificationDataProvider
import foundation.e.blisslauncher.features.notification.NotificationListener
import foundation.e.blisslauncher.features.shortcuts.DeepShortcutManager
import foundation.e.blisslauncher.features.shortcuts.ShortcutKey
-import foundation.e.blisslauncher.features.suggestions.AutoCompleteAdapter
import foundation.e.blisslauncher.features.suggestions.SearchSuggestionUtil
-import foundation.e.blisslauncher.features.suggestions.SuggestionsResult
import foundation.e.blisslauncher.features.test.LauncherState.*
import foundation.e.blisslauncher.features.test.RotationHelper.REQUEST_NONE
import foundation.e.blisslauncher.features.test.dragndrop.DragController
import foundation.e.blisslauncher.features.test.dragndrop.DragLayer
import foundation.e.blisslauncher.features.test.graphics.RotationMode
-import foundation.e.blisslauncher.features.usagestats.AppUsageStats
-import foundation.e.blisslauncher.features.weather.DeviceStatusService
-import foundation.e.blisslauncher.features.weather.ForecastBuilder
import foundation.e.blisslauncher.features.weather.WeatherPreferences
-import foundation.e.blisslauncher.features.weather.WeatherSourceListenerService
import foundation.e.blisslauncher.features.weather.WeatherUpdateService
-import foundation.e.blisslauncher.features.widgets.WidgetManager
-import foundation.e.blisslauncher.features.widgets.WidgetViewBuilder
-import foundation.e.blisslauncher.features.widgets.WidgetsActivity
-import foundation.e.blisslauncher.features.widgets.WidgetsRootView
import foundation.e.blisslauncher.uioverrides.OverlayCallbackImpl
import foundation.e.blisslauncher.uioverrides.UiFactory
-import io.reactivex.Observable
-import io.reactivex.ObservableSource
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.observers.DisposableObserver
-import io.reactivex.schedulers.Schedulers
-import java.lang.Exception
import java.net.URISyntaxException
import java.util.ArrayList
-import java.util.Arrays
-import java.util.Comparator
-import java.util.Locale
-import java.util.concurrent.TimeUnit
import java.util.function.Predicate
-import me.relex.circleindicator.CircleIndicator
-class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionClickListener,
- LauncherModel.Callbacks {
+class TestActivity : BaseDraggingActivity(), LauncherModel.Callbacks {
+ private var mIsEditingName: Boolean = false
private var mModel: LauncherModel? = null
- private lateinit var widgetRootView: WidgetsRootView
private lateinit var overlayCallbackImpl: OverlayCallbackImpl
// Folder start scale
@@ -164,9 +111,6 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
private lateinit var dragLayer: DragLayer
private lateinit var workspace: LauncherPagedView
private lateinit var hotseat: Hotseat
- private lateinit var widgetPage: InsettableFrameLayout
-
- private lateinit var mSearchInput: BlissInput
private val REQUEST_LOCATION_SOURCE_SETTING = 267
@@ -177,43 +121,13 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
// UI and state for the overview panel
private lateinit var overviewPanel: View
- private lateinit var folderContainer: RelativeLayout
-
private val mOnResumeCallbacks = ArrayList()
- private lateinit var mAppWidgetManager: AppWidgetManager
- private lateinit var mAppWidgetHost: WidgetHost
- private lateinit var widgetContainer: LinearLayout
- private var activeRoundedWidgetView: RoundedWidgetView? = null
-
- private lateinit var mWeatherPanel: View
- private lateinit var mWeatherSetupTextView: View
- private val allAppsDisplayed = false
- private val forceRefreshSuggestedApps = false
-
- private var mUsageStats: List? = null
-
- private var enableLocationDialog: AlertDialog? = null
-
- private var currentAnimator: AnimatorSet? = null
-
- private var activeFolder: FolderItem? = null
- private var activeFolderView: IconTextView? = null
- private var activeFolderStartBounds = Rect()
-
- private var mFolderAppsViewPager: ViewPager? = null
- private var mFolderTitleInput: BlissInput? = null
+ lateinit var mAppWidgetManager: AppWidgetManager
+ lateinit var mAppWidgetHost: WidgetHost
private val mainHandler = Handler(Looper.getMainLooper())
- private val mWeatherReceiver: BroadcastReceiver = object : BroadcastReceiver() {
- override fun onReceive(context: Context, intent: Intent) {
- if (!intent.getBooleanExtra(WeatherUpdateService.EXTRA_UPDATE_CANCELLED, false)) {
- updateWeatherPanel()
- }
- }
- }
-
private lateinit var notificationDataProvider: NotificationDataProvider
val mHandler = Handler()
private val mHandleDeferredResume = Runnable { this.handleDeferredResume() }
@@ -221,6 +135,8 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
private val TAG = "TestActivity"
+ private var wallpaperChangeReceiver: WallpaperChangeReceiver? = null
+
override fun onCreate(savedInstanceState: Bundle?) {
if (DEBUG_STRICT_MODE) {
StrictMode.setThreadPolicy(
@@ -253,6 +169,8 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
mAppWidgetHost = BlissLauncher.getApplication(this).appWidgetHost
initDeviceProfile(BlissLauncher.getApplication(this).invariantDeviceProfile)
+ val wm = getSystemService(WALLPAPER_SERVICE) as WallpaperManager
+ wm.suggestDesiredDimensions(mDeviceProfile.widthPx, mDeviceProfile.heightPx)
dragController = DragController(this)
rotationHelper = RotationHelper(this)
mStateManager = LauncherStateManager(this)
@@ -277,7 +195,7 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
systemUiController.updateUiState(
SystemUiController.UI_STATE_BASE_WINDOW,
- true
+ false
)
rotationHelper.initialize()
TraceHelper.endSection("Launcher-onCreate")
@@ -293,9 +211,20 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
}
}
})
+
+ if (ActivityCompat.checkSelfPermission(
+ this,
+ Manifest.permission.READ_EXTERNAL_STORAGE
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ requestPermissions(
+ arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
+ STORAGE_PERMISSION_REQUEST_CODE
+ )
+ }
createOrUpdateIconGrid()
overlayCallbackImpl = OverlayCallbackImpl(this)
- setLauncherOverlay(overlayCallbackImpl)
+ // setLauncherOverlay(overlayCallbackImpl)
}
private fun askForNotificationIfFirstTime() {
@@ -416,193 +345,45 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
workspace.initParentViews(dragLayer)
overviewPanel = findViewById(R.id.overview_panel)
hotseat = findViewById(R.id.hotseat)
- folderContainer = findViewById(R.id.folder_window_container)
- mFolderAppsViewPager = findViewById(R.id.folder_apps)
- mFolderTitleInput = findViewById(R.id.folder_title)
+
launcherView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
dragLayer.setup(dragController, workspace)
mCancelTouchController = UiFactory.enableLiveUIChanges(this)
workspace.setup(dragController)
- setupWidgetPage()
- workspace.bindAndInitFirstScreen(null)
dragController.addDragListener(workspace)
dragController.addDropTarget(workspace)
// Setup the drag controller (drop targets have to be added in reverse order in priority)
dragController.setMoveTarget(workspace)
- }
-
- private fun setupWidgetPage() {
- widgetPage =
- layoutInflater.inflate(R.layout.widgets_page, rootView, false) as InsettableFrameLayout
- rootView.addView(widgetPage)
-
- widgetContainer = widgetPage.findViewById(R.id.widget_container)
-
- widgetPage.visibility = View.VISIBLE
- widgetPage.post {
- widgetPage.translationX = -(widgetPage.measuredWidth * 1.00f)
- }
- widgetRootView = widgetPage.findViewById(R.id.widgets_scroll_container)
- widgetPage.findViewById(R.id.used_apps_layout).clipToOutline = true
- widgetPage.tag = "Widget page"
-
- // TODO: replace with app predictions
- // Prepare app suggestions view
- // [[BEGIN]]
- widgetPage.findViewById(R.id.openUsageAccessSettings).setOnClickListener {
- startActivity(
- Intent(
- Settings.ACTION_USAGE_ACCESS_SETTINGS
- )
- )
- }
-
- // divided by 2 because of left and right padding.
- val padding = (mDeviceProfile.availableWidthPx / 2 - Utilities.pxFromDp(8, this) -
- (2 *
- mDeviceProfile.cellWidthPx)).toInt()
- widgetPage.findViewById(R.id.suggestedAppGrid).setPadding(padding, 0, padding, 0)
- // [[END]]
-
- // Prepare search suggestion view
- // [[BEGIN]]
- mSearchInput = widgetPage.findViewById(R.id.search_input)
- val clearSuggestions: ImageView =
- widgetPage.findViewById(R.id.clearSuggestionImageView)
- clearSuggestions.setOnClickListener {
- mSearchInput.setText("")
- mSearchInput.clearFocus()
- }
-
- mSearchInput.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
- if (s.toString().trim { it <= ' ' }.isEmpty()) {
- clearSuggestions.visibility = View.GONE
- } else {
- clearSuggestions.visibility = View.VISIBLE
- }
- }
-
- override fun afterTextChanged(s: Editable) {}
- })
- val suggestionRecyclerView: RecyclerView =
- widgetPage.findViewById(R.id.suggestionRecyclerView)
- val suggestionAdapter = AutoCompleteAdapter(this)
- suggestionRecyclerView.setHasFixedSize(true)
- suggestionRecyclerView.layoutManager =
- LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
- suggestionRecyclerView.adapter = suggestionAdapter
- val dividerItemDecoration = DividerItemDecoration(
- this,
- DividerItemDecoration.VERTICAL
- )
- suggestionRecyclerView.addItemDecoration(dividerItemDecoration)
- getCompositeDisposable().add(
- mSearchInput.textChanges()
- .debounce(300, TimeUnit.MILLISECONDS)
- .map { obj: CharSequence -> obj.toString() }
- .distinctUntilChanged()
- .switchMap { charSequence: String? ->
- if (charSequence != null && charSequence.isNotEmpty()) {
- searchForQuery(charSequence)
- } else {
- Observable.just(
- SuggestionsResult(charSequence)
- )
- }
- }
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeWith(
- SearchInputDisposableObserver(this, suggestionAdapter, widgetPage)
- )
- )
- mSearchInput.onFocusChangeListener =
- View.OnFocusChangeListener { v: View, hasFocus: Boolean ->
- if (!hasFocus) {
- hideKeyboard(v)
- }
+ wallpaperChangeReceiver = WallpaperChangeReceiver(workspace)
+ workspace.addOnAttachStateChangeListener(object : OnAttachStateChangeListener {
+ override fun onViewAttachedToWindow(v: View) {
+ wallpaperChangeReceiver?.setWindowToken(v.windowToken)
}
- mSearchInput.setOnEditorActionListener { _: TextView?, action: Int, _: KeyEvent? ->
- if (action == EditorInfo.IME_ACTION_SEARCH) {
- hideKeyboard(mSearchInput)
- runSearch(mSearchInput.text.toString())
- mSearchInput.setText("")
- mSearchInput.clearFocus()
- return@setOnEditorActionListener true
- }
- false
- }
- // [[END]]
-
- // Prepare edit widgets button
- findViewById(R.id.edit_widgets_button).setOnClickListener { view: View? ->
- startActivity(
- Intent(
- this,
- WidgetsActivity::class.java
- )
- )
- }
-
- // Prepare weather widget view
- // [[BEGIN]]
- findViewById(R.id.weather_setting_imageview).setOnClickListener { v: View? ->
- startActivity(
- Intent(
- this,
- WeatherPreferences::class.java
- )
- )
- }
-
- mWeatherSetupTextView = findViewById(R.id.weather_setup_textview)
- mWeatherPanel = findViewById(R.id.weather_panel)
- mWeatherPanel.setOnClickListener(View.OnClickListener { v: View? ->
- val launchIntent =
- packageManager.getLaunchIntentForPackage(
- "foundation.e.weather"
- )
- if (launchIntent != null) {
- launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- startActivity(launchIntent)
+ override fun onViewDetachedFromWindow(v: View) {
+ wallpaperChangeReceiver?.setWindowToken(null)
}
})
- updateWeatherPanel()
-
- if (foundation.e.blisslauncher.features.weather.WeatherUtils.isWeatherServiceAvailable(
- this
- )
- ) {
- startService(Intent(this, WeatherSourceListenerService::class.java))
- startService(Intent(this, DeviceStatusService::class.java))
- }
-
- LocalBroadcastManager.getInstance(this).registerReceiver(
- mWeatherReceiver, IntentFilter(
- WeatherUpdateService.ACTION_UPDATE_FINISHED
- )
- )
+ }
- if (!Preferences.useCustomWeatherLocation(this)) {
- if (!WeatherPreferences.hasLocationPermission(this)) {
- val permissions = arrayOf(Manifest.permission.ACCESS_FINE_LOCATION)
- requestPermissions(
- permissions,
- WeatherPreferences.LOCATION_PERMISSION_REQUEST_CODE
- )
- } else {
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ if (requestCode == WeatherPreferences.LOCATION_PERMISSION_REQUEST_CODE) {
+ if (grantResults.isNotEmpty() &&
+ grantResults[0] == PackageManager.PERMISSION_GRANTED
+ ) {
+ // We only get here if user tried to enable the preference,
+ // hence safe to turn it on after permission is granted
val lm = getSystemService(LOCATION_SERVICE) as LocationManager
- if (!lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER) &&
- Preferences.getEnableLocation(this)
- ) {
- showLocationEnableDialog()
+ if (!lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
+ workspace.showLocationEnableDialog()
Preferences.setEnableLocation(this)
} else {
startService(
@@ -611,85 +392,13 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
)
}
}
- } else {
- startService(
- Intent(this, WeatherUpdateService::class.java)
- .setAction(WeatherUpdateService.ACTION_FORCE_UPDATE)
- )
- }
- // [[END]]
-
- val widgetIds: IntArray = mAppWidgetHost.appWidgetIds
- Arrays.sort(widgetIds)
- for (id in widgetIds) {
- val appWidgetInfo: AppWidgetProviderInfo? = mAppWidgetManager.getAppWidgetInfo(id)
- if (appWidgetInfo != null) {
- val hostView: RoundedWidgetView = mAppWidgetHost.createView(
- applicationContext, id,
- appWidgetInfo
- ) as RoundedWidgetView
- hostView.setAppWidget(id, appWidgetInfo)
- getCompositeDisposable().add(DatabaseManager.getManager(this).getHeightOfWidget(id)
- .subscribeOn(Schedulers.from(AppExecutors.getInstance().diskIO()))
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe({ height: Int ->
- val widgetView = WidgetViewBuilder.create(this, hostView)
- if (height != 0) {
- val minHeight = hostView.appWidgetInfo.minResizeHeight
- val maxHeight = mDeviceProfile.availableHeightPx * 3 / 4
- val normalisedDifference = (maxHeight - minHeight) / 100
- val newHeight = minHeight + normalisedDifference * height
- widgetView.layoutParams.height = newHeight
- }
- addWidgetToContainer(widgetView)
- }) { obj: Throwable -> obj.printStackTrace() })
+ } else if (requestCode == STORAGE_PERMISSION_REQUEST_CODE) {
+ if (grantResults.isNotEmpty() &&
+ grantResults[0] == PackageManager.PERMISSION_GRANTED
+ ) {
+ BlurWallpaperProvider.getInstance(applicationContext).updateAsync()
}
- }
- }
-
- private fun addWidgetToContainer(widgetView: RoundedWidgetView) {
- widgetView.setPadding(0, 0, 0, 0)
- widgetContainer.addView(widgetView)
- }
-
- private fun updateWeatherPanel() {
- if (Preferences.getCachedWeatherInfo(this) == null) {
- mWeatherSetupTextView.visibility = View.VISIBLE
- mWeatherPanel.visibility = View.GONE
- mWeatherSetupTextView.setOnClickListener { v: View? ->
- startActivity(
- Intent(this, WeatherPreferences::class.java)
- )
- }
- return
- }
- mWeatherSetupTextView.visibility = View.GONE
- mWeatherPanel.visibility = View.VISIBLE
- ForecastBuilder.buildLargePanel(
- this, mWeatherPanel,
- Preferences.getCachedWeatherInfo(this)
- )
- }
-
- private fun showLocationEnableDialog() {
- val builder = AlertDialog.Builder(this)
- // Build and show the dialog
- builder.setTitle(R.string.weather_retrieve_location_dialog_title)
- builder.setMessage(R.string.weather_retrieve_location_dialog_message)
- builder.setCancelable(false)
- builder.setPositiveButton(
- R.string.weather_retrieve_location_dialog_enable_button
- ) { dialog1, whichButton ->
- val intent =
- Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
- intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
- startActivityForResult(
- intent, REQUEST_LOCATION_SOURCE_SETTING
- )
- }
- builder.setNegativeButton(R.string.cancel, null)
- enableLocationDialog = builder.create()
- enableLocationDialog?.show()
+ } else super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
@@ -711,123 +420,6 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
}
}
- private fun searchForQuery(
- charSequence: CharSequence
- ): ObservableSource? {
- val launcherItems = searchForLauncherItems(
- charSequence.toString()
- ).subscribeOn(Schedulers.io())
- val networkItems = searchForNetworkItems(
- charSequence
- ).subscribeOn(Schedulers.io())
- return launcherItems.mergeWith(networkItems)
- }
-
- private fun searchForLauncherItems(
- charSequence: CharSequence
- ): Observable {
- val query = charSequence.toString().toLowerCase()
- val suggestionsResult = SuggestionsResult(
- query
- )
- val launcherItems: MutableList = ArrayList()
- workspace.mWorkspaceScreens.forEach { gridLayout: GridLayout ->
- for (i in 0 until gridLayout.childCount) {
- val blissFrameLayout = gridLayout.getChildAt(i) as BlissFrameLayout
- val launcherItem = blissFrameLayout.launcherItem
- if (launcherItem.itemType == Constants.ITEM_TYPE_FOLDER) {
- val folderItem = launcherItem as FolderItem
- for (item in folderItem.items) {
- if (item.title.toString().toLowerCase().contains(query)) {
- launcherItems.add(item)
- }
- }
- } else if (launcherItem.title.toString().toLowerCase().contains(query)) {
- launcherItems.add(launcherItem)
- }
- }
- }
- val hotseat = getHotseat()
- for (i in 0 until hotseat.childCount) {
- val blissFrameLayout = hotseat.getChildAt(i) as BlissFrameLayout
- val launcherItem = blissFrameLayout.launcherItem
- if (launcherItem.itemType == Constants.ITEM_TYPE_FOLDER) {
- val folderItem = launcherItem as FolderItem
- for (item in folderItem.items) {
- if (item.title.toString().toLowerCase().contains(query)) {
- launcherItems.add(item)
- }
- }
- } else if (launcherItem.title.toString().toLowerCase().contains(query)) {
- launcherItems.add(launcherItem)
- }
- }
- launcherItems.sortWith(Comparator.comparing { launcherItem: LauncherItem ->
- launcherItem.title.toString().toLowerCase().indexOf(query)
- })
- if (launcherItems.size > 4) {
- suggestionsResult.launcherItems = launcherItems.subList(0, 4)
- } else {
- suggestionsResult.launcherItems = launcherItems
- }
- return Observable.just(suggestionsResult)
- .onErrorReturn { throwable: Throwable? ->
- suggestionsResult.launcherItems = ArrayList()
- suggestionsResult
- }
- }
-
- private fun searchForNetworkItems(charSequence: CharSequence): Observable {
- val query = charSequence.toString().lowercase(Locale.getDefault()).trim { it <= ' ' }
- val suggestionProvider = SearchSuggestionUtil().getSuggestionProvider(
- this
- )
- return suggestionProvider.query(query).toObservable()
- }
-
- fun hideWidgetResizeContainer() {
- val widgetResizeContainer: RelativeLayout = widgetPage.findViewById(
- R.id.widget_resizer_container
- )
- if (widgetResizeContainer.visibility == View.VISIBLE) {
- currentAnimator?.cancel()
- val set = AnimatorSet()
- set.play(
- ObjectAnimator.ofFloat(
- widgetResizeContainer, View.Y,
- mDeviceProfile.availableHeightPx
- .toFloat()
- )
- )
- set.duration = 200
- set.interpolator = LinearInterpolator()
- set.addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationStart(animation: Animator) {
- super.onAnimationStart(animation)
- (widgetPage.findViewById(
- R.id.widget_resizer_seekbar
- ) as SeekBar).setOnSeekBarChangeListener(null)
- }
-
- override fun onAnimationCancel(animation: Animator) {
- super.onAnimationCancel(animation)
- currentAnimator = null
- widgetResizeContainer.visibility = View.VISIBLE
- }
-
- override fun onAnimationEnd(animation: Animator) {
- super.onAnimationEnd(animation)
- currentAnimator = null
- widgetResizeContainer.visibility = View.GONE
- activeRoundedWidgetView?.removeBorder()
- }
- }
- )
- set.start()
- currentAnimator = set
- }
- }
-
fun hideKeyboard(view: View) {
val inputMethodManager = (getSystemService(
INPUT_METHOD_SERVICE
@@ -842,7 +434,7 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
inputMethodManager.showSoftInput(view, 0)
}
- private fun runSearch(query: String) {
+ fun runSearch(query: String) {
val intent = Intent(
Intent.ACTION_VIEW,
SearchSuggestionUtil().getUriForQuery(this, query)
@@ -851,92 +443,7 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
}
fun showWidgetResizeContainer(roundedWidgetView: RoundedWidgetView) {
- val widgetResizeContainer: RelativeLayout = widgetPage.findViewById(
- R.id.widget_resizer_container
- )
- if (widgetResizeContainer.visibility != View.VISIBLE) {
- activeRoundedWidgetView = roundedWidgetView
- val seekBar = widgetResizeContainer.findViewById(R.id.widget_resizer_seekbar)
- if (currentAnimator != null) {
- currentAnimator!!.cancel()
- }
- seekBar.setOnTouchListener { v: View?, event: MotionEvent? ->
- seekBar.parent.requestDisallowInterceptTouchEvent(true)
- false
- }
- val set = AnimatorSet()
- set.play(
- ObjectAnimator.ofFloat(
- widgetResizeContainer, View.Y,
- mDeviceProfile.availableHeightPx.toFloat(),
- mDeviceProfile.availableHeightPx - Utilities.pxFromDp(48, this)
- )
- )
- set.duration = 200
- set.interpolator = LinearInterpolator()
- set.addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationStart(animation: Animator) {
- super.onAnimationStart(animation)
- widgetResizeContainer.visibility = View.VISIBLE
- }
-
- override fun onAnimationCancel(animation: Animator) {
- super.onAnimationCancel(animation)
- currentAnimator = null
- widgetResizeContainer.visibility = View.GONE
- roundedWidgetView.removeBorder()
- }
-
- override fun onAnimationEnd(animation: Animator) {
- super.onAnimationEnd(animation)
- currentAnimator = null
- prepareWidgetResizeSeekBar(seekBar)
- roundedWidgetView.addBorder()
- }
- }
- )
- set.start()
- currentAnimator = set
- }
- }
-
- private fun prepareWidgetResizeSeekBar(seekBar: SeekBar) {
- val minHeight = activeRoundedWidgetView!!.appWidgetInfo.minResizeHeight
- val maxHeight = mDeviceProfile.availableHeightPx * 3 / 4
- val normalisedDifference = (maxHeight - minHeight) / 100
- val defaultHeight = activeRoundedWidgetView!!.height
- val currentProgress = (defaultHeight - minHeight) * 100 / (maxHeight - minHeight)
- seekBar.max = 100
- seekBar.progress = currentProgress
- seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
- override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
- val newHeight = minHeight + normalisedDifference * progress
- val layoutParams =
- activeRoundedWidgetView!!.layoutParams as LinearLayout.LayoutParams
- layoutParams.height = newHeight
- activeRoundedWidgetView!!.layoutParams = layoutParams
- val newOps = Bundle()
- newOps.putInt(
- AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
- mDeviceProfile.maxWidgetWidth
- )
- newOps.putInt(
- AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
- mDeviceProfile.maxWidgetWidth
- )
- newOps.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, newHeight)
- newOps.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, newHeight)
- activeRoundedWidgetView!!.updateAppWidgetOptions(newOps)
- activeRoundedWidgetView!!.requestLayout()
- }
-
- override fun onStartTrackingTouch(seekBar: SeekBar) {}
- override fun onStopTrackingTouch(seekBar: SeekBar) {
- DatabaseManager.getManager(this@TestActivity).saveWidget(
- activeRoundedWidgetView!!.appWidgetId, seekBar.progress
- )
- }
- })
+ workspace.showWidgetResizeContainer(roundedWidgetView)
}
override fun findViewById(id: Int): T {
@@ -962,6 +469,7 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
super.onPause()
dragController.cancelDrag()
dragController.resetLastGestureUpTime()
+ workspace.hideWidgetResizeContainer()
}
override fun onResume() {
@@ -978,37 +486,9 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
resumeCallbacks.clear()
}
- if (mWeatherPanel != null) {
- updateWeatherPanel()
- }
-
- if (widgetPage != null) {
- refreshSuggestedApps(widgetPage, forceRefreshSuggestedApps)
- }
-
- if (widgetContainer != null) {
- val widgetManager = WidgetManager.getInstance()
- var id = widgetManager.dequeRemoveId()
- while (id != null) {
- for (i in 0 until widgetContainer.childCount) {
- if (widgetContainer.getChildAt(i) is RoundedWidgetView) {
- val appWidgetHostView = widgetContainer.getChildAt(i) as RoundedWidgetView
- if (appWidgetHostView.appWidgetId == id) {
- widgetContainer.removeViewAt(i)
- DatabaseManager.getManager(this).removeWidget(id)
- break
- }
- }
- }
- id = widgetManager.dequeRemoveId()
- }
- var widgetView = widgetManager.dequeAddWidgetView()
- while (widgetView != null) {
- widgetView = WidgetViewBuilder.create(this, widgetView)
- addWidgetToContainer(widgetView)
- widgetView = widgetManager.dequeAddWidgetView()
- }
- }
+ workspace.updateWeatherPanel()
+ workspace.refreshSuggestedApps(false) // TODO: Update with app remove event
+ workspace.updateWidgets()
}
override fun onStop() {
@@ -1021,6 +501,7 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
override fun onDestroy() {
super.onDestroy()
+ workspace.removeFolderListeners()
if (mCancelTouchController != null) {
mCancelTouchController!!.run()
mCancelTouchController = null
@@ -1070,7 +551,7 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
fun isWorkspaceLocked() = false
- private fun getCompositeDisposable(): CompositeDisposable {
+ fun getCompositeDisposable(): CompositeDisposable {
if (mCompositeDisposable == null || mCompositeDisposable!!.isDisposed) {
mCompositeDisposable = CompositeDisposable()
}
@@ -1082,12 +563,12 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
BlissLauncher.getApplication(this)
.appProvider
.appsRepository
- .appsRelay
+ .allItemsRelay
.distinctUntilChanged()
.observeOn(AndroidSchedulers.mainThread())
- .subscribeWith(object : DisposableObserver>() {
- override fun onNext(launcherItems: List) {
- mainHandler.post { showApps(launcherItems) }
+ .subscribeWith(object : DisposableObserver() {
+ override fun onNext(items: AppsRepository.AllItems) {
+ mainHandler.post { showApps(items) }
}
override fun onError(e: Throwable) {
@@ -1099,14 +580,16 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
)
}
- private fun showApps(launcherItems: List) {
- Log.d(TAG, "showApps() called with: launcherItems = $launcherItems")
+ private fun showApps(allItems: AppsRepository.AllItems) {
hotseat.resetLayout(false)
- val populatedItems = populateItemPositions(launcherItems)
+ val populatedItems = populateItemPositions(allItems.items)
val orderedScreenIds = IntegerArray()
orderedScreenIds.addAll(collectWorkspaceScreens(populatedItems))
+ workspace.removeAllWorkspaceScreens()
workspace.bindScreens(orderedScreenIds)
+ workspace.post(workspace::moveToDefaultScreen)
workspace.bindItems(populatedItems, false)
+ workspace.bindItemsAdded(allItems.newAddedItems)
}
private fun populateItemPositions(launcherItems: List): List {
@@ -1165,11 +648,11 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
/**
* Call this after onCreate to set or clear overlay.
*/
- private fun setLauncherOverlay(overlay: LauncherOverlay) {
+ /*private fun setLauncherOverlay(overlay: LauncherOverlay) {
overlay.setOverlayCallbacks(LauncherOverlayCallbacksImpl())
workspace.setLauncherOverlay(overlay)
widgetRootView.setLauncherOverlay(overlay)
- }
+ }*/
fun isInState(state: LauncherState): Boolean {
return mStateManager.state === state
@@ -1179,45 +662,6 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
mOnResumeCallbacks.add(callback)
}
- fun refreshSuggestedApps(viewGroup: ViewGroup, forceRefresh: Boolean) {
- val openUsageAccessSettingsTv =
- viewGroup.findViewById(R.id.openUsageAccessSettings)
- val suggestedAppsGridLayout = viewGroup.findViewById(R.id.suggestedAppGrid)
- val appUsageStats = AppUsageStats(this)
- val usageStats = appUsageStats.usageStats
- if (usageStats.size > 0) {
- openUsageAccessSettingsTv.visibility = View.GONE
- suggestedAppsGridLayout.visibility = View.VISIBLE
-
- // Check if usage stats have been changed or not to avoid unnecessary flickering
- if (forceRefresh || mUsageStats == null || mUsageStats!!.size != usageStats.size || !ListUtil.areEqualLists(
- mUsageStats,
- usageStats
- )
- ) {
- mUsageStats = usageStats
- if (suggestedAppsGridLayout.childCount > 0) {
- suggestedAppsGridLayout.removeAllViews()
- }
- var i = 0
- while (suggestedAppsGridLayout.childCount < 4 && i < mUsageStats!!.size) {
- val appItem = AppUtils.createAppItem(
- this,
- mUsageStats!![i].packageName, UserHandle()
- )
- if (appItem != null) {
- val view: BlissFrameLayout = prepareSuggestedApp(appItem)
- addAppToGrid(suggestedAppsGridLayout, view)
- }
- i++
- }
- }
- } else {
- openUsageAccessSettingsTv.visibility = View.VISIBLE
- suggestedAppsGridLayout.visibility = View.GONE
- }
- }
-
fun prepareSuggestedApp(launcherItem: LauncherItem): BlissFrameLayout {
val v = layoutInflater.inflate(
R.layout.app_view,
@@ -1239,8 +683,17 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
val rowSpec = GridLayout.spec(GridLayout.UNDEFINED)
val colSpec = GridLayout.spec(GridLayout.UNDEFINED)
val iconLayoutParams = GridLayout.LayoutParams(rowSpec, colSpec)
- iconLayoutParams.height = mDeviceProfile.cellHeightPx
- iconLayoutParams.width = mDeviceProfile.cellWidthPx
+ val emptySpace = mDeviceProfile.availableWidthPx - 2 * Utilities.pxFromDp(16, this) - 4 *
+ mDeviceProfile.cellWidthPx
+ val padding = emptySpace / 10
+ val topBottomPadding = Utilities.pxFromDp(8, this).toInt()
+ iconLayoutParams.height = (mDeviceProfile.cellHeightPx + topBottomPadding)
+ iconLayoutParams.width = (mDeviceProfile.cellWidthPx + padding * 2).toInt()
+
+ view.setPadding(
+ padding.toInt(),
+ (topBottomPadding / 2), padding.toInt(), topBottomPadding / 2
+ )
view.findViewById(R.id.app_label).visibility = View.VISIBLE
view.layoutParams = iconLayoutParams
view.setWithText(true)
@@ -1257,7 +710,8 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
// Check this condition before handling isActionMain, as this will get reset.
val shouldMoveToDefaultScreen = (alreadyOnHome && isInState(NORMAL) &&
- AbstractFloatingView.getTopOpenView(this) == null)
+ AbstractFloatingView.getTopOpenView(this) == null) &&
+ ((workspace.activeRoundedWidgetView?.isWidgetActivated ?: false).not())
val isActionMain = Intent.ACTION_MAIN == intent!!.action
val internalStateHandled = InternalStateHandler
.handleNewIntent(this, intent, isStarted)
@@ -1266,11 +720,6 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
if (!internalStateHandled) {
// In all these cases, only animate if we're already on home
AbstractFloatingView.closeAllOpenViews(this, isStarted)
-
- if (folderContainer.visibility == View.VISIBLE) {
- closeFolder()
- return
- }
if (!isInState(NORMAL)) {
// Only change state, if not already the same. This prevents cancelling any
// animations running as part of resume
@@ -1280,6 +729,8 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
// Reset the apps view
if (!alreadyOnHome) {
// TODO: maybe stop icon giggling or search view here.
+ } else {
+ workspace.hideWidgetResizeContainer()
}
if (shouldMoveToDefaultScreen && !workspace.isHandlingTouch) {
workspace.post(workspace::moveToDefaultScreen)
@@ -1310,14 +761,13 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
return
}
+ workspace.clearWidgetState()
+
// Note: There should be at most one log per method call. This is enforced implicitly
// by using if-else statements.
val topView = AbstractFloatingView.getTopOpenView(this)
if (topView != null && topView.onBackPressed()) {
- // Handled by the floating view.
- } else if (folderContainer.visibility == View.VISIBLE) {
- closeFolder()
} else {
mStateManager.state.onBackPressed(this)
}
@@ -1334,6 +784,8 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
const val DEBUG_STRICT_MODE = false
+ private val STORAGE_PERMISSION_REQUEST_CODE: Int = 586
+
// TODO: Remove after test is finished
fun getLauncher(context: Context): TestActivity {
return if (context is TestActivity) {
@@ -1380,7 +832,7 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
}
// TODO: Maybe we need to simplify the logic here.
- inner class LauncherOverlayCallbacksImpl : LauncherOverlayCallbacks {
+ /*inner class LauncherOverlayCallbacksImpl : LauncherOverlayCallbacks {
private var currentProgress = 0f
private var isScrolling = false
@@ -1393,8 +845,11 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
if (scrollFromWorkspace) {
workspace.onOverlayScrollChanged(progress)
widgetPage.translationX = widgetPage.measuredWidth * (progress - 1)
+ widgetPage.changeBlurBounds(progress, true)
} else {
workspace.onOverlayScrollChanged(progress)
+ Log.i(TAG, "onScrollChanged: $progress")
+ widgetPage.changeBlurBounds(progress, false)
}
}
}
@@ -1411,6 +866,7 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
workspace.onOverlayScrollChanged(it.animatedValue as Float)
widgetPage.translationX =
widgetPage.measuredWidth * (it.animatedValue as Float - 1)
+ widgetPage.changeBlurBounds(it.animatedValue as Float, true)
}
workspaceAnim.duration = 300
workspaceAnim.interpolator = AccelerateDecelerateInterpolator()
@@ -1422,6 +878,7 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
override fun onAnimationCancel(animation: Animator) {
workspace.onOverlayScrollChanged(0f)
widgetPage.translationX = (-widgetPage.measuredWidth).toFloat()
+ widgetPage.changeBlurBounds(0f, true)
animator = null
}
})
@@ -1432,6 +889,7 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
workspace.onOverlayScrollChanged(it.animatedValue as Float)
widgetPage.translationX =
widgetPage.measuredWidth * (it.animatedValue as Float - 1)
+ widgetPage.changeBlurBounds(it.animatedValue as Float, false)
}
workspaceAnim.duration = 300
workspaceAnim.interpolator = AccelerateDecelerateInterpolator()
@@ -1443,6 +901,7 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
override fun onAnimationCancel(animation: Animator) {
workspace.onOverlayScrollChanged(1f)
widgetPage.translationX = 0f
+ widgetPage.changeBlurBounds(1f, false)
animator = null
}
})
@@ -1450,14 +909,7 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
}
animator?.start()
}
- }
-
- override fun onClick(suggestion: String) {
- mSearchInput.setText(suggestion)
- runSearch(suggestion)
- mSearchInput.clearFocus()
- mSearchInput.setText("")
- }
+ }*/
fun updateNotificationDots(updatedDots: Predicate) {
workspace.updateNotificationBadge(updatedDots)
@@ -1564,7 +1016,7 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
}
}
- fun openFolder(folderView: View) {
+ /*fun openFolder(folderView: View) {
if (currentAnimator != null) {
currentAnimator!!.cancel()
}
@@ -1613,12 +1065,13 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
// Construct and run the parallel animation of the four translation and
// scale properties (X, Y, SCALE_X, and SCALE_Y).
val set = AnimatorSet()
- /*ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 18);
+ *//*ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 18);
valueAnimator.addUpdateListener(animation ->
- BlurWallpaperProvider.getInstance(this).blur((Integer) animation.getAnimatedValue()));*/
- /*ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 18);
+ BlurWallpaperProvider.getInstance(this).blur((Integer) animation.getAnimatedValue()));*//*
+ *//*ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 18);
valueAnimator.addUpdateListener(animation ->
- BlurWallpaperProvider.getInstance(this).blur((Integer) animation.getAnimatedValue()));*/set.play(
+ BlurWallpaperProvider.getInstance(this).blur((Integer) animation.getAnimatedValue()));*//*
+ set.play(
ObjectAnimator.ofFloat(
folderContainer, View.X,
startBounds.left.toFloat(), finalBounds.left
@@ -1646,7 +1099,7 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
)
.with(ObjectAnimator.ofFloat(getLauncherPagedView(), View.ALPHA, 0f))
// .with(ObjectAnimator.ofFloat(mIndicator, View.ALPHA, 0f))
- .with(ObjectAnimator.ofFloat(hotseat, View.ALPHA, 0f))
+ .with()
set.duration = 300
set.interpolator = LinearInterpolator()
set.addListener(object : AnimatorListenerAdapter() {
@@ -1702,19 +1155,22 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
}
fun closeFolder() {
- mFolderTitleInput?.clearFocus()
+ if (isEditingName()) {
+ mFolderTitleInput.dispatchBackKey()
+ }
+
currentAnimator?.cancel()
// Animate the four positioning/sizing properties in parallel,
// back to their original values.
val set = AnimatorSet()
- /*ValueAnimator valueAnimator = ValueAnimator.ofInt(18, 0);
+ *//*ValueAnimator valueAnimator = ValueAnimator.ofInt(18, 0);
+ valueAnimator.addUpdateListener(animati on ->
+ BlurWallpaperProvider.getInstance(this).blurWithLauncherView(mergedView, (Integer) animation.getAnimatedValue()));*//*
+ *//*ValueAnimator valueAnimator = ValueAnimator.ofInt(18, 0);
valueAnimator.addUpdateListener(animation ->
- BlurWallpaperProvider.getInstance(this).blurWithLauncherView(mergedView, (Integer) animation.getAnimatedValue()));*/
- /*ValueAnimator valueAnimator = ValueAnimator.ofInt(18, 0);
- valueAnimator.addUpdateListener(animation ->
- BlurWallpaperProvider.getInstance(this).blurWithLauncherView(mergedView, (Integer) animation.getAnimatedValue()));*/set.play(
+ BlurWallpaperProvider.getInstance(this).blurWithLauncherView(mergedView, (Integer) animation.getAnimatedValue()));*//*set.play(
ObjectAnimator
.ofFloat(folderContainer, View.X, activeFolderStartBounds.left.toFloat())
)
@@ -1774,11 +1230,22 @@ class TestActivity : BaseDraggingActivity(), AutoCompleteAdapter.OnSuggestionCli
})
set.start()
currentAnimator = set
- }
+ }*/
override fun bindAppsAdded(items: MutableList) {
if (items.isEmpty()) return
+ workspace.bindItemsAdded(items)
+ }
- workspace?.bindItemsAdded(items)
+ /**
+ * A package was uninstalled/updated. We take both the super set of packageNames
+ * in addition to specific applications to remove, the reason being that
+ * this can be called when a package is updated as well. In that scenario,
+ * we only remove specific components from the workspace and hotseat, where as
+ * package-removal should clear all items by package name.
+ */
+ override fun bindWorkspaceComponentsRemoved(matcher: LauncherItemMatcher) {
+ workspace.removeItemsByMatcher(matcher)
+ dragController.onAppsRemoved(matcher)
}
}
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/test/VariantDeviceProfile.kt b/app/src/main/java/foundation/e/blisslauncher/features/test/VariantDeviceProfile.kt
index 9939c758d803466d0858aa56f4814e079ae271f9..f613b15b1483687c287b9e4d30911a2f96fccb16 100644
--- a/app/src/main/java/foundation/e/blisslauncher/features/test/VariantDeviceProfile.kt
+++ b/app/src/main/java/foundation/e/blisslauncher/features/test/VariantDeviceProfile.kt
@@ -29,11 +29,12 @@ import android.view.WindowInsets
import android.view.WindowManager
import foundation.e.blisslauncher.R
import foundation.e.blisslauncher.core.Utilities
-import foundation.e.blisslauncher.core.utils.Constants
+import foundation.e.blisslauncher.core.utils.ResourceUtils
import foundation.e.blisslauncher.features.notification.DotRenderer
import foundation.e.blisslauncher.features.test.uninstall.UninstallButtonRenderer
import kotlin.math.max
import kotlin.math.min
+import kotlin.math.roundToInt
class VariantDeviceProfile(
val context: Context,
@@ -46,7 +47,6 @@ class VariantDeviceProfile(
@JvmField
var isMultiWindowMode: Boolean
) {
-
val mDotRenderer: DotRenderer
val uninstallRenderer: UninstallButtonRenderer
@@ -64,7 +64,7 @@ class VariantDeviceProfile(
// Workspace
val desiredWorkspaceLeftRightMarginPx: Int
val cellLayoutPaddingLeftRightPx: Int
- val cellLayoutBottomPaddingPx: Int
+ var cellLayoutBottomPaddingPx: Int
val edgeMarginPx: Int
val defaultWidgetPadding: Rect
val defaultPageSpacingPx: Int
@@ -78,7 +78,7 @@ class VariantDeviceProfile(
var cellWidthPx = 0
var cellHeightPx = 0
var workspaceCellPaddingXPx: Int
- var workspacePageIndicatorHeight: Int
+ val workspacePageIndicatorHeight: Int
// Folder
var folderIconSizePx = 0
@@ -211,8 +211,11 @@ class VariantDeviceProfile(
res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding)
hotseatBarSidePaddingPx =
res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_side_padding)
- hotseatBarSizePx =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_size) + hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx
+ hotseatBarSizePx = ResourceUtils.pxFromDp(
+ inv.iconSize,
+ dm
+ ) + (res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_extra_vertical_size) +
+ hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx)
workspacePageIndicatorHeight =
res.getDimensionPixelSize(R.dimen.dotSize) * 2 + res.getDimensionPixelSize(R.dimen.dotPadding) * 2
@@ -409,7 +412,7 @@ class VariantDeviceProfile(
}
/**
- * Updates [.workspacePadding] as a result of any internal value change to reflect the
+ * Updates [workspacePadding] as a result of any internal value change to reflect the
* new workspace padding
*/
private fun updateWorkspacePadding() {
@@ -448,11 +451,12 @@ class VariantDeviceProfile(
val workspaceCellWidth = widthPx.toFloat() / inv.numColumns
val hotseatCellWidth = widthPx.toFloat() / inv.numHotseatIcons
val hotseatAdjustment =
- Math.round((workspaceCellWidth - hotseatCellWidth) / 2)
+ ((workspaceCellWidth - hotseatCellWidth) / 2).roundToInt()
- mHotseatPadding[hotseatAdjustment + workspacePadding.left + cellLayoutPaddingLeftRightPx, hotseatBarTopPaddingPx, hotseatAdjustment + workspacePadding.right + cellLayoutPaddingLeftRightPx] =
+ mHotseatPadding[hotseatAdjustment + workspacePadding.left + cellLayoutPaddingLeftRightPx,
+ hotseatBarTopPaddingPx,
+ hotseatAdjustment + workspacePadding.right + cellLayoutPaddingLeftRightPx] =
hotseatBarBottomPaddingPx + insets.bottom + cellLayoutBottomPaddingPx
- Log.d(TAG, "Hotseat padding: $mHotseatPadding, insets: $insets")
return mHotseatPadding
} // Folders should only appear below the drop target bar and above the hotseat// Folders should only appear right of the drop target bar and left of the hotseat
@@ -467,10 +471,10 @@ class VariantDeviceProfile(
insets.top + availableHeightPx - hotseatBarSizePx - -edgeMarginPx
)
- fun getCellHeight(containerType: Long): Int {
+ fun getCellHeight(containerType: Int): Int {
return when (containerType) {
- Constants.CONTAINER_DESKTOP -> cellHeightPx
- Constants.CONTAINER_HOTSEAT -> hotseatCellHeightPx
+ CellLayout.WORKSPACE -> cellHeightPx
+ CellLayout.HOTSEAT -> hotseatCellHeightPx
else -> 0
}
}
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/test/WorkspaceStateTransitionAnimation.java b/app/src/main/java/foundation/e/blisslauncher/features/test/WorkspaceStateTransitionAnimation.java
index 9e7729346c92945b55d83ffa5e1654f96f059298..c10c768378d29d73047c4ea97dd4858f651c7db8 100644
--- a/app/src/main/java/foundation/e/blisslauncher/features/test/WorkspaceStateTransitionAnimation.java
+++ b/app/src/main/java/foundation/e/blisslauncher/features/test/WorkspaceStateTransitionAnimation.java
@@ -76,7 +76,7 @@ public class WorkspaceStateTransitionAnimation {
LauncherState.PageAlphaProvider pageAlphaProvider = state.getWorkspacePageAlphaProvider(mLauncher);
final int childCount = mWorkspace.getChildCount();
for (int i = 0; i < childCount; i++) {
- applyChildState(state, (CellLayout) mWorkspace.getChildAt(i), i, pageAlphaProvider,
+ applyChildState(state, mWorkspace.getChildAt(i), i, pageAlphaProvider,
propertySetter, builder, config);
}
@@ -144,7 +144,7 @@ public class WorkspaceStateTransitionAnimation {
NO_ANIM_PROPERTY_SETTER, new AnimatorSetBuilder(), new LauncherStateManager.AnimationConfig());
}
- private void applyChildState(LauncherState state, CellLayout cl, int childIndex,
+ private void applyChildState(LauncherState state, View cl, int childIndex,
LauncherState.PageAlphaProvider pageAlphaProvider, PropertySetter propertySetter,
AnimatorSetBuilder builder, LauncherStateManager.AnimationConfig config) {
float pageAlpha = pageAlphaProvider.getPageAlpha(childIndex);
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/test/dragndrop/DragController.java b/app/src/main/java/foundation/e/blisslauncher/features/test/dragndrop/DragController.java
index 0535824a672f2f418c9e64e2ddb2b9eaead70a07..298f7dc073e5ab2f6a40603d781022dc4b77473b 100644
--- a/app/src/main/java/foundation/e/blisslauncher/features/test/dragndrop/DragController.java
+++ b/app/src/main/java/foundation/e/blisslauncher/features/test/dragndrop/DragController.java
@@ -16,6 +16,9 @@
package foundation.e.blisslauncher.features.test.dragndrop;
+import static foundation.e.blisslauncher.features.test.LauncherState.NORMAL;
+import static foundation.e.blisslauncher.features.test.anim.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
+
import android.content.ComponentName;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -28,9 +31,6 @@ import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
-
-import java.util.ArrayList;
-
import foundation.e.blisslauncher.R;
import foundation.e.blisslauncher.core.database.model.ApplicationItem;
import foundation.e.blisslauncher.core.database.model.LauncherItem;
@@ -39,6 +39,7 @@ import foundation.e.blisslauncher.features.test.LauncherItemMatcher;
import foundation.e.blisslauncher.features.test.TestActivity;
import foundation.e.blisslauncher.features.test.TouchController;
import foundation.e.blisslauncher.features.test.UiThreadHelper;
+import java.util.ArrayList;
/**
* Class for initiating a drag within a view or across multiple views.
@@ -251,8 +252,7 @@ public class DragController implements DragDriver.EventListener, TouchController
if (!accepted) {
// If it was not accepted, cleanup the state. If it was accepted, it is the
// responsibility of the drop target to cleanup the state.
- // mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
- //TODO: Go to normal state here.
+ mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
mDragObject.deferDragViewCleanupPostAnimation = false;
}
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/widgets/WidgetPageLayer.kt b/app/src/main/java/foundation/e/blisslauncher/features/widgets/WidgetPageLayer.kt
new file mode 100644
index 0000000000000000000000000000000000000000..a1bd897c57b880e57000e18339f91cf65a73e720
--- /dev/null
+++ b/app/src/main/java/foundation/e/blisslauncher/features/widgets/WidgetPageLayer.kt
@@ -0,0 +1,107 @@
+package foundation.e.blisslauncher.features.widgets
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.drawable.Drawable
+import android.util.AttributeSet
+import foundation.e.blisslauncher.core.blur.BlurWallpaperProvider
+import foundation.e.blisslauncher.core.blur.ShaderBlurDrawable
+import foundation.e.blisslauncher.core.customviews.Insettable
+import foundation.e.blisslauncher.core.customviews.InsettableFrameLayout
+import foundation.e.blisslauncher.core.runOnMainThread
+
+class WidgetPageLayer @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null
+) : InsettableFrameLayout(context, attrs), Insettable,
+ BlurWallpaperProvider.Listener {
+ private val blurWallpaperProvider: BlurWallpaperProvider
+ private var fullBlurDrawable: ShaderBlurDrawable? = null
+ private val blurAlpha = 255
+ private val blurDrawableCallback: Drawable.Callback = object : Drawable.Callback {
+ override fun invalidateDrawable(who: Drawable) {
+ runOnMainThread {
+ invalidate()
+ }
+ }
+
+ override fun scheduleDrawable(
+ who: Drawable,
+ what: Runnable,
+ `when`: Long
+ ) {
+ }
+
+ override fun unscheduleDrawable(
+ who: Drawable,
+ what: Runnable
+ ) {
+ }
+ }
+
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+ BlurWallpaperProvider.getInstance(context).addListener(this)
+ fullBlurDrawable?.startListening()
+ }
+
+ override fun onDetachedFromWindow() {
+ super.onDetachedFromWindow()
+ BlurWallpaperProvider.getInstance(context).removeListener(this)
+ fullBlurDrawable?.stopListening()
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ fullBlurDrawable?.alpha = blurAlpha
+ // fullBlurDrawable?.draw(canvas)
+ super.onDraw(canvas)
+ }
+
+ override fun onLayout(
+ changed: Boolean,
+ left: Int,
+ top: Int,
+ right: Int,
+ bottom: Int
+ ) {
+ super.onLayout(changed, left, top, right, bottom)
+ if (changed) {
+ fullBlurDrawable?.setBounds(left, top, right, bottom)
+ }
+ }
+
+ /**
+ * We only need to change right bound for widget page blur layer.
+ */
+ fun changeBlurBounds(factor: Float, isLeftToRight: Boolean) {
+ fullBlurDrawable?.setBounds(left, top, (right * factor).toInt(), bottom)
+ if (isLeftToRight) {
+ fullBlurDrawable?.canvasOffset =
+ (right - left) * (1 - factor)
+ }
+ fullBlurDrawable?.invalidateSelf()
+ }
+
+ private fun createBlurDrawable() {
+ if (isAttachedToWindow) {
+ fullBlurDrawable?.stopListening()
+ }
+ fullBlurDrawable = blurWallpaperProvider.createDrawable().apply {
+ callback = blurDrawableCallback
+ setBounds(left, top, right, bottom)
+ }
+ if (isAttachedToWindow) fullBlurDrawable?.startListening()
+ }
+
+ override fun onEnabledChanged() {
+ createBlurDrawable()
+ }
+
+ override fun onWallpaperChanged() {}
+
+ init {
+ setWillNotDraw(false)
+ blurWallpaperProvider = BlurWallpaperProvider.getInstance(context)
+ createBlurDrawable()
+ }
+}
diff --git a/app/src/main/java/foundation/e/blisslauncher/features/widgets/WidgetsRootView.java b/app/src/main/java/foundation/e/blisslauncher/features/widgets/WidgetsRootView.java
index e9e7b74d06d0d43d7757126f3ebfb509cadbbf01..8631ed6a1577e53143fb4395d8773a627def10da 100644
--- a/app/src/main/java/foundation/e/blisslauncher/features/widgets/WidgetsRootView.java
+++ b/app/src/main/java/foundation/e/blisslauncher/features/widgets/WidgetsRootView.java
@@ -19,6 +19,10 @@ public class WidgetsRootView extends HorizontalScrollView {
private boolean shouldScrollWorkspace = true;
+ // The following constants need to be scaled based on density. The scaled versions will be
+ // assigned to the corresponding member variables below.
+ private static final int FLING_THRESHOLD_VELOCITY = 500;
+
public WidgetsRootView(Context context) {
super(context);
init();
@@ -55,6 +59,16 @@ public class WidgetsRootView extends HorizontalScrollView {
}
}
+ @Override
+ public void fling(int velocityX) {
+ super.fling(velocityX);
+ float density = getResources().getDisplayMetrics().density;
+ if (Math.abs(velocityX) > FLING_THRESHOLD_VELOCITY * density) {
+ shouldScrollWorkspace = !shouldScrollWorkspace;
+ overlay.onScrollInteractionEnd();
+ }
+ }
+
@Override
protected boolean overScrollBy(
int deltaX,
diff --git a/app/src/main/res/anim/folder_interpolator.xml b/app/src/main/res/anim/folder_interpolator.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b95d4548ffb74b4689d7f25a03dffef5683e5468
--- /dev/null
+++ b/app/src/main/res/anim/folder_interpolator.xml
@@ -0,0 +1,24 @@
+
+
+
+
diff --git a/app/src/main/res/layout/activity_test.xml b/app/src/main/res/layout/activity_test.xml
index 3f92b6f2934619c9718e3f2a7f9e6893ae3fc063..15769e455e4319685a79a7b98e857f397a02c584 100644
--- a/app/src/main/res/layout/activity_test.xml
+++ b/app/src/main/res/layout/activity_test.xml
@@ -13,8 +13,14 @@
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
+ android:background="@android:color/transparent"
android:importantForAccessibility="no">
+
+
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/folder_icon.xml b/app/src/main/res/layout/folder_icon.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d277f88ae1c4eec8ae3d8b56a3ed68824f37cc8e
--- /dev/null
+++ b/app/src/main/res/layout/folder_icon.xml
@@ -0,0 +1,17 @@
+
+
+
+
diff --git a/app/src/main/res/layout/layout_folder.xml b/app/src/main/res/layout/layout_folder.xml
index c3772e34d935a90198beaf8b652eaec36e5b1b45..03d72950a7e0d90f7ddaa82f4d1f5f1d80e3aae9 100644
--- a/app/src/main/res/layout/layout_folder.xml
+++ b/app/src/main/res/layout/layout_folder.xml
@@ -1,25 +1,26 @@
-
-
@@ -31,7 +32,7 @@
android:background="@drawable/folder_window"
android:orientation="vertical">
-
@@ -44,4 +45,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_search_suggestion.xml b/app/src/main/res/layout/layout_search_suggestion.xml
index 2ab03468f4c5e6d1be43ef3460b5fe009bc75912..0366d5500de59d69f186065ffd5322358a2d8702 100644
--- a/app/src/main/res/layout/layout_search_suggestion.xml
+++ b/app/src/main/res/layout/layout_search_suggestion.xml
@@ -1,7 +1,7 @@
diff --git a/app/src/main/res/layout/layout_used_apps.xml b/app/src/main/res/layout/layout_used_apps.xml
index 5b26e9678dc074c98d41ff41d296aeec96eddea2..1435459de0054a03a428b3e7b96a477ffcc3b24e 100755
--- a/app/src/main/res/layout/layout_used_apps.xml
+++ b/app/src/main/res/layout/layout_used_apps.xml
@@ -34,7 +34,7 @@
-
+ android:animateLayoutChanges="true"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp">
-
+ android:id="@+id/widgets_scroll_container"
+ android:overScrollMode="never"
+ android:scrollbars="none">
-
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/dp_16">
+
+
+
+
-
-
+ android:orientation="vertical" />
-
-
-
-
-
-
-
-
-
-
-
+
+
-
+
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index e97578812da245d8e088a1c510dc62b6010f25f2..29dc2f91b10596d75fa2d54726992da951e184f3 100755
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -1,8 +1,8 @@
- #3F51B5
- #303F9F
- #FF4081
+ #FFFFFF
+ #FFFFFF
+ #007FFF
#ffffff
#4D000000
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index e6704acb4fcb30df14b489ee57d7ee452c2c6149..58954d87ad71d9181402a7132521bc780c0d1aa4 100755
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -31,6 +31,7 @@
8dp
2dp
80dp
+ 34dp
0dp
9dp
diff --git a/app/src/main/res/values/integers.xml b/app/src/main/res/values/integers.xml
index 1b9261212756242e783825180c0489deb325b2b2..be3bb156eb183c2c7d31d5065de03c8f3935b177 100644
--- a/app/src/main/res/values/integers.xml
+++ b/app/src/main/res/values/integers.xml
@@ -3,4 +3,6 @@
800
500
100
+ 200
+ 30
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index f718025891c1211be75e50bbecae0a6a179a9f03..4cd4ba3ed9621be73585ea11fe5f5583aadb7ea3 100755
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -8,6 +8,7 @@
-
diff --git a/app/src/main/res/xml/device_profiles.xml b/app/src/main/res/xml/device_profiles.xml
index 78d03ac9eb4d0b7df2b1a60946307b89188a700c..3e8521e38e22f9eccbb0ada65f45dee650dfd51b 100644
--- a/app/src/main/res/xml/device_profiles.xml
+++ b/app/src/main/res/xml/device_profiles.xml
@@ -1,7 +1,7 @@
-
@@ -24,7 +24,7 @@
launcher:numFolderRows="3"
launcher:numFolderColumns="3"
launcher:numHotseatIcons="4"
- launcher:iconSize="56"
+ launcher:iconSize="62"
launcher:iconTextSize="13.0"
launcher:defaultLayoutId="@xml/dw_hotseat_4"
/>
@@ -38,7 +38,7 @@
launcher:numFolderRows="3"
launcher:numFolderColumns="3"
launcher:numHotseatIcons="4"
- launcher:iconSize="54"
+ launcher:iconSize="60"
launcher:iconTextSize="13.0"
launcher:defaultLayoutId="@xml/dw_hotseat_5"
/>
@@ -52,7 +52,7 @@
launcher:numFolderRows="3"
launcher:numFolderColumns="3"
launcher:numHotseatIcons="4"
- launcher:iconSize="56"
+ launcher:iconSize="60"
launcher:iconTextSize="13.0"
launcher:defaultLayoutId="@xml/dw_hotseat_5"
/>
@@ -66,7 +66,7 @@
launcher:numFolderRows="3"
launcher:numFolderColumns="3"
launcher:numHotseatIcons="4"
- launcher:iconSize="56"
+ launcher:iconSize="60"
launcher:iconTextSize="13.0"
launcher:defaultLayoutId="@xml/dw_hotseat_5"
/>
@@ -80,7 +80,7 @@
launcher:numFolderRows="3"
launcher:numFolderColumns="3"
launcher:numHotseatIcons="4"
- launcher:iconSize="54"
+ launcher:iconSize="60"
launcher:iconTextSize="13.0"
launcher:defaultLayoutId="@xml/dw_hotseat_5"
/>
@@ -94,7 +94,7 @@
launcher:numFolderRows="3"
launcher:numFolderColumns="3"
launcher:numHotseatIcons="4"
- launcher:iconSize="52"
+ launcher:iconSize="60"
launcher:iconTextSize="13.0"
launcher:defaultLayoutId="@xml/dw_hotseat_6"
/>
@@ -108,11 +108,12 @@
launcher:numFolderRows="3"
launcher:numFolderColumns="3"
launcher:numHotseatIcons="6"
- launcher:iconSize="64"
+ launcher:iconSize="76"
launcher:iconTextSize="13.0"
launcher:defaultLayoutId="@xml/dw_hotseat_6"
- />
-
+
+
-->
+ />
diff --git a/app/src/quickstep/recents_ui_overrides/src/foundation/e/blisslauncher/uioverrides/OverlayCallbackImpl.java b/app/src/quickstep/recents_ui_overrides/src/foundation/e/blisslauncher/uioverrides/OverlayCallbackImpl.java
index 4f2d6c10f2139c703f51cca511449a0bcca68504..844831f22cdfbc80f671e88bb09607a329e7ff7e 100644
--- a/app/src/quickstep/recents_ui_overrides/src/foundation/e/blisslauncher/uioverrides/OverlayCallbackImpl.java
+++ b/app/src/quickstep/recents_ui_overrides/src/foundation/e/blisslauncher/uioverrides/OverlayCallbackImpl.java
@@ -15,6 +15,9 @@ public class OverlayCallbackImpl implements TestActivity.LauncherOverlay {
private TestActivity.LauncherOverlayCallbacks mLauncherOverlayCallbacks;
+ // The page is moved more than halfway, automatically move to the next page on touch up.
+ private static final float SIGNIFICANT_MOVE_THRESHOLD = 0.4f;
+
public OverlayCallbackImpl(TestActivity launcher) {
this.mLauncher = launcher;
}
@@ -27,10 +30,10 @@ public class OverlayCallbackImpl implements TestActivity.LauncherOverlay {
@Override
public void onScrollInteractionEnd() {
if(scrollFromWorkspace) {
- if(mProgress >= 0.5f) mLauncherOverlayCallbacks.onScrollEnd(1f, true);
+ if(mProgress >= SIGNIFICANT_MOVE_THRESHOLD) mLauncherOverlayCallbacks.onScrollEnd(1f, true);
else mLauncherOverlayCallbacks.onScrollEnd(0f, true);
} else {
- if(mProgress < 0.5f) mLauncherOverlayCallbacks.onScrollEnd(0f, false);
+ if(mProgress < SIGNIFICANT_MOVE_THRESHOLD) mLauncherOverlayCallbacks.onScrollEnd(0f, false);
else mLauncherOverlayCallbacks.onScrollEnd(1f, false);
}
}