Commit 3079a3e2 authored by Amit Kumar's avatar Amit Kumar 💻
Browse files

Finish quickstep porting and implementation

parent 2f3850e5
......@@ -15,7 +15,7 @@ cache:
build:
stage: build
script:
- ./gradlew build
- ./gradlew assmebleApiQ
artifacts:
paths:
- app/build/outputs/apk
......@@ -31,7 +31,6 @@ import android.os.UserHandle;
import android.util.IconDrawableFactory;
import android.util.Log;
import android.util.LruCache;
import com.android.systemui.shared.system.PackageManagerWrapper;
public abstract class IconLoader {
......
......@@ -20,17 +20,14 @@ import static android.view.Display.DEFAULT_DISPLAY;
import android.app.ActivityManager;
import android.app.ActivityManager.TaskDescription;
import android.app.TaskInfo;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.view.ViewDebug;
import com.android.systemui.shared.QuickstepCompat;
import com.android.systemui.shared.recents.utilities.Utilities;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Objects;
......
......@@ -17,13 +17,11 @@
package com.android.systemui.shared.recents.model;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_UNDEFINED;
import android.app.ActivityManager.TaskSnapshot;
import android.graphics.Bitmap;
import android.graphics.Rect;
import com.android.systemui.shared.QuickstepCompat;
/**
......
......@@ -32,7 +32,6 @@ import android.app.ActivityManager;
import android.app.ActivityManager.RecentTaskInfo;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.AppGlobals;
import android.app.IAssistDataReceiver;
import android.app.WindowConfiguration;
......@@ -57,21 +56,15 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import android.view.IRecentsAnimationController;
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationTarget;
import com.android.internal.app.IVoiceInteractionManagerService;
import com.android.systemui.shared.QuickstepCompat;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskKey;
import com.android.systemui.shared.recents.model.ThumbnailData;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import java.util.function.Consumer;
import xyz.paphonb.quickstep.compat.ActivityManagerCompat;
import xyz.paphonb.quickstep.compat.RecentsAnimationRunner;
public class ActivityManagerWrapper {
......
......@@ -31,11 +31,8 @@ import android.view.IWindowManager;
import android.view.InputChannel;
import android.view.InputEvent;
import android.view.WindowManagerGlobal;
import com.android.systemui.shared.QuickstepCompat;
import java.io.PrintWriter;
import xyz.paphonb.quickstep.compat.InputCompat;
/**
......
......@@ -26,9 +26,7 @@ import android.content.res.Resources;
import android.os.Build;
import android.view.ViewConfiguration;
import android.view.WindowManagerPolicyConstants;
import com.android.internal.policy.ScreenDecorationsUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.StringJoiner;
......
......@@ -30,7 +30,6 @@ import android.util.Log;
import android.view.IPinnedStackListener;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import com.android.systemui.shared.QuickstepCompat;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.RecentsTransition;
......
......@@ -171,7 +171,7 @@
android:value="true" />
<service
android:name=".features.quickstep.TouchInteractionService"
android:name=".quickstep.TouchInteractionService"
android:permission="android.permission.STATUS_BAR_SERVICE"
android:directBootAware="true">
<intent-filter>
......@@ -181,7 +181,7 @@
<!-- STOPSHIP: Change exported to false once all the integration is complete.
It is set to true so that the activity can be started from command line -->
<activity android:name=".features.quickstep.RecentsActivity"
<activity android:name=".quickstep.RecentsActivity"
android:exported="true"
android:excludeFromRecents="true"
android:launchMode="singleTask"
......
......@@ -2,6 +2,6 @@ package foundation.e.blisslauncher.core
// used to control the behavior of launcher
object Flags {
const val QUICKSTEP_SPRINGS = true
const val ENABLE_QUICKSTEP_LIVE_TILE = true
}
\ No newline at end of file
const val QUICKSTEP_SPRINGS = true
const val ENABLE_QUICKSTEP_LIVE_TILE = true
}
package foundation.e.blisslauncher.core;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
......@@ -30,6 +30,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
......@@ -102,6 +103,7 @@ public class Utilities {
* See {@link MotionEvent#setEdgeFlags(int)}.
*/
public static final int FLAG_NO_GESTURES = 1 << 9;
/**
* Compresses the bitmap to a byte array for serialization.
*/
......@@ -268,6 +270,13 @@ public class Utilities {
return Math.max(lowerBound, Math.min(value, upperBound));
}
/**
* @see #boundToRange(int, int, int).
*/
public static long boundToRange(long value, long lowerBound, long upperBound) {
return Math.max(lowerBound, Math.min(value, upperBound));
}
public static boolean isSystemApp(Context context, Intent intent) {
PackageManager pm = context.getPackageManager();
ComponentName cn = intent.getComponent();
......@@ -335,6 +344,74 @@ public class Utilities {
return scale;
}
/**
* Given a coordinate relative to the descendant, find the coordinate in a parent view's
* coordinates.
*
* @param descendant The descendant to which the passed coordinate is relative.
* @param ancestor The root view to make the coordinates relative to.
* @param coord The coordinate that we want mapped.
* @param includeRootScroll Whether or not to account for the scroll of the descendant:
* sometimes this is relevant as in a child's coordinates within the descendant.
* @return The factor by which this descendant is scaled relative to this DragLayer. Caution
* this scale factor is assumed to be equal in X and Y, and so if at any point this
* assumption fails, we will need to return a pair of scale factors.
*/
public static float getDescendantCoordRelativeToAncestor(
View descendant, View ancestor, float[] coord, boolean includeRootScroll
) {
return getDescendantCoordRelativeToAncestor(descendant, ancestor, coord, includeRootScroll,
false, null
);
}
/**
* Given a coordinate relative to the descendant, find the coordinate in a parent view's
* coordinates.
*
* @param descendant The descendant to which the passed coordinate is relative.
* @param ancestor The root view to make the coordinates relative to.
* @param coord The coordinate that we want mapped.
* @param includeRootScroll Whether or not to account for the scroll of the descendant:
* sometimes this is relevant as in a child's coordinates within the descendant.
* @param ignoreTransform If true, view transform is ignored
* @param outRotation If not null, and {@param ignoreTransform} is true, this is set to the
* overall rotation of the view in degrees.
* @return The factor by which this descendant is scaled relative to this DragLayer. Caution
* this scale factor is assumed to be equal in X and Y, and so if at any point this
* assumption fails, we will need to return a pair of scale factors.
*/
public static float getDescendantCoordRelativeToAncestor(
View descendant, View ancestor,
float[] coord, boolean includeRootScroll, boolean ignoreTransform,
float[] outRotation
) {
float scale = 1.0f;
View v = descendant;
while (v != ancestor && v != null) {
// For TextViews, scroll has a meaning which relates to the text position
// which is very strange... ignore the scroll.
if (v != descendant || includeRootScroll) {
offsetPoints(coord, -v.getScrollX(), -v.getScrollY());
}
v.getMatrix().mapPoints(coord);
offsetPoints(coord, v.getLeft(), v.getTop());
scale *= v.getScaleX();
v = (View) v.getParent();
}
return scale;
}
public static void offsetPoints(float[] points, float offsetX, float offsetY) {
for (int i = 0; i < points.length; i += 2) {
points[i] += offsetX;
points[i + 1] += offsetY;
}
}
/**
* Inverse of {@link #getDescendantCoordRelativeToAncestor(View, View, int[], boolean)}.
*/
......@@ -357,6 +434,23 @@ public class Utilities {
coord[1] = Math.round(sPoint[1]);
}
/**
* Inverse of {@link #getDescendantCoordRelativeToAncestor(View, View, float[], boolean)}.
*/
public static void mapCoordInSelfToDescendant(View descendant, View root, float[] coord) {
sMatrix.reset();
View v = descendant;
while(v != root) {
sMatrix.postTranslate(-v.getScrollX(), -v.getScrollY());
sMatrix.postConcat(v.getMatrix());
sMatrix.postTranslate(v.getLeft(), v.getTop());
v = (View) v.getParent();
}
sMatrix.postTranslate(-v.getScrollX(), -v.getScrollY());
sMatrix.invert(sInverseMatrix);
sInverseMatrix.mapPoints(coord);
}
/**
* Utility method to determine whether the given point, in local coordinates,
* is inside the view, where the area of the view is expanded by the slop factor.
......@@ -414,7 +508,7 @@ public class Utilities {
try {
return clazz.newInstance();
} catch (InstantiationException|IllegalAccessException e) {
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
......@@ -425,7 +519,7 @@ public class Utilities {
float cy = r.centerY();
r.offset(-cx, -cy);
r.left = r.left * scale;
r.top = r.top * scale ;
r.top = r.top * scale;
r.right = r.right * scale;
r.bottom = r.bottom * scale;
r.offset(cx, cy);
......@@ -462,4 +556,37 @@ public class Utilities {
public static boolean shouldDisableGestures(MotionEvent ev) {
return (ev.getEdgeFlags() & FLAG_NO_GESTURES) == FLAG_NO_GESTURES;
}
public static float getProgress(float current, float min, float max) {
return Math.abs(current - min) / Math.abs(max - min);
}
public static void unregisterReceiverSafely(Context context, BroadcastReceiver receiver) {
try {
context.unregisterReceiver(receiver);
} catch (IllegalArgumentException e) {
}
}
/**
* Maps t from one range to another range.
*
* @param t The value to map.
* @param fromMin The lower bound of the range that t is being mapped from.
* @param fromMax The upper bound of the range that t is being mapped from.
* @param toMin The lower bound of the range that t is being mapped to.
* @param toMax The upper bound of the range that t is being mapped to.
* @return The mapped value of t.
*/
public static float mapToRange(
float t, float fromMin, float fromMax, float toMin, float toMax,
Interpolator interpolator
) {
if (fromMin == fromMax || toMin == toMax) {
Log.e(TAG, "mapToRange: range has 0 length");
return toMin;
}
float progress = getProgress(t, fromMin, fromMax);
return mapRange(interpolator.getInterpolation(progress), toMin, toMax);
}
}
......@@ -14,7 +14,7 @@
* limitations under the License.
*/
package foundation.e.blisslauncher.features.quickstep;
package foundation.e.blisslauncher.core.customviews;
import android.annotation.SuppressLint;
import android.content.Context;
......@@ -39,25 +39,27 @@ import foundation.e.blisslauncher.features.test.TouchController;
*/
public abstract class AbstractFloatingView extends LinearLayout implements TouchController {
@IntDef(flag = true, value = {
TYPE_TASK_MENU,
TYPE_OPTIONS_POPUP
TYPE_TASK_MENU,
TYPE_OPTIONS_POPUP,
TYPE_LISTENER
})
@Retention(RetentionPolicy.SOURCE)
public @interface FloatingViewType {}
public @interface FloatingViewType {
}
public static final int TYPE_LISTENER = 1 << 1;
// Popups related to quickstep UI
public static final int TYPE_TASK_MENU = 1 << 7;
public static final int TYPE_OPTIONS_POPUP = 1 << 8;
public static final int TYPE_TASK_MENU = 1 << 2;
public static final int TYPE_OPTIONS_POPUP = 1 << 3;
public static final int TYPE_ALL = TYPE_TASK_MENU | TYPE_OPTIONS_POPUP;
public static final int TYPE_ALL = TYPE_TASK_MENU | TYPE_OPTIONS_POPUP | TYPE_LISTENER;
public static final int TYPE_ACCESSIBLE = TYPE_ALL;
public static final int TYPE_ACCESSIBLE = TYPE_ALL & ~TYPE_LISTENER;
public static final int TYPE_STATUS_BAR_SWIPE_DOWN_DISALLOW = TYPE_TASK_MENU;
protected boolean mIsOpen;
public AbstractFloatingView(Context context, AttributeSet attrs) {
......@@ -94,7 +96,9 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
protected abstract boolean isOfType(@FloatingViewType int type);
/** @return Whether the back is consumed. If false, Launcher will handle the back as well. */
/**
* @return Whether the back is consumed. If false, Launcher will handle the back as well.
*/
public boolean onBackPressed() {
close(true);
return true;
......@@ -105,13 +109,13 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
return false;
}
protected Pair<View, String> getAccessibilityTarget() {
return null;
}
protected static <T extends AbstractFloatingView> T getOpenView(
BaseDraggingActivity activity, @FloatingViewType int type) {
BaseDraggingActivity activity, @FloatingViewType int type
) {
BaseDragLayer dragLayer = activity.getDragLayer();
// Iterate in reverse order. AbstractFloatingView is added later to the dragLayer,
// and will be one of the last views.
......@@ -127,16 +131,20 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
return null;
}
public static void closeOpenContainer(BaseDraggingActivity activity,
@FloatingViewType int type) {
public static void closeOpenContainer(
BaseDraggingActivity activity,
@FloatingViewType int type
) {
AbstractFloatingView view = getOpenView(activity, type);
if (view != null) {
view.close(true);
}
}
public static void closeOpenViews(BaseDraggingActivity activity, boolean animate,
@FloatingViewType int type) {
public static void closeOpenViews(
BaseDraggingActivity activity, boolean animate,
@FloatingViewType int type
) {
BaseDragLayer dragLayer = activity.getDragLayer();
// Iterate in reverse order. AbstractFloatingView is added later to the dragLayer,
// and will be one of the last views.
......@@ -160,12 +168,29 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
closeAllOpenViews(activity, true);
}
public static void closeAllOpenViewsExcept(
BaseDraggingActivity activity, boolean animate,
@FloatingViewType int type
) {
closeOpenViews(activity, animate, TYPE_ALL & ~type);
activity.finishAutoCancelActionMode();
}
public static void closeAllOpenViewsExcept(
BaseDraggingActivity activity,
@FloatingViewType int type
) {
closeAllOpenViewsExcept(activity, true, type);
}
public static AbstractFloatingView getTopOpenView(BaseDraggingActivity activity) {
return getTopOpenViewWithType(activity, TYPE_ALL);
}
public static AbstractFloatingView getTopOpenViewWithType(BaseDraggingActivity activity,
@FloatingViewType int type) {
public static AbstractFloatingView getTopOpenViewWithType(
BaseDraggingActivity activity,
@FloatingViewType int type
) {
return getOpenView(activity, type);
}
}
package foundation.e.blisslauncher.core.customviews;
import static foundation.e.blisslauncher.core.utils.Constants.ITEM_TYPE_APPLICATION;
import static foundation.e.blisslauncher.features.test.LauncherState.NORMAL;
import static foundation.e.blisslauncher.features.test.anim.LauncherAnimUtils.SPRING_LOADED_TRANSITION_MS;
......@@ -17,6 +18,8 @@ import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
......@@ -547,7 +550,7 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
false,
launcherItem.container != Constants.CONTAINER_HOTSEAT
);
} else if (launcherItem.itemType == Constants.ITEM_TYPE_APPLICATION) {
} else if (launcherItem.itemType == ITEM_TYPE_APPLICATION) {
ApplicationItem applicationItem = (ApplicationItem) launcherItem;
iconView.applyBadge(
false,
......@@ -1957,7 +1960,7 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
boolean aboveShortcut = (dropOverView.getTag() instanceof ShortcutItem || dropOverView
.getTag() instanceof ApplicationItem);
boolean willBecomeShortcut =
(info.itemType == Constants.ITEM_TYPE_APPLICATION ||
(info.itemType == ITEM_TYPE_APPLICATION ||
info.itemType == Constants.ITEM_TYPE_SHORTCUT);
return (aboveShortcut && willBecomeShortcut);
......@@ -2088,6 +2091,106 @@ public class LauncherPagedView extends PagedView<PageIndicatorDots> implements V
builder.play(stepAnimator);
}
/**
* Similar to {@link #getFirstMatch} but optimized to finding a suitable view for the app close
* animation.
*
* @param packageName The package name of the app to match.
* @param user The user of the app to match.
*/
public View getFirstMatchForAppClose(String packageName, UserHandle user) {
final int curPage = getCurrentPage();
final CellLayout currentPage = (CellLayout) getPageAt(curPage);
final LauncherPagedView.ItemOperator packageAndUser = (LauncherItem info, View view) -> info != null
&& info.getTargetComponent() != null
&& TextUtils.equals(info.getTargetComponent().getPackageName(), packageName)
&& info.user.equals(user);
final LauncherPagedView.ItemOperator packageAndUserAndApp = (LauncherItem info, View view) ->
packageAndUser.evaluate(info, view) && info.itemType == ITEM_TYPE_APPLICATION;
return getFirstMatch(new CellLayout[] { mLauncher.getHotseat(), currentPage },
packageAndUserAndApp);
}
/**
* @param cellLayouts List of CellLayouts to scan, in order of preference.
* @param operators List of operators, in order starting from best matching operator.
* @return
*/
private View getFirstMatch(CellLayout[] cellLayouts, final ItemOperator... operators) {
// This array is filled with the first match for each operator.
final View[] matches = new View[operators.length];
// For efficiency, the outer loop should be CellLayout.
for (CellLayout cellLayout : cellLayouts) {
mapOverCellLayout(MAP_NO_RECURSE, cellLayout, (info, v) -> {
for (int i = 0; i < operators.length; ++i) {
if (matches[i] == null && operators[i].evaluate(info, v)) {
matches[i] = v;
if (i == 0) {
// We can return since this is the best match possible.
return true;
}
}
}
return false;
});
if (matches[0] != null) {
break;
}
}
for (View match : matches) {
if (match != null) {
return match;
}
}
return null;
}
private boolean mapOverCellLayout(boolean recurse, CellLayout layout, ItemOperator op) {
// TODO(b/128460496) Potential race condition where layout is not yet loaded
if (layout == null) {
return false;
}
// map over all the shortcuts on the workspace
final int itemCount = layout.getChildCount();
for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {
View item = layout.getChildAt(itemIdx);
LauncherItem info = (LauncherItem) item.getTag();
if (recurse && info instanceof FolderItem) {
FolderItem folder = (FolderItem) info;
List<LauncherItem> folderChildren = folder.items;
// map over all the children in the folder
final int childCount = folder.items.size();
for (int childIdx = 0; childIdx < childCount; childIdx++) {
LauncherItem childItem = folderChildren.get(childIdx);
if (op.evaluate(info, item)) {
return true;
}
}
} else {
if (op.evaluate(info, item)) {
return true;
}
}