Commit cc72e887 authored by Amit Kumar's avatar Amit Kumar 💻
Browse files

Add initial recents ui

parent ddb87c8e
Pipeline #123744 failed with stage
in 3 minutes and 17 seconds
......@@ -105,7 +105,8 @@ dependencies {
apiNougatImplementation 'org.cyanogenmod:platform.sdk:6.0'
apiOreoImplementation files('libs/lineage-sdk-oreo.jar')
apiQImplementation files('libs/lineage-sdk-q.jar')
implementation files('libs/sysui_shared.jar')
debugImplementation 'com.amitshekhar.android:debug-db:1.0.4'
......
......@@ -157,6 +157,29 @@
<meta-data
android:name="android.nfc.disable_beam_default"
android:value="true" />
<service
android:name=".features.quickstep.TouchInteractionService"
android:permission="android.permission.STATUS_BAR_SERVICE" >
<intent-filter>
<action android:name="android.intent.action.QUICKSTEP_SERVICE" />
</intent-filter>
</service>
<!-- 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"
android:exported="true"
android:excludeFromRecents="true"
android:launchMode="singleTask"
android:clearTaskOnLaunch="true"
android:stateNotNeeded="true"
android:theme="@style/LauncherTheme"
android:screenOrientation="unspecified"
android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:taskAffinity="" />
</application>
</manifest>
\ No newline at end of file
......@@ -7,6 +7,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
......@@ -15,6 +16,7 @@ import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.PowerManager;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
......@@ -363,4 +365,17 @@ public class Utilities {
r.bottom = (int) (r.bottom * scale + 0.5f);
}
}
public static boolean isRtl(Resources res) {
return res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
}
public static boolean isPowerSaverPreventingAnimation(Context context) {
if (ATLEAST_P) {
// Battery saver mode no longer prevents animations.
return false;
}
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
return powerManager.isPowerSaveMode();
}
}
/*
* Copyright (C) 2016 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.quickstep;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import androidx.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import foundation.e.blisslauncher.core.Utilities;
import foundation.e.blisslauncher.features.test.BaseDragLayer;
import foundation.e.blisslauncher.features.test.BaseDraggingActivity;
import foundation.e.blisslauncher.features.test.TouchController;
/**
* Base class for a View which shows a floating UI on top of the launcher UI.
*/
public abstract class AbstractFloatingView extends LinearLayout implements TouchController {
@IntDef(flag = true, value = {
TYPE_QUICKSTEP_PREVIEW,
TYPE_TASK_MENU,
TYPE_OPTIONS_POPUP
})
@Retention(RetentionPolicy.SOURCE)
public @interface FloatingViewType {}
// Popups related to quickstep UI
public static final int TYPE_QUICKSTEP_PREVIEW = 1 << 6;
public static final int TYPE_TASK_MENU = 1 << 7;
public static final int TYPE_OPTIONS_POPUP = 1 << 8;
public static final int TYPE_ALL = TYPE_QUICKSTEP_PREVIEW | TYPE_TASK_MENU | TYPE_OPTIONS_POPUP;
// Type of popups which should be kept open during launcher rebind
public static final int TYPE_REBIND_SAFE = TYPE_QUICKSTEP_PREVIEW ;
protected boolean mIsOpen;
public AbstractFloatingView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AbstractFloatingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* We need to handle touch events to prevent them from falling through to the workspace below.
*/
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent ev) {
return true;
}
public final void close(boolean animate) {
animate &= !Utilities.isPowerSaverPreventingAnimation(getContext());
handleClose(animate);
mIsOpen = false;
}
protected abstract void handleClose(boolean animate);
public final boolean isOpen() {
return mIsOpen;
}
protected void onWidgetsBound() {
}
protected abstract boolean isOfType(@FloatingViewType int type);
/** @return Whether the back is consumed. If false, Launcher will handle the back as well. */
public boolean onBackPressed() {
close(true);
return true;
}
@Override
public boolean onControllerTouchEvent(MotionEvent ev) {
return false;
}
protected Pair<View, String> getAccessibilityTarget() {
return null;
}
protected static <T extends AbstractFloatingView> T getOpenView(
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.
for (int i = dragLayer.getChildCount() - 1; i >= 0; i--) {
View child = dragLayer.getChildAt(i);
if (child instanceof AbstractFloatingView) {
AbstractFloatingView view = (AbstractFloatingView) child;
if (view.isOfType(type) && view.isOpen()) {
return (T) view;
}
}
}
return null;
}
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) {
BaseDragLayer dragLayer = activity.getDragLayer();
// Iterate in reverse order. AbstractFloatingView is added later to the dragLayer,
// and will be one of the last views.
for (int i = dragLayer.getChildCount() - 1; i >= 0; i--) {
View child = dragLayer.getChildAt(i);
if (child instanceof AbstractFloatingView) {
AbstractFloatingView abs = (AbstractFloatingView) child;
if (abs.isOfType(type)) {
abs.close(animate);
}
}
}
}
public static void closeAllOpenViews(BaseDraggingActivity activity, boolean animate) {
closeOpenViews(activity, animate, TYPE_ALL);
activity.finishAutoCancelActionMode();
}
public static void closeAllOpenViews(BaseDraggingActivity activity) {
closeAllOpenViews(activity, true);
}
public static AbstractFloatingView getTopOpenView(BaseDraggingActivity activity) {
return getTopOpenViewWithType(activity, TYPE_ALL);
}
public static AbstractFloatingView getTopOpenViewWithType(BaseDraggingActivity activity,
@FloatingViewType int type) {
return getOpenView(activity, type);
}
}
/*
* 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.quickstep;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.util.FloatProperty;
/**
* A mutable float which allows animating the value
*/
public class AnimatedFloat {
public static FloatProperty<AnimatedFloat> VALUE = new FloatProperty<AnimatedFloat>("value") {
@Override
public void setValue(AnimatedFloat obj, float v) {
obj.updateValue(v);
}
@Override
public Float get(AnimatedFloat obj) {
return obj.value;
}
};
private final Runnable mUpdateCallback;
private ObjectAnimator mValueAnimator;
public float value;
public AnimatedFloat(Runnable updateCallback) {
mUpdateCallback = updateCallback;
}
public ObjectAnimator animateToValue(float start, float end) {
cancelAnimation();
mValueAnimator = ObjectAnimator.ofFloat(this, VALUE, start, end);
mValueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
if (mValueAnimator == animator) {
mValueAnimator = null;
}
}
});
return mValueAnimator;
}
/**
* Changes the value and calls the callback.
* Note that the value can be directly accessed as well to avoid notifying the callback.
*/
public void updateValue(float v) {
if (Float.compare(v, value) != 0) {
value = v;
mUpdateCallback.run();
}
}
public void cancelAnimation() {
if (mValueAnimator != null) {
mValueAnimator.cancel();
}
}
public void finishAnimation() {
if (mValueAnimator != null && mValueAnimator.isRunning()) {
mValueAnimator.end();
}
}
public ObjectAnimator getCurrentAnimation() {
return mValueAnimator;
}
}
/*
* Copyright (C) 2018 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.quickstep;
import android.annotation.TargetApi;
import android.os.Build;
import android.view.Choreographer;
import android.view.MotionEvent;
import android.view.VelocityTracker;
/**
* A TouchConsumer which defers all events on the UIThread until the consumer is created.
*/
@TargetApi(Build.VERSION_CODES.P)
public class DeferredTouchConsumer implements TouchConsumer {
private final VelocityTracker mVelocityTracker;
private final DeferredTouchProvider mTouchProvider;
private MotionEventQueue mMyQueue;
private TouchConsumer mTarget;
public DeferredTouchConsumer(DeferredTouchProvider touchProvider) {
mVelocityTracker = VelocityTracker.obtain();
mTouchProvider = touchProvider;
}
@Override
public void accept(MotionEvent event) {
mTarget.accept(event);
}
@Override
public void reset() {
mTarget.reset();
}
@Override
public void updateTouchTracking(int interactionType) {
mTarget.updateTouchTracking(interactionType);
}
@Override
public void onQuickScrubEnd() {
mTarget.onQuickScrubEnd();
}
@Override
public void onQuickScrubProgress(float progress) {
mTarget.onQuickScrubProgress(progress);
}
@Override
public void onQuickStep(MotionEvent ev) {
mTarget.onQuickStep(ev);
}
@Override
public void onCommand(int command) {
mTarget.onCommand(command);
}
@Override
public void preProcessMotionEvent(MotionEvent ev) {
mVelocityTracker.addMovement(ev);
}
@Override
public Choreographer getIntrimChoreographer(MotionEventQueue queue) {
mMyQueue = queue;
return null;
}
@Override
public void deferInit() {
mTarget = mTouchProvider.createTouchConsumer(mVelocityTracker);
mTarget.getIntrimChoreographer(mMyQueue);
}
@Override
public boolean forceToLauncherConsumer() {
return mTarget.forceToLauncherConsumer();
}
@Override
public boolean deferNextEventToMainThread() {
// If our target is still null, defer the next target as well
TouchConsumer target = mTarget;
return target == null ? true : target.deferNextEventToMainThread();
}
@Override
public void onShowOverviewFromAltTab() {
mTarget.onShowOverviewFromAltTab();
}
public interface DeferredTouchProvider {
TouchConsumer createTouchConsumer(VelocityTracker tracker);
}
}
/*
* Copyright (C) 2018 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.quickstep;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.InstantAppInfo;
import android.content.pm.PackageManager;
import android.util.Log;
import com.android.launcher3.AppInfo;
import com.android.launcher3.util.InstantAppResolver;
import java.util.ArrayList;
import java.util.List;
/**
* Implementation of InstantAppResolver using platform APIs
*/
@SuppressWarnings("unused")
public class InstantAppResolverImpl extends InstantAppResolver {
private static final String TAG = "InstantAppResolverImpl";
public static final String COMPONENT_CLASS_MARKER = "@instantapp";
private final PackageManager mPM;
public InstantAppResolverImpl(Context context)
throws NoSuchMethodException, ClassNotFoundException {
mPM = context.getPackageManager();
}
@Override
public boolean isInstantApp(ApplicationInfo info) {
return info.isInstantApp();
}
@Override
public boolean isInstantApp(AppInfo info) {
ComponentName cn = info.getTargetComponent();
return cn != null && cn.getClassName().equals(COMPONENT_CLASS_MARKER);
}
@Override
public List<ApplicationInfo> getInstantApps() {
try {
List<ApplicationInfo> result = new ArrayList<>();
for (InstantAppInfo iai : mPM.getInstantApps()) {
ApplicationInfo info = iai.getApplicationInfo();
if (info != null) {
result.add(info);
}
}
return result;
} catch (SecurityException se) {
Log.w(TAG, "getInstantApps failed. Launcher may not be the default home app.", se);
} catch (Exception e) {
Log.e(TAG, "Error calling API: getInstantApps", e);
}
return super.getInstantApps();
}
}
/*
* Copyright (C) 2018 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.quickstep;
import android.annotation.TargetApi;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.ResolveInfo;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.os.Build;
import android.provider.SearchIndexablesContract.XmlResource;
import android.provider.SearchIndexablesProvider;
import android.util.Xml;
import com.android.launcher3.R;
import com.android.launcher3.graphics.IconShapeOverride;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import static android.provider.SearchIndexablesContract.INDEXABLES_RAW_COLUMNS;
import static android.provider.SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS;
import static android.provider.SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS;
@TargetApi(Build.VERSION_CODES.O)
public class LauncherSearchIndexablesProvider extends SearchIndexablesProvider {