Merge "Fill in LauncherTarget fields with values extracted from LauncherLogProto.Target." into ub-launcher3-qt-future-dev
diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java
index 3aa783a..e40a9c2 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java
@@ -17,7 +17,6 @@
import android.content.ComponentName;
import android.content.Context;
-import android.content.pm.PackageInfo;
import android.os.LocaleList;
import android.os.UserHandle;
@@ -44,13 +43,6 @@
}
/**
- * Returns the timestamp the entry was last updated in cache.
- */
- default long getLastUpdatedTime(T object, PackageInfo info) {
- return info.lastUpdateTime;
- }
-
- /**
* Returns true the object should be added to mem cache; otherwise returns false.
*/
default boolean addToMemCache() {
diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java b/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java
index bcdbce5..8224966 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java
@@ -171,8 +171,7 @@
long updateTime = c.getLong(indexLastUpdate);
int version = c.getInt(indexVersion);
T app = componentMap.remove(component);
- if (version == info.versionCode
- && updateTime == cachingLogic.getLastUpdatedTime(app, info)
+ if (version == info.versionCode && updateTime == info.lastUpdateTime
&& TextUtils.equals(c.getString(systemStateIndex),
mIconCache.getIconSystemState(info.packageName))) {
@@ -232,6 +231,7 @@
}
}
+
/**
* A runnable that updates invalid icons and adds missing icons in the DB for the provided
* LauncherActivityInfo list. Items are updated/added one at a time, so that the
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
index 4a3ad1d..e215cfe 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
@@ -32,8 +32,8 @@
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE;
import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
@@ -132,16 +132,33 @@
// Fade in prediction icons quickly, then rest of all apps after reaching overview.
float progressToReachOverview = NORMAL.getVerticalProgress(mLauncher)
- OVERVIEW.getVerticalProgress(mLauncher);
- builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress(ACCEL,
- 0, ALL_APPS_CONTENT_FADE_THRESHOLD));
- builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(LINEAR,
- progressToReachOverview, 1));
+ builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress(
+ ACCEL,
+ 0,
+ ALL_APPS_CONTENT_FADE_THRESHOLD));
+ builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(
+ ACCEL,
+ progressToReachOverview,
+ progressToReachOverview + ALL_APPS_CONTENT_FADE_THRESHOLD));
// Get workspace out of the way quickly, to prepare for potential pause.
builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL_3);
builder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, DEACCEL_3);
builder.setInterpolator(ANIM_WORKSPACE_FADE, DEACCEL_3);
return builder;
+ } else if (fromState == ALL_APPS && toState == NORMAL) {
+ AnimatorSetBuilder builder = new AnimatorSetBuilder();
+ // Keep all apps/predictions opaque until the very end of the transition.
+ float progressToReachOverview = OVERVIEW.getVerticalProgress(mLauncher);
+ builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(
+ DEACCEL,
+ progressToReachOverview - ALL_APPS_CONTENT_FADE_THRESHOLD,
+ progressToReachOverview));
+ builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress(
+ DEACCEL,
+ 1 - ALL_APPS_CONTENT_FADE_THRESHOLD,
+ 1));
+ return builder;
}
return super.getAnimatorSetBuilderForStates(fromState, toState);
}
@@ -164,6 +181,7 @@
AnimatorSetBuilder builder = new AnimatorSetBuilder();
builder.setInterpolator(ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2);
+ builder.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_3);
if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
builder.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2);
builder.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
index c17b2fe..57e6d96 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
@@ -273,17 +273,7 @@
// from the side. Calculate the start translation based on current scale/scroll.
float currScale = recentsView.getScaleX();
float scrollOffsetX = recentsView.getScrollOffset();
-
- float offscreenX = NORMAL.getOverviewScaleAndTranslation(activity).translationX;
- // The first task is hidden, so offset by its width.
- int firstTaskWidth = recentsView.getTaskViewAt(0).getWidth();
- offscreenX -= (firstTaskWidth + recentsView.getPageSpacing()) * currScale;
- // Offset since scale pushes tasks outwards.
- offscreenX += firstTaskWidth * (currScale - 1) / 2;
- offscreenX = Math.max(0, offscreenX);
- if (recentsView.isRtl()) {
- offscreenX = -offscreenX;
- }
+ float offscreenX = recentsView.getOffscreenTranslationX(currScale);
float fromTranslationX = attached ? offscreenX - scrollOffsetX : 0;
float toTranslationX = attached ? 0 : offscreenX - scrollOffsetX;
@@ -380,6 +370,10 @@
TaskView runningTaskView = recentsView.getRunningTaskView();
if (runningTaskView == null) {
runningTaskView = recentsView.getCurrentPageTaskView();
+ if (runningTaskView == null) {
+ // There are no task views in LockTask mode when Overview is enabled.
+ return;
+ }
}
TimeInterpolator oldInterpolator = translateY.getInterpolator();
Rect fallbackInsets = launcher.getDeviceProfile().getInsets();
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java
index 79273ea..a8d402e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java
@@ -161,9 +161,6 @@
@Override
public void run() {
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.ALL_APPS_UPON_RECENTS, "RecentsActivityCommand.run");
- }
long elapsedTime = mCreateTime - mLastToggleTime;
mLastToggleTime = mCreateTime;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java
index e51ba63..c4d3fa0 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java
@@ -19,6 +19,8 @@
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
+import android.os.SystemClock;
+import android.util.Log;
import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -38,6 +40,8 @@
*/
public class RecentsAnimationWrapper {
+ private static final String TAG = "RecentsAnimationWrapper";
+
// A list of callbacks to run when we receive the recents animation target. There are different
// than the state callbacks as these run on the current worker thread.
private final ArrayList<Runnable> mCallbacks = new ArrayList<>();
@@ -125,6 +129,7 @@
boolean sendUserLeaveHint) {
SwipeAnimationTargetSet controller = targetSet;
targetSet = null;
+ disableInputProxy();
if (controller != null) {
controller.finishController(toRecents, onFinishComplete, sendUserLeaveHint);
}
@@ -153,6 +158,16 @@
mInputConsumerController.setInputListener(this::onInputConsumerEvent);
}
+ private void disableInputProxy() {
+ if (mInputConsumer != null && mTouchInProgress) {
+ long now = SystemClock.uptimeMillis();
+ MotionEvent dummyCancel = MotionEvent.obtain(now, now, ACTION_CANCEL, 0, 0, 0);
+ mInputConsumer.onMotionEvent(dummyCancel);
+ dummyCancel.recycle();
+ }
+ mInputConsumerController.setInputListener(null);
+ }
+
private boolean onInputConsumerEvent(InputEvent ev) {
if (ev instanceof MotionEvent) {
onInputConsumerMotionEvent((MotionEvent) ev);
@@ -168,6 +183,18 @@
private boolean onInputConsumerMotionEvent(MotionEvent ev) {
int action = ev.getAction();
+
+ // Just to be safe, verify that ACTION_DOWN comes before any other action,
+ // and ignore any ACTION_DOWN after the first one (though that should not happen).
+ if (!mTouchInProgress && action != ACTION_DOWN) {
+ Log.w(TAG, "Received non-down motion before down motion: " + action);
+ return false;
+ }
+ if (mTouchInProgress && action == ACTION_DOWN) {
+ Log.w(TAG, "Received down motion while touch was already in progress");
+ return false;
+ }
+
if (action == ACTION_DOWN) {
mTouchInProgress = true;
if (mInputConsumer == null) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
index 03441c8..b601834 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -57,6 +57,8 @@
@TargetApi(Build.VERSION_CODES.O)
public class LauncherRecentsView extends RecentsView<Launcher> implements StateListener {
+ private static final Rect sTempRect = new Rect();
+
private final TransformParams mTransformParams = new TransformParams();
public LauncherRecentsView(Context context) {
@@ -144,6 +146,25 @@
LayoutUtils.calculateLauncherTaskSize(getContext(), dp, outRect);
}
+ /**
+ * @return The translationX to apply to this view so that the first task is just offscreen.
+ */
+ public float getOffscreenTranslationX(float recentsScale) {
+ float offscreenX = NORMAL.getOverviewScaleAndTranslation(mActivity).translationX;
+ // Offset since scale pushes tasks outwards.
+ getTaskSize(sTempRect);
+ int taskWidth = sTempRect.width();
+ offscreenX += taskWidth * (recentsScale - 1) / 2;
+ if (mRunningTaskTileHidden) {
+ // The first task is hidden, so offset by its width.
+ offscreenX -= (taskWidth + getPageSpacing()) * recentsScale;
+ }
+ if (isRtl()) {
+ offscreenX = -offscreenX;
+ }
+ return offscreenX;
+ }
+
@Override
protected void onTaskLaunchAnimationUpdate(float progress, TaskView tv) {
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index 12b37cb..554f437 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -272,7 +272,7 @@
// Only valid until the launcher state changes to NORMAL
protected int mRunningTaskId = -1;
- private boolean mRunningTaskTileHidden;
+ protected boolean mRunningTaskTileHidden;
private Task mTmpRunningTask;
private boolean mRunningTaskIconScaledDown = false;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java
index 742d6a2..07d0796 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java
@@ -161,9 +161,6 @@
}
public static TaskMenuView showForTask(TaskView taskView) {
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.WELLBEING_NO_TASK_MENU, "showForTask");
- }
BaseDraggingActivity activity = BaseDraggingActivity.fromContext(taskView.getContext());
final TaskMenuView taskMenuView = (TaskMenuView) activity.getLayoutInflater().inflate(
R.layout.task_menu, activity.getDragLayer(), false);
@@ -171,15 +168,9 @@
}
private boolean populateAndShowForTask(TaskView taskView) {
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.WELLBEING_NO_TASK_MENU, "populateAndShowForTask1");
- }
if (isAttachedToWindow()) {
return false;
}
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.WELLBEING_NO_TASK_MENU, "populateAndShowForTask2");
- }
mActivity.getDragLayer().addView(this);
mTaskView = taskView;
addMenuOptions(mTaskView);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
index 7f1e898..044292a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -39,24 +39,28 @@
import android.util.FloatProperty;
import android.util.Property;
import android.view.View;
+import android.view.ViewGroup;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
import com.android.quickstep.TaskOverlayFactory;
import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
import com.android.quickstep.util.TaskCornerRadius;
+import com.android.systemui.plugins.OverviewScreenshotActions;
+import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
/**
* A task in the Recents view.
*/
-public class TaskThumbnailView extends View {
+public class TaskThumbnailView extends View implements PluginListener<OverviewScreenshotActions> {
private final static ColorMatrix COLOR_MATRIX = new ColorMatrix();
private final static ColorMatrix SATURATION_COLOR_MATRIX = new ColorMatrix();
@@ -100,6 +104,7 @@
private boolean mOverlayEnabled;
private boolean mRotated;
+ private OverviewScreenshotActions mOverviewScreenshotActionsPlugin;
public TaskThumbnailView(Context context) {
this(context, null);
@@ -147,6 +152,11 @@
mPaint.setShader(null);
mOverlay.reset();
}
+
+ if (mOverviewScreenshotActionsPlugin != null) {
+ mOverviewScreenshotActionsPlugin
+ .setupActions((ViewGroup) getTaskView(), getThumbnail(), mActivity);
+ }
updateThumbnailPaintFilter();
}
@@ -211,6 +221,33 @@
canvas.restore();
}
+ @Override
+ public void onPluginConnected(OverviewScreenshotActions overviewScreenshotActions,
+ Context context) {
+ mOverviewScreenshotActionsPlugin = overviewScreenshotActions;
+ mOverviewScreenshotActionsPlugin.setupActions(getTaskView(), getThumbnail(), mActivity);
+ }
+
+ @Override
+ public void onPluginDisconnected(OverviewScreenshotActions plugin) {
+ if (mOverviewScreenshotActionsPlugin != null) {
+ mOverviewScreenshotActionsPlugin = null;
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ PluginManagerWrapper.INSTANCE.get(getContext())
+ .addPluginListener(this, OverviewScreenshotActions.class);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ PluginManagerWrapper.INSTANCE.get(getContext()).removePluginListener(this);
+ }
+
public RectF getInsetsToDrawInFullscreen(boolean isMultiWindowMode) {
// Don't show insets in multi window mode.
return isMultiWindowMode ? EMPTY_RECT_F : mClippedInsets;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index 3eed281..51802df 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -391,9 +391,6 @@
mIconView.setDrawable(icon);
mIconView.setOnClickListener(v -> showTaskMenu(Touch.TAP));
mIconView.setOnLongClickListener(v -> {
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.WELLBEING_NO_TASK_MENU, "setOnLongClickListener");
- }
requestDisallowInterceptTouchEvent(true);
return showTaskMenu(Touch.LONGPRESS);
});
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index b81edfa..9813295 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -177,6 +177,20 @@
return builder;
}
+ private AnimatorSetBuilder getNormalToAllAppsAnimation() {
+ AnimatorSetBuilder builder = new AnimatorSetBuilder();
+ builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(ACCEL,
+ 0, ALL_APPS_CONTENT_FADE_THRESHOLD));
+ return builder;
+ }
+
+ private AnimatorSetBuilder getAllAppsToNormalAnimation() {
+ AnimatorSetBuilder builder = new AnimatorSetBuilder();
+ builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(DEACCEL,
+ 1 - ALL_APPS_CONTENT_FADE_THRESHOLD, 1));
+ return builder;
+ }
+
@Override
protected AnimatorSetBuilder getAnimatorSetBuilderForStates(LauncherState fromState,
LauncherState toState) {
@@ -187,6 +201,10 @@
builder = getOverviewToAllAppsAnimation();
} else if (fromState == ALL_APPS && toState == OVERVIEW) {
builder = getAllAppsToOverviewAnimation();
+ } else if (fromState == NORMAL && toState == ALL_APPS) {
+ builder = getNormalToAllAppsAnimation();
+ } else if (fromState == ALL_APPS && toState == NORMAL) {
+ builder = getAllAppsToNormalAnimation();
}
return builder;
}
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
index dc6b56e..26e9eaf 100644
--- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
+++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
@@ -161,7 +161,7 @@
mMidProgress = OVERVIEW.getVerticalProgress(mLauncher);
Rect hotseatPadding = dp.getHotseatLayoutPadding();
int hotseatSize = dp.hotseatBarSizePx + dp.getInsets().bottom
- - hotseatPadding.bottom - hotseatPadding.top;
+ + hotseatPadding.bottom + hotseatPadding.top;
float dragHandleTop =
Math.min(hotseatSize, OverviewState.getDefaultSwipeHeight(context, dp));
mDragHandleProgress = 1 - (dragHandleTop / mShiftRange);
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index e5f949b..8c11c1c 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -42,6 +42,7 @@
import androidx.test.uiautomator.Until;
import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.tapl.TestHelpers;
import com.android.launcher3.testcomponent.TestCommandReceiver;
import com.android.launcher3.util.rule.FailureWatcher;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
@@ -78,7 +79,7 @@
Context context = instrumentation.getContext();
mDevice = UiDevice.getInstance(instrumentation);
mDevice.setOrientationNatural();
- mLauncher = new LauncherInstrumentation(instrumentation);
+ mLauncher = new LauncherInstrumentation();
mOrderSensitiveRules = RuleChain.
outerRule(new NavigationModeSwitchRule(mLauncher)).
@@ -103,6 +104,11 @@
}
}
};
+ if (TestHelpers.isInLauncherProcess()) {
+ mLauncher.setSystemHealthSupplier(startTime -> TestCommandReceiver.callCommand(
+ TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE, startTime.toString()).
+ getString("result"));
+ }
}
@NavigationModeSwitch(mode = THREE_BUTTON)
diff --git a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
index c5b560c..2111e2c 100644
--- a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
@@ -25,7 +25,6 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.Launcher;
-import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.util.RaceConditionReproducer;
import com.android.quickstep.NavigationModeSwitchRule.Mode;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
@@ -80,8 +79,6 @@
@Test
@NavigationModeSwitch
public void testStressPressHome() {
- if (LauncherInstrumentation.isAvd()) return; // b/136278866
-
for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
// Destroy Launcher activity.
closeLauncherActivity();
@@ -94,8 +91,6 @@
@Test
@NavigationModeSwitch
public void testStressSwipeToOverview() {
- if (LauncherInstrumentation.isAvd()) return; // b/136278866
-
for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
// Destroy Launcher activity.
closeLauncherActivity();
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index e76b898..7be584e 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -159,21 +159,6 @@
<attr name="canThumbDetach" format="boolean" />
</declare-styleable>
- <declare-styleable name="CustomAppWidgetProviderInfo">
- <attr name="providerId" format="integer" />
-
- <attr name="android:label" />
- <attr name="android:initialLayout" />
- <attr name="android:icon" />
- <attr name="android:previewImage" />
- <attr name="android:resizeMode" />
-
- <attr name="numRows" />
- <attr name="numColumns" />
- <attr name="numMinRows" format="integer" />
- <attr name="numMinColumns" format="integer" />
- </declare-styleable>
-
<declare-styleable name="PreviewFragment">
<attr name="android:name" />
<attr name="android:id" />
diff --git a/res/xml/custom_widgets.xml b/res/xml/custom_widgets.xml
deleted file mode 100644
index 4b54386..0000000
--- a/res/xml/custom_widgets.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-
-<widgets>
- <!-- Sample widget definition
- <widget
- android:label="My custom widget"
- android:initialLayout="@layout/sample_widget_layout"
- android:icon="@drawable/ic_launcher_home"
- android:resizeMode="horizontal|vertical"
- launcher:numRows="2"
- launcher:numColumns="3"
- launcher:numMinRows="1"
- launcher:numMinColumns="2"
- launcher:providerId="1" />
- -->
-</widgets>
\ No newline at end of file
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index b113249..7adb6a4 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -104,6 +104,8 @@
private Drawable mIcon;
private final boolean mCenterVertically;
+ private final int mDisplay;
+
private final CheckLongPressHelper mLongPressHelper;
private final StylusEventHelper mStylusEventHelper;
private final float mSlop;
@@ -133,6 +135,9 @@
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mDisableRelayout = false;
+ @ViewDebug.ExportedProperty(category = "launcher")
+ private final boolean mIgnorePaddingTouch;
+
private IconLoadRequest mIconLoadRequest;
public BubbleTextView(Context context) {
@@ -152,26 +157,32 @@
R.styleable.BubbleTextView, defStyle, 0);
mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false);
- int display = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE);
+ mDisplay = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE);
final int defaultIconSize;
- if (display == DISPLAY_WORKSPACE) {
+ if (mDisplay == DISPLAY_WORKSPACE) {
DeviceProfile grid = mActivity.getWallpaperDeviceProfile();
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
defaultIconSize = grid.iconSizePx;
- } else if (display == DISPLAY_ALL_APPS) {
+ mIgnorePaddingTouch = true;
+ } else if (mDisplay == DISPLAY_ALL_APPS) {
DeviceProfile grid = mActivity.getDeviceProfile();
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx);
setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx);
defaultIconSize = grid.allAppsIconSizePx;
- } else if (display == DISPLAY_FOLDER) {
+ mIgnorePaddingTouch = true;
+ } else if (mDisplay == DISPLAY_FOLDER) {
DeviceProfile grid = mActivity.getDeviceProfile();
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.folderChildTextSizePx);
setCompoundDrawablePadding(grid.folderChildDrawablePaddingPx);
defaultIconSize = grid.folderChildIconSizePx;
+ mIgnorePaddingTouch = true;
} else {
+ // widget_selection or shortcut_popup
defaultIconSize = mActivity.getDeviceProfile().iconSizePx;
+ mIgnorePaddingTouch = false;
}
+
mCenterVertically = a.getBoolean(R.styleable.BubbleTextView_centerVertically, false);
mIconSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_iconSizeOverride,
@@ -319,6 +330,15 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
+ // ignore events if they happen in padding area
+ if (event.getAction() == MotionEvent.ACTION_DOWN && mIgnorePaddingTouch
+ && (event.getY() < getPaddingTop()
+ || event.getX() < getPaddingLeft()
+ || event.getY() > getHeight() - getPaddingBottom()
+ || event.getX() > getWidth() - getPaddingRight())) {
+ return false;
+ }
+
// Call the superclass onTouchEvent first, because sometimes it changes the state to
// isPressed() on an ACTION_UP
boolean result = super.onTouchEvent(event);
@@ -564,7 +584,11 @@
mDotInfo = mActivity.getDotInfoForItem(itemInfo);
boolean isDotted = mDotInfo != null;
float newDotScale = isDotted ? 1f : 0;
- mDotRenderer = mActivity.getDeviceProfile().mDotRenderer;
+ if (mDisplay == DISPLAY_ALL_APPS) {
+ mDotRenderer = mActivity.getDeviceProfile().mDotRendererAllApps;
+ } else {
+ mDotRenderer = mActivity.getDeviceProfile().mDotRendererWorkSpace;
+ }
if (wasDotted || isDotted) {
// Animate when a dot is first added or when it is removed.
if (animate && (wasDotted ^ isDotted) && isShown()) {
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 44c3070..c034d2d 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -129,7 +129,8 @@
private boolean mIsSeascape;
// Notification dots
- public DotRenderer mDotRenderer;
+ public DotRenderer mDotRendererWorkSpace;
+ public DotRenderer mDotRendererAllApps;
public DeviceProfile(Context context, InvariantDeviceProfile inv,
Point minSize, Point maxSize,
@@ -230,8 +231,11 @@
updateWorkspacePadding();
// This is done last, after iconSizePx is calculated above.
- mDotRenderer = new DotRenderer(iconSizePx, IconShape.getShapePath(),
+ mDotRendererWorkSpace = new DotRenderer(iconSizePx, IconShape.getShapePath(),
IconShape.DEFAULT_PATH_SIZE);
+ mDotRendererAllApps = iconSizePx == allAppsIconSizePx ? mDotRendererWorkSpace :
+ new DotRenderer(allAppsIconSizePx, IconShape.getShapePath(),
+ IconShape.DEFAULT_PATH_SIZE);
}
public DeviceProfile copy(Context context) {
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index fb80537..17fbb79 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -619,6 +619,11 @@
}
private static WorkspaceItemInfo createWorkspaceItemInfo(Intent data, LauncherAppState app) {
+ if (data == null) {
+ Log.e(TAG, "Can't construct WorkspaceItemInfo with null data");
+ return null;
+ }
+
Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index d667e8c..7bb618d 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -79,6 +79,7 @@
import android.widget.Toast;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
@@ -147,7 +148,7 @@
import com.android.launcher3.widget.WidgetHostViewLoader;
import com.android.launcher3.widget.WidgetListRowEntry;
import com.android.launcher3.widget.WidgetsFullSheet;
-import com.android.launcher3.widget.custom.CustomWidgetParser;
+import com.android.launcher3.widget.custom.CustomWidgetManager;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -158,9 +159,6 @@
import java.util.List;
import java.util.function.Predicate;
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-
/**
* Default launcher application.
*/
@@ -1666,10 +1664,9 @@
} else {
// In this case, we either need to start an activity to get permission to bind
// the widget, or we need to start an activity to configure the widget, or both.
- if (FeatureFlags.ENABLE_CUSTOM_WIDGETS &&
- info.itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET) {
- appWidgetId = CustomWidgetParser.getWidgetIdForCustomProvider(
- this, info.componentName);
+ if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET) {
+ appWidgetId = CustomWidgetManager.INSTANCE.get(this).getWidgetIdForCustomProvider(
+ info.componentName);
} else {
appWidgetId = getAppWidgetHost().allocateAppWidgetId();
}
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index b4a2216..d70abc2 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -37,6 +37,7 @@
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.SecureSettingsObserver;
+import com.android.launcher3.widget.custom.CustomWidgetManager;
public class LauncherAppState {
@@ -149,6 +150,8 @@
LauncherModel setLauncher(Launcher launcher) {
getLocalProvider(mContext).setLauncherProviderChangeListener(launcher);
mModel.initialize(launcher);
+ CustomWidgetManager.INSTANCE.get(launcher)
+ .setWidgetRefreshCallback(mModel::refreshAndBindWidgetsAndShortcuts);
return mModel;
}
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index 64ec730..1215d43 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -27,12 +27,12 @@
import android.content.Intent;
import android.os.Handler;
import android.util.SparseArray;
-import android.view.LayoutInflater;
import android.widget.Toast;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.widget.DeferredAppWidgetHostView;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.launcher3.widget.custom.CustomWidgetManager;
import java.util.ArrayList;
import java.util.function.IntConsumer;
@@ -193,10 +193,8 @@
LauncherAppWidgetProviderInfo appWidget) {
if (appWidget.isCustomWidget()) {
LauncherAppWidgetHostView lahv = new LauncherAppWidgetHostView(context);
- LayoutInflater inflater = (LayoutInflater)
- context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- inflater.inflate(appWidget.initialLayout, lahv);
lahv.setAppWidget(0, appWidget);
+ CustomWidgetManager.INSTANCE.get(context).onViewCreated(lahv);
return lahv;
} else if ((mFlags & FLAG_LISTENING) == 0) {
DeferredAppWidgetHostView view = new DeferredAppWidgetHostView(context);
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 14f6598..c0cf135 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -22,7 +22,6 @@
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
@@ -54,8 +53,6 @@
import com.android.launcher3.model.ShortcutsChangedTask;
import com.android.launcher3.model.UserLockStateChangedTask;
import com.android.launcher3.shortcuts.DeepShortcutManager;
-import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.PackageUserKey;
@@ -553,5 +550,4 @@
public Callbacks getCallback() {
return mCallbacks != null ? mCallbacks.get() : null;
}
-
}
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 242e099..c509680 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -59,6 +59,10 @@
public static final String ITEM_TYPE = "itemType";
/**
+ * The gesture is a package
+ */
+ public static final int ITEM_TYPE_NON_ACTIONABLE = -1;
+ /**
* The gesture is an application
*/
public static final int ITEM_TYPE_APPLICATION = 0;
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 6bfae13..848e19f 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -227,11 +227,6 @@
private void goToState(LauncherState state, boolean animated, long delay,
final Runnable onCompleteRunnable) {
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.ALL_APPS_UPON_RECENTS, "goToState: " +
- state.getClass().getSimpleName() +
- " @ " + Log.getStackTraceString(new Throwable()));
- }
animated &= Utilities.areAnimationsEnabled(mLauncher);
if (mLauncher.isInState(state)) {
if (mConfig.mCurrentAnimation == null) {
@@ -412,11 +407,6 @@
mState.onStateDisabled(mLauncher);
}
mState = state;
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.STABLE_STATE_MISMATCH, "onStateTransitionStart: " +
- state.getClass().getSimpleName() +
- " @ " + Log.getStackTraceString(new Throwable()));
- }
mState.onStateEnabled(mLauncher);
mLauncher.onStateSetStart(mState);
@@ -436,11 +426,6 @@
if (state != mCurrentStableState) {
mLastStableState = state.getHistoryForState(mCurrentStableState);
mCurrentStableState = state;
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.ALL_APPS_UPON_RECENTS, "onStateTransitionEnd: " +
- state.getClass().getSimpleName() +
- " @ " + Log.getStackTraceString(new Throwable()));
- }
}
state.onStateTransitionEnd(mLauncher);
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index a99c7c2..5c790f3 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1548,7 +1548,7 @@
snapToPage(getNextPage() - 1);
return true;
}
- return false;
+ return onOverscroll(-getMeasuredWidth());
}
public boolean scrollRight() {
@@ -1556,7 +1556,15 @@
snapToPage(getNextPage() + 1);
return true;
}
- return false;
+ return onOverscroll(getMeasuredWidth());
+ }
+
+ protected boolean onOverscroll(int amount) {
+ if (!mAllowOverScroll) return false;
+ onScrollInteractionBegin();
+ overScroll(amount);
+ onScrollInteractionEnd();
+ return true;
}
@Override
@@ -1576,8 +1584,9 @@
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
final boolean pagesFlipped = isPageOrderFlipped();
- info.setScrollable(getPageCount() > 1);
- if (getCurrentPage() < getPageCount() - 1) {
+ int offset = (mAllowOverScroll ? 0 : 1);
+ info.setScrollable(getPageCount() > offset);
+ if (getCurrentPage() < getPageCount() - offset) {
info.addAction(pagesFlipped ?
AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD
: AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
@@ -1585,7 +1594,7 @@
AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT
: AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT);
}
- if (getCurrentPage() > 0) {
+ if (getCurrentPage() >= offset) {
info.addAction(pagesFlipped ?
AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD
: AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
@@ -1593,7 +1602,6 @@
AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT
: AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT);
}
-
// Accessibility-wise, PagedView doesn't support long click, so disabling it.
// Besides disabling the accessibility long-click, this also prevents this view from getting
// accessibility focus.
@@ -1612,7 +1620,7 @@
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
- event.setScrollable(getPageCount() > 1);
+ event.setScrollable(mAllowOverScroll || getPageCount() > 1);
}
@Override
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index f9201d0..474c59d 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1035,6 +1035,13 @@
}
@Override
+ protected boolean onOverscroll(int amount) {
+ // Enforce overscroll on -1 direction
+ if ((amount > 0 && !mIsRtl) || (amount < 0 && mIsRtl)) return false;
+ return super.onOverscroll(amount);
+ }
+
+ @Override
protected boolean shouldFlingForVelocity(int velocityX) {
// When the overlay is moving, the fling or settle transition is controlled by the overlay.
return Float.compare(Math.abs(mOverlayTranslation), 0) == 0 &&
@@ -1461,6 +1468,9 @@
public DragView beginDragShared(View child, DragSource source, ItemInfo dragObject,
DragPreviewProvider previewProvider, DragOptions dragOptions) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_CONTEXT_MENU, "beginDragShared");
+ }
float iconScale = 1f;
if (child instanceof BubbleTextView) {
Drawable icon = ((BubbleTextView) child).getIcon();
@@ -1486,7 +1496,7 @@
Rect dragRect = null;
if (child instanceof BubbleTextView) {
dragRect = new Rect();
- ((BubbleTextView) child).getIconBounds(dragRect);
+ BubbleTextView.getIconBounds(child, dragRect, grid.iconSizePx);
dragLayerY += dragRect.top;
// Note: The dragRect is used to calculate drag layer offsets, but the
// dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
diff --git a/src/com/android/launcher3/WorkspaceItemInfo.java b/src/com/android/launcher3/WorkspaceItemInfo.java
index 1323588..23795c5 100644
--- a/src/com/android/launcher3/WorkspaceItemInfo.java
+++ b/src/com/android/launcher3/WorkspaceItemInfo.java
@@ -212,7 +212,7 @@
public ComponentName getTargetComponent() {
ComponentName cn = super.getTargetComponent();
if (cn == null && (itemType == Favorites.ITEM_TYPE_SHORTCUT
- || hasStatusFlag(FLAG_SUPPORTS_WEB_UI | FLAG_AUTOINSTALL_ICON))) {
+ || hasStatusFlag(FLAG_SUPPORTS_WEB_UI|FLAG_AUTOINSTALL_ICON|FLAG_RESTORED_ICON))) {
// Legacy shortcuts and promise icons with web UI may not have a componentName but just
// a packageName. In that case create a dummy componentName instead of adding additional
// check everywhere.
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
index 3243256..fc5d11c 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
@@ -23,19 +23,18 @@
import android.os.Bundle;
import android.os.UserHandle;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.widget.custom.CustomWidgetParser;
+import com.android.launcher3.widget.custom.CustomWidgetManager;
import java.util.HashMap;
import java.util.List;
-import androidx.annotation.Nullable;
-
public abstract class AppWidgetManagerCompat {
private static final Object sInstanceLock = new Object();
@@ -63,11 +62,9 @@
}
public LauncherAppWidgetProviderInfo getLauncherAppWidgetInfo(int appWidgetId) {
- if (FeatureFlags.ENABLE_CUSTOM_WIDGETS
- && appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) {
- return CustomWidgetParser.getWidgetProvider(mContext, appWidgetId);
+ if (appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) {
+ return CustomWidgetManager.INSTANCE.get(mContext).getWidgetProvider(appWidgetId);
}
-
AppWidgetProviderInfo info = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
return info == null ? null : LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info);
}
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
index 1065748..c8b1f67 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
@@ -24,12 +24,15 @@
import android.os.UserHandle;
import android.os.UserManager;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.widget.custom.CustomWidgetParser;
+import com.android.launcher3.widget.custom.CustomAppWidgetProviderInfo;
+import com.android.launcher3.widget.custom.CustomWidgetManager;
import java.util.ArrayList;
import java.util.Collections;
@@ -37,8 +40,6 @@
import java.util.Iterator;
import java.util.List;
-import androidx.annotation.Nullable;
-
class AppWidgetManagerCompatVL extends AppWidgetManagerCompat {
private final UserManager mUserManager;
@@ -54,14 +55,11 @@
return Collections.emptyList();
}
if (packageUser == null) {
- ArrayList<AppWidgetProviderInfo> providers = new ArrayList<AppWidgetProviderInfo>();
+ ArrayList<AppWidgetProviderInfo> providers = new ArrayList<>();
for (UserHandle user : mUserManager.getUserProfiles()) {
providers.addAll(mAppWidgetManager.getInstalledProvidersForProfile(user));
}
-
- if (FeatureFlags.ENABLE_CUSTOM_WIDGETS) {
- providers.addAll(CustomWidgetParser.getCustomWidgets(mContext));
- }
+ providers.addAll(getCustomWidgets());
return providers;
}
// Only get providers for the given package/user.
@@ -74,9 +72,9 @@
}
}
- if (FeatureFlags.ENABLE_CUSTOM_WIDGETS && Process.myUserHandle().equals(packageUser.mUser)
+ if (Process.myUserHandle().equals(packageUser.mUser)
&& mContext.getPackageName().equals(packageUser.mPackageName)) {
- providers.addAll(CustomWidgetParser.getCustomWidgets(mContext));
+ providers.addAll(getCustomWidgets());
}
return providers;
}
@@ -87,9 +85,7 @@
if (FeatureFlags.GO_DISABLE_WIDGETS) {
return false;
}
-
- if (FeatureFlags.ENABLE_CUSTOM_WIDGETS
- && appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) {
+ if (appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) {
return true;
}
return mAppWidgetManager.bindAppWidgetIdIfAllowed(
@@ -108,9 +104,8 @@
}
}
- if (FeatureFlags.ENABLE_CUSTOM_WIDGETS && Process.myUserHandle().equals(user)) {
- for (LauncherAppWidgetProviderInfo info :
- CustomWidgetParser.getCustomWidgets(mContext)) {
+ if (Process.myUserHandle().equals(user)) {
+ for (LauncherAppWidgetProviderInfo info : getCustomWidgets()) {
if (info.provider.equals(provider)) {
return info;
}
@@ -131,13 +126,13 @@
result.put(new ComponentKey(info.provider, user), info);
}
}
-
- if (FeatureFlags.ENABLE_CUSTOM_WIDGETS) {
- for (LauncherAppWidgetProviderInfo info :
- CustomWidgetParser.getCustomWidgets(mContext)) {
- result.put(new ComponentKey(info.provider, info.getProfile()), info);
- }
+ for (LauncherAppWidgetProviderInfo info : getCustomWidgets()) {
+ result.put(new ComponentKey(info.provider, info.getProfile()), info);
}
return result;
}
+
+ List<CustomAppWidgetProviderInfo> getCustomWidgets() {
+ return CustomWidgetManager.INSTANCE.get(mContext).getCustomWidgets();
+ }
}
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
index b7b0563..11ec333 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
@@ -19,14 +19,14 @@
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.PackageUserKey;
import java.util.Collections;
import java.util.List;
-import androidx.annotation.Nullable;
-
class AppWidgetManagerCompatVO extends AppWidgetManagerCompatVL {
AppWidgetManagerCompatVO(Context context) {
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index 9455889..7c8fe16 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -23,11 +23,11 @@
import androidx.annotation.GuardedBy;
import androidx.annotation.Keep;
-
import androidx.annotation.VisibleForTesting;
-import com.android.launcher3.Utilities;
+import com.android.launcher3.Utilities;
import com.android.launcher3.uioverrides.TogglableFlag;
+
import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;
@@ -74,9 +74,6 @@
//Feature flag to enable pulling down navigation shade from workspace.
public static final boolean PULL_DOWN_STATUS_BAR = true;
- // When true, custom widgets are loaded using CustomWidgetParser.
- public static final boolean ENABLE_CUSTOM_WIDGETS = false;
-
// Features to control Launcher3Go behavior
public static final boolean GO_DISABLE_WIDGETS = false;
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index b59164a..cdc7061 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -284,7 +284,8 @@
// The child may be scaled (always about the center of the view) so to account for it,
// we have to offset the position by the scaled size. Once we do that, we can center
// the drag view about the scaled child view.
- toY += Math.round(toScale * tv.getPaddingTop());
+ // padding will remain constant (does not scale with size)
+ toY += tv.getPaddingTop();
toY -= dragView.getMeasuredHeight() * (1 - toScale) / 2;
if (dragView.getDragVisualizeOffset() != null) {
toY -= Math.round(toScale * dragView.getDragVisualizeOffset().y);
diff --git a/src/com/android/launcher3/dragndrop/FlingToDeleteHelper.java b/src/com/android/launcher3/dragndrop/FlingToDeleteHelper.java
index 589ad25..06b5c40 100644
--- a/src/com/android/launcher3/dragndrop/FlingToDeleteHelper.java
+++ b/src/com/android/launcher3/dragndrop/FlingToDeleteHelper.java
@@ -106,6 +106,7 @@
* @return the vector at which the item was flung, or null if no fling was detected.
*/
private PointF isFlingingToDelete() {
+ if (mVelocityTracker == null) return null;
if (mDropTarget == null) {
mDropTarget = (ButtonDropTarget) mLauncher.findViewById(R.id.delete_target_text);
}
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index a463c7a..3840639 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -176,7 +176,7 @@
icon.setOnClickListener(ItemClickHandler.INSTANCE);
icon.mInfo = folderInfo;
icon.mLauncher = launcher;
- icon.mDotRenderer = grid.mDotRenderer;
+ icon.mDotRenderer = grid.mDotRendererWorkSpace;
icon.setContentDescription(launcher.getString(R.string.folder_name_format, folderInfo.title));
Folder folder = Folder.fromXml(launcher);
folder.setDragController(launcher.getDragController());
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index 747efe3..f579451 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -195,15 +195,22 @@
private final Bitmap mPreviewSnapshot;
private final Context mContext;
+ private final boolean mIsIcon;
OutlineGeneratorCallback(Bitmap preview) {
mPreviewSnapshot = preview;
mContext = mView.getContext();
+ mIsIcon = mView instanceof BubbleTextView;
}
@Override
public void run() {
Bitmap preview = convertPreviewToAlphaBitmap(mPreviewSnapshot);
+ if (mIsIcon) {
+ int size = Launcher.getLauncher(mContext).getDeviceProfile().iconSizePx;
+ preview = Bitmap.createScaledBitmap(preview, size, size, false);
+ }
+ //else case covers AppWidgetHost (doesn't drag/drop across different device profiles)
// We start by removing most of the alpha channel so as to ignore shadows, and
// other types of partial transparency when defining the shape of the object
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 11c7f20..9c46260 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -26,7 +26,6 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ShortcutInfo;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Process;
@@ -50,7 +49,6 @@
import com.android.launcher3.icons.cache.CachingLogic;
import com.android.launcher3.icons.cache.HandlerRunnable;
import com.android.launcher3.model.PackageItemInfo;
-import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.InstantAppResolver;
import com.android.launcher3.util.Preconditions;
@@ -65,7 +63,6 @@
private final CachingLogic<ComponentWithLabel> mComponentWithLabelCachingLogic;
private final CachingLogic<LauncherActivityInfo> mLauncherActivityInfoCachingLogic;
- private final CachingLogic<ShortcutInfo> mShortcutCachingLogic;
private final LauncherAppsCompat mLauncherApps;
private final UserManagerCompat mUserManager;
@@ -79,7 +76,6 @@
inv.fillResIconDpi, inv.iconBitmapSize, true /* inMemoryCache */);
mComponentWithLabelCachingLogic = new ComponentCachingLogic(context, false);
mLauncherActivityInfoCachingLogic = LauncherActivityCachingLogic.newInstance(context);
- mShortcutCachingLogic = new ShortcutCachingLogic();
mLauncherApps = LauncherAppsCompat.getInstance(mContext);
mUserManager = UserManagerCompat.getInstance(mContext);
mInstantAppResolver = InstantAppResolver.newInstance(mContext);
@@ -178,14 +174,6 @@
}
/**
- * Fill in info with the icon and label for deep shortcut.
- */
- public synchronized CacheEntry getDeepShortcutTitleAndIcon(ShortcutInfo info) {
- return cacheLocked(ShortcutKey.fromInfo(info).componentName, info.getUserHandle(),
- () -> info, mShortcutCachingLogic, false, false);
- }
-
- /**
* Fill in {@param info} with the icon and label. If the
* corresponding activity is not found, it reverts to the package icon.
*/
diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java
index c6949af..adc92c4 100644
--- a/src/com/android/launcher3/icons/LauncherIcons.java
+++ b/src/com/android/launcher3/icons/LauncherIcons.java
@@ -21,6 +21,7 @@
import android.content.Intent;
import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
import android.os.Process;
import androidx.annotation.Nullable;
@@ -32,8 +33,8 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.graphics.IconShape;
-import com.android.launcher3.icons.cache.BaseIconCache;
import com.android.launcher3.model.PackageItemInfo;
+import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.util.Themes;
import java.util.function.Supplier;
@@ -125,12 +126,13 @@
public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo,
boolean badged, @Nullable Supplier<ItemInfoWithIcon> fallbackIconProvider) {
+ Drawable unbadgedDrawable = DeepShortcutManager.getInstance(mContext)
+ .getShortcutIconDrawable(shortcutInfo, mFillResIconDpi);
IconCache cache = LauncherAppState.getInstance(mContext).getIconCache();
- BaseIconCache.CacheEntry entry = cache.getDeepShortcutTitleAndIcon(shortcutInfo);
final Bitmap unbadgedBitmap;
- if (entry.icon != null) {
- unbadgedBitmap = entry.icon;
+ if (unbadgedDrawable != null) {
+ unbadgedBitmap = createScaledBitmapWithoutShadow(unbadgedDrawable, 0);
} else {
if (fallbackIconProvider != null) {
// Fallback icons are already badged and with appropriate shadow
diff --git a/src/com/android/launcher3/icons/ShortcutCachingLogic.java b/src/com/android/launcher3/icons/ShortcutCachingLogic.java
deleted file mode 100644
index 5d696fd..0000000
--- a/src/com/android/launcher3/icons/ShortcutCachingLogic.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2019 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 com.android.launcher3.icons;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.ShortcutInfo;
-import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
-
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.icons.cache.CachingLogic;
-import com.android.launcher3.shortcuts.DeepShortcutManager;
-import com.android.launcher3.shortcuts.ShortcutKey;
-
-/**
- * Caching logic for shortcuts.
- */
-public class ShortcutCachingLogic implements CachingLogic<ShortcutInfo> {
-
- @Override
- public ComponentName getComponent(ShortcutInfo info) {
- return ShortcutKey.fromInfo(info).componentName;
- }
-
- @Override
- public UserHandle getUser(ShortcutInfo info) {
- return info.getUserHandle();
- }
-
- @Override
- public CharSequence getLabel(ShortcutInfo info) {
- return info.getShortLabel();
- }
-
- @Override
- public void loadIcon(Context context, ShortcutInfo info, BitmapInfo target) {
- LauncherIcons li = LauncherIcons.obtain(context);
- Drawable unbadgedDrawable = DeepShortcutManager.getInstance(context)
- .getShortcutIconDrawable(info, LauncherAppState.getIDP(context).fillResIconDpi);
- if (unbadgedDrawable != null) {
- target.icon = li.createScaledBitmapWithoutShadow(unbadgedDrawable, 0);
- }
- li.recycle();
- }
-
- @Override
- public long getLastUpdatedTime(ShortcutInfo shortcutInfo, PackageInfo info) {
- if (shortcutInfo == null) return info.lastUpdateTime;
- return Math.max(shortcutInfo.getLastChangedTimestamp(), info.lastUpdateTime);
- }
-
- @Override
- public boolean addToMemCache() {
- return false;
- }
-}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 583ebee..50e1d56 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -63,7 +63,6 @@
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.icons.LauncherActivityCachingLogic;
import com.android.launcher3.icons.LauncherIcons;
-import com.android.launcher3.icons.ShortcutCachingLogic;
import com.android.launcher3.icons.cache.IconCacheUpdateHandler;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.provider.ImportDataTask;
@@ -172,8 +171,7 @@
TraceHelper.beginSection(TAG);
try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
TraceHelper.partitionSection(TAG, "step 1.1: loading workspace");
- List<ShortcutInfo> allShortcuts = new ArrayList<>();
- loadWorkspace(allShortcuts);
+ loadWorkspace();
verifyNotStopped();
TraceHelper.partitionSection(TAG, "step 1.2: bind workspace workspace");
@@ -192,23 +190,18 @@
TraceHelper.partitionSection(TAG, "step 2.1: loading all apps");
List<LauncherActivityInfo> allActivityList = loadAllApps();
- TraceHelper.partitionSection(TAG, "step 2.2: binding all apps");
+ TraceHelper.partitionSection(TAG, "step 2.2: Binding all apps");
verifyNotStopped();
mResults.bindAllApps();
verifyNotStopped();
- TraceHelper.partitionSection(TAG, "step 2.3: save app icons in icon cache");
+ TraceHelper.partitionSection(TAG, "step 2.3: Update icon cache");
IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler();
setIgnorePackages(updateHandler);
updateHandler.updateIcons(allActivityList,
LauncherActivityCachingLogic.newInstance(mApp.getContext()),
mApp.getModel()::onPackageIconsUpdated);
- verifyNotStopped();
- TraceHelper.partitionSection(TAG, "step 2.4: save shortcuts in icon cache");
- updateHandler.updateIcons(allShortcuts, new ShortcutCachingLogic(),
- mApp.getModel()::onPackageIconsUpdated);
-
// Take a break
TraceHelper.partitionSection(TAG, "step 2 completed, wait for idle");
waitForIdle();
@@ -216,17 +209,12 @@
// third step
TraceHelper.partitionSection(TAG, "step 3.1: loading deep shortcuts");
- List<ShortcutInfo> allDeepShortcuts = loadDeepShortcuts();
+ loadDeepShortcuts();
verifyNotStopped();
TraceHelper.partitionSection(TAG, "step 3.2: bind deep shortcuts");
mResults.bindDeepShortcuts();
- verifyNotStopped();
- TraceHelper.partitionSection(TAG, "step 3.3: save deep shortcuts in icon cache");
- updateHandler.updateIcons(allDeepShortcuts,
- new ShortcutCachingLogic(), (pkgs, user) -> { });
-
// Take a break
TraceHelper.partitionSection(TAG, "step 3 completed, wait for idle");
waitForIdle();
@@ -241,6 +229,7 @@
mResults.bindWidgets();
verifyNotStopped();
+
TraceHelper.partitionSection(TAG, "step 4.3: save widgets in icon cache");
updateHandler.updateIcons(allWidgetsList, new ComponentCachingLogic(
mApp.getContext(), true), mApp.getModel()::onWidgetLabelsUpdated);
@@ -262,7 +251,7 @@
this.notify();
}
- private void loadWorkspace(List<ShortcutInfo> allDeepShortcuts) {
+ private void loadWorkspace() {
final Context context = mApp.getContext();
final ContentResolver contentResolver = context.getContentResolver();
final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
@@ -515,7 +504,6 @@
info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED;
}
intent = info.intent;
- allDeepShortcuts.add(pinnedShortcut);
} else {
// Create a shortcut info in disabled mode for now.
info = c.loadSimpleWorkspaceItem();
@@ -864,8 +852,7 @@
return allActivityList;
}
- private List<ShortcutInfo> loadDeepShortcuts() {
- List<ShortcutInfo> allShortcuts = new ArrayList<>();
+ private void loadDeepShortcuts() {
mBgDataModel.deepShortcutMap.clear();
mBgDataModel.hasShortcutHostPermission = mShortcutManager.hasHostPermission();
if (mBgDataModel.hasShortcutHostPermission) {
@@ -873,12 +860,10 @@
if (mUserManager.isUserUnlocked(user)) {
List<ShortcutInfo> shortcuts =
mShortcutManager.queryForAllShortcuts(user);
- allShortcuts.addAll(shortcuts);
mBgDataModel.updateDeepShortcutCounts(null, user, shortcuts);
}
}
}
- return allShortcuts;
}
public static boolean isValidProvider(AppWidgetProviderInfo provider) {
diff --git a/src/com/android/launcher3/model/PackageItemInfo.java b/src/com/android/launcher3/model/PackageItemInfo.java
index 741be66..3ef48cd 100644
--- a/src/com/android/launcher3/model/PackageItemInfo.java
+++ b/src/com/android/launcher3/model/PackageItemInfo.java
@@ -17,6 +17,7 @@
package com.android.launcher3.model;
import com.android.launcher3.ItemInfoWithIcon;
+import com.android.launcher3.LauncherSettings;
/**
* Represents a {@link Package} in the widget tray section.
@@ -30,10 +31,12 @@
public PackageItemInfo(String packageName) {
this.packageName = packageName;
+ this.itemType = LauncherSettings.Favorites.ITEM_TYPE_NON_ACTIONABLE;
}
public PackageItemInfo(PackageItemInfo copy) {
this.packageName = copy.packageName;
+ this.itemType = LauncherSettings.Favorites.ITEM_TYPE_NON_ACTIONABLE;
}
@Override
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 5e6c7b8..d6ebaaf 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -55,6 +55,9 @@
import java.util.HashSet;
import java.util.List;
+import static com.android.launcher3.WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON;
+import static com.android.launcher3.WorkspaceItemInfo.FLAG_RESTORED_ICON;
+
/**
* Handles updates due to changes in package manager (app installed/updated/removed)
* or when a user availability changes.
@@ -221,7 +224,7 @@
isTargetValid = LauncherAppsCompat.getInstance(context)
.isActivityEnabledForProfile(cn, mUser);
}
- if (si.hasStatusFlag(FLAG_AUTOINSTALL_ICON)) {
+ if (si.hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON)) {
if (updateWorkspaceItemIntent(context, si, packageName)) {
infoUpdated = true;
} else if (si.hasPromiseIconUi()) {
diff --git a/src/com/android/launcher3/notification/NotificationItemView.java b/src/com/android/launcher3/notification/NotificationItemView.java
index 32410a6..717a7e9 100644
--- a/src/com/android/launcher3/notification/NotificationItemView.java
+++ b/src/com/android/launcher3/notification/NotificationItemView.java
@@ -16,6 +16,8 @@
package com.android.launcher3.notification;
+import static com.android.launcher3.touch.SwipeDetector.HORIZONTAL;
+
import android.app.Notification;
import android.content.Context;
import android.graphics.Color;
@@ -33,8 +35,6 @@
import java.util.List;
-import static com.android.launcher3.touch.SwipeDetector.HORIZONTAL;
-
/**
* Utility class to manage notification UI
*/
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index c2aabca..4833c26 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -37,6 +37,7 @@
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
@@ -65,6 +66,7 @@
import com.android.launcher3.popup.PopupDataProvider.PopupDataChangeListener;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.util.PackageUserKey;
@@ -194,6 +196,9 @@
* @return the container if shown or null.
*/
public static PopupContainerWithArrow showForIcon(BubbleTextView icon) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_CONTEXT_MENU, "showForIcon");
+ }
Launcher launcher = Launcher.getLauncher(icon.getContext());
if (getOpen(launcher) != null) {
// There is already an items container open, so don't open this one.
@@ -235,6 +240,9 @@
protected void populateAndShow(
BubbleTextView icon, ItemInfo item, SystemShortcutFactory factory) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_CONTEXT_MENU, "populateAndShow");
+ }
PopupDataProvider popupDataProvider = mLauncher.getPopupDataProvider();
populateAndShow(icon,
popupDataProvider.getShortcutCountForItem(item),
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 0d1d1a6..d3ec83b 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -15,9 +15,10 @@
*/
package com.android.launcher3.testing;
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static android.graphics.Bitmap.Config.ARGB_8888;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 19c557c..62bb564 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -84,7 +84,5 @@
public static final String NO_BACKGROUND_TO_OVERVIEW_TAG = "b/138251824";
public static final String NO_DRAG_TO_WORKSPACE = "b/138729456";
public static final String APP_NOT_DISABLED = "b/139891609";
- public static final String ALL_APPS_UPON_RECENTS = "b/139941530";
- public static final String STABLE_STATE_MISMATCH = "b/140311911";
- public static final String WELLBEING_NO_TASK_MENU = "b/141275518";
+ public static final String NO_CONTEXT_MENU = "b/141770616";
}
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index 6cd2b2d..86d2b39 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -22,6 +22,7 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
+import android.util.Log;
import android.view.View;
import android.view.View.OnLongClickListener;
@@ -33,6 +34,9 @@
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.folder.Folder;
+import com.android.launcher3.testing.TestProtocol;
+
+import java.util.Arrays;
/**
* Class to handle long-clicks on workspace items and start drag as a result.
@@ -75,10 +79,19 @@
}
private static boolean onAllAppsItemLongClick(View v) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_CONTEXT_MENU, "onAllAppsItemLongClick1");
+ }
Launcher launcher = Launcher.getLauncher(v.getContext());
if (!canStartDrag(launcher)) return false;
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_CONTEXT_MENU, "onAllAppsItemLongClick2");
+ }
// When we have exited all apps or are in transition, disregard long clicks
if (!launcher.isInState(ALL_APPS) && !launcher.isInState(OVERVIEW)) return false;
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_CONTEXT_MENU, "onAllAppsItemLongClick3");
+ }
if (launcher.getWorkspace().isSwitchingState()) return false;
// Start the drag
diff --git a/src/com/android/launcher3/touch/SwipeDetector.java b/src/com/android/launcher3/touch/SwipeDetector.java
index 3777a41..d0edfd8 100644
--- a/src/com/android/launcher3/touch/SwipeDetector.java
+++ b/src/com/android/launcher3/touch/SwipeDetector.java
@@ -24,12 +24,11 @@
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.testing.TestProtocol;
-
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.Utilities;
+
/**
* One dimensional scroll/drag/swipe gesture detector.
*
@@ -41,47 +40,14 @@
private static final boolean DBG = false;
private static final String TAG = "SwipeDetector";
+ private static final float ANIMATION_DURATION = 1200;
+ /** The minimum release velocity in pixels per millisecond that triggers fling.*/
+ private static final float RELEASE_VELOCITY_PX_MS = 1.0f;
- private int mScrollConditions;
public static final int DIRECTION_POSITIVE = 1 << 0;
public static final int DIRECTION_NEGATIVE = 1 << 1;
public static final int DIRECTION_BOTH = DIRECTION_NEGATIVE | DIRECTION_POSITIVE;
- private static final float ANIMATION_DURATION = 1200;
-
- protected int mActivePointerId = INVALID_POINTER_ID;
-
- /**
- * The minimum release velocity in pixels per millisecond that triggers fling..
- */
- public static final float RELEASE_VELOCITY_PX_MS = 1.0f;
-
- /* Scroll state, this is set to true during dragging and animation. */
- private ScrollState mState = ScrollState.IDLE;
-
- enum ScrollState {
- IDLE,
- DRAGGING, // onDragStart, onDrag
- SETTLING // onDragEnd
- }
-
- public static abstract class Direction {
-
- abstract float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint,
- boolean isRtl);
-
- /**
- * Distance in pixels a touch can wander before we think the user is scrolling.
- */
- abstract float getActiveTouchSlop(MotionEvent ev, int pointerIndex, PointF downPos);
-
- abstract float getVelocity(VelocityTracker tracker, boolean isRtl);
-
- abstract boolean isPositive(float displacement);
-
- abstract boolean isNegative(float displacement);
- }
-
public static final Direction VERTICAL = new Direction() {
@Override
@@ -150,35 +116,54 @@
}
};
- //------------------- ScrollState transition diagram -----------------------------------
- //
- // IDLE -> (mDisplacement > mTouchSlop) -> DRAGGING
- // DRAGGING -> (MotionEvent#ACTION_UP, MotionEvent#ACTION_CANCEL) -> SETTLING
- // SETTLING -> (MotionEvent#ACTION_DOWN) -> DRAGGING
- // SETTLING -> (View settled) -> IDLE
+ private final PointF mDownPos = new PointF();
+ private final PointF mLastPos = new PointF();
+ private final Direction mDir;
+ private final boolean mIsRtl;
+ private final float mTouchSlop;
+ private final float mMaxVelocity;
+ /* Client of this gesture detector can register a callback. */
+ private final Listener mListener;
- private void setState(ScrollState newState) {
- if (DBG) {
- Log.d(TAG, "setState:" + mState + "->" + newState);
- }
- // onDragStart and onDragEnd is reported ONLY on state transition
- if (newState == ScrollState.DRAGGING) {
- initializeDragging();
- if (mState == ScrollState.IDLE) {
- reportDragStart(false /* recatch */);
- } else if (mState == ScrollState.SETTLING) {
- reportDragStart(true /* recatch */);
- }
- }
- if (newState == ScrollState.SETTLING) {
- reportDragEnd();
- }
+ private int mActivePointerId = INVALID_POINTER_ID;
+ private VelocityTracker mVelocityTracker;
+ private float mLastDisplacement;
+ private float mDisplacement;
+ private float mSubtractDisplacement;
+ private boolean mIgnoreSlopWhenSettling;
+ private int mScrollDirections;
+ private ScrollState mState = ScrollState.IDLE;
- mState = newState;
+ private enum ScrollState {
+ IDLE,
+ DRAGGING, // onDragStart, onDrag
+ SETTLING // onDragEnd
}
- public boolean isDraggingOrSettling() {
- return mState == ScrollState.DRAGGING || mState == ScrollState.SETTLING;
+ public SwipeDetector(@NonNull Context context, @NonNull Listener l, @NonNull Direction dir) {
+ this(ViewConfiguration.get(context), l, dir, Utilities.isRtl(context.getResources()));
+ }
+
+ @VisibleForTesting
+ protected SwipeDetector(@NonNull ViewConfiguration config, @NonNull Listener l,
+ @NonNull Direction dir, boolean isRtl) {
+ mListener = l;
+ mDir = dir;
+ mIsRtl = isRtl;
+ mTouchSlop = config.getScaledTouchSlop();
+ mMaxVelocity = config.getScaledMaximumFlingVelocity();
+ }
+
+ public static long calculateDuration(float velocity, float progressNeeded) {
+ // TODO: make these values constants after tuning.
+ float velocityDivisor = Math.max(2f, Math.abs(0.5f * velocity));
+ float travelDistance = Math.max(0.2f, progressNeeded);
+ long duration = (long) Math.max(100, ANIMATION_DURATION / velocityDivisor * travelDistance);
+ if (DBG) {
+ Log.d(TAG, String.format(
+ "calculateDuration=%d, v=%f, d=%f", duration, velocity, progressNeeded));
+ }
+ return duration;
}
public int getDownX() {
@@ -203,73 +188,31 @@
return mState == ScrollState.DRAGGING;
}
- private final PointF mDownPos = new PointF();
- private final PointF mLastPos = new PointF();
- private final Direction mDir;
- private final boolean mIsRtl;
-
- private final float mTouchSlop;
- private final float mMaxVelocity;
-
- /* Client of this gesture detector can register a callback. */
- private final Listener mListener;
-
- private VelocityTracker mVelocityTracker;
-
- private float mLastDisplacement;
- private float mDisplacement;
-
- private float mSubtractDisplacement;
- private boolean mIgnoreSlopWhenSettling;
-
- public interface Listener {
- void onDragStart(boolean start);
-
- boolean onDrag(float displacement);
-
- default boolean onDrag(float displacement, MotionEvent event) {
- return onDrag(displacement);
- }
-
- void onDragEnd(float velocity, boolean fling);
- }
-
- public SwipeDetector(@NonNull Context context, @NonNull Listener l, @NonNull Direction dir) {
- this(ViewConfiguration.get(context), l, dir, Utilities.isRtl(context.getResources()));
- }
-
- @VisibleForTesting
- protected SwipeDetector(@NonNull ViewConfiguration config, @NonNull Listener l,
- @NonNull Direction dir, boolean isRtl) {
- mListener = l;
- mDir = dir;
- mIsRtl = isRtl;
- mTouchSlop = config.getScaledTouchSlop();
- mMaxVelocity = config.getScaledMaximumFlingVelocity();
+ public boolean isDraggingOrSettling() {
+ return mState == ScrollState.DRAGGING || mState == ScrollState.SETTLING;
}
public void setDetectableScrollConditions(int scrollDirectionFlags, boolean ignoreSlop) {
- mScrollConditions = scrollDirectionFlags;
+ mScrollDirections = scrollDirectionFlags;
mIgnoreSlopWhenSettling = ignoreSlop;
}
public int getScrollDirections() {
- return mScrollConditions;
+ return mScrollDirections;
}
- private boolean shouldScrollStart(MotionEvent ev, int pointerIndex) {
- // reject cases where the angle or slop condition is not met.
- if (Math.max(mDir.getActiveTouchSlop(ev, pointerIndex, mDownPos), mTouchSlop)
- > Math.abs(mDisplacement)) {
- return false;
- }
+ public void finishedScrolling() {
+ setState(ScrollState.IDLE);
+ }
- // Check if the client is interested in scroll in current direction.
- if (((mScrollConditions & DIRECTION_NEGATIVE) > 0 && mDir.isNegative(mDisplacement)) ||
- ((mScrollConditions & DIRECTION_POSITIVE) > 0 && mDir.isPositive(mDisplacement))) {
- return true;
- }
- return false;
+ /**
+ * Returns if the start drag was towards the positive direction or negative.
+ *
+ * @see #setDetectableScrollConditions(int, boolean)
+ * @see #DIRECTION_BOTH
+ */
+ public boolean wasInitialTouchPositive() {
+ return mDir.isPositive(mSubtractDisplacement);
}
public boolean onTouchEvent(MotionEvent ev) {
@@ -338,16 +281,50 @@
return true;
}
- public void finishedScrolling() {
- setState(ScrollState.IDLE);
+ //------------------- ScrollState transition diagram -----------------------------------
+ //
+ // IDLE -> (mDisplacement > mTouchSlop) -> DRAGGING
+ // DRAGGING -> (MotionEvent#ACTION_UP, MotionEvent#ACTION_CANCEL) -> SETTLING
+ // SETTLING -> (MotionEvent#ACTION_DOWN) -> DRAGGING
+ // SETTLING -> (View settled) -> IDLE
+
+ private void setState(ScrollState newState) {
+ if (DBG) {
+ Log.d(TAG, "setState:" + mState + "->" + newState);
+ }
+ // onDragStart and onDragEnd is reported ONLY on state transition
+ if (newState == ScrollState.DRAGGING) {
+ initializeDragging();
+ if (mState == ScrollState.IDLE) {
+ reportDragStart(false /* recatch */);
+ } else if (mState == ScrollState.SETTLING) {
+ reportDragStart(true /* recatch */);
+ }
+ }
+ if (newState == ScrollState.SETTLING) {
+ reportDragEnd();
+ }
+
+ mState = newState;
}
- private boolean reportDragStart(boolean recatch) {
+ private boolean shouldScrollStart(MotionEvent ev, int pointerIndex) {
+ // reject cases where the angle or slop condition is not met.
+ if (Math.max(mDir.getActiveTouchSlop(ev, pointerIndex, mDownPos), mTouchSlop)
+ > Math.abs(mDisplacement)) {
+ return false;
+ }
+
+ // Check if the client is interested in scroll in current direction.
+ return ((mScrollDirections & DIRECTION_NEGATIVE) > 0 && mDir.isNegative(mDisplacement))
+ || ((mScrollDirections & DIRECTION_POSITIVE) > 0 && mDir.isPositive(mDisplacement));
+ }
+
+ private void reportDragStart(boolean recatch) {
mListener.onDragStart(!recatch);
if (DBG) {
Log.d(TAG, "onDragStart recatch:" + recatch);
}
- return true;
}
private void initializeDragging() {
@@ -361,26 +338,15 @@
}
}
- /**
- * Returns if the start drag was towards the positive direction or negative.
- *
- * @see #setDetectableScrollConditions(int, boolean)
- * @see #DIRECTION_BOTH
- */
- public boolean wasInitialTouchPositive() {
- return mDir.isPositive(mSubtractDisplacement);
- }
-
- private boolean reportDragging(MotionEvent event) {
+ private void reportDragging(MotionEvent event) {
if (mDisplacement != mLastDisplacement) {
if (DBG) {
Log.d(TAG, String.format("onDrag disp=%.1f", mDisplacement));
}
mLastDisplacement = mDisplacement;
- return mListener.onDrag(mDisplacement - mSubtractDisplacement, event);
+ mListener.onDrag(mDisplacement - mSubtractDisplacement, event);
}
- return true;
}
private void reportDragEnd() {
@@ -394,14 +360,33 @@
mListener.onDragEnd(velocity, Math.abs(velocity) > RELEASE_VELOCITY_PX_MS);
}
- public static long calculateDuration(float velocity, float progressNeeded) {
- // TODO: make these values constants after tuning.
- float velocityDivisor = Math.max(2f, Math.abs(0.5f * velocity));
- float travelDistance = Math.max(0.2f, progressNeeded);
- long duration = (long) Math.max(100, ANIMATION_DURATION / velocityDivisor * travelDistance);
- if (DBG) {
- Log.d(TAG, String.format("calculateDuration=%d, v=%f, d=%f", duration, velocity, progressNeeded));
+ /** Listener to receive updates on the swipe. */
+ public interface Listener {
+ void onDragStart(boolean start);
+
+ boolean onDrag(float displacement);
+
+ default boolean onDrag(float displacement, MotionEvent event) {
+ return onDrag(displacement);
}
- return duration;
+
+ void onDragEnd(float velocity, boolean fling);
+ }
+
+ public abstract static class Direction {
+
+ abstract float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint,
+ boolean isRtl);
+
+ /**
+ * Distance in pixels a touch can wander before we think the user is scrolling.
+ */
+ abstract float getActiveTouchSlop(MotionEvent ev, int pointerIndex, PointF downPos);
+
+ abstract float getVelocity(VelocityTracker tracker, boolean isRtl);
+
+ abstract boolean isPositive(float displacement);
+
+ abstract boolean isNegative(float displacement);
}
}
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index da1df3f..9f59d78 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -288,6 +288,7 @@
anim.addUpdateListener((v) -> invalidate(invalidateRegion));
getOverlay().add(drawable);
anim.start();
+ return true;
}
return value;
}
diff --git a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
new file mode 100644
index 0000000..f20c83d
--- /dev/null
+++ b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2019 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 com.android.launcher3.widget.custom;
+
+import static com.android.launcher3.LauncherAppWidgetProviderInfo.CLS_CUSTOM_WIDGET_PREFIX;
+
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Process;
+import android.util.SparseArray;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.systemui.plugins.CustomWidgetPlugin;
+import com.android.systemui.plugins.PluginListener;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * CustomWidgetManager handles custom widgets implemented as a plugin.
+ */
+public class CustomWidgetManager implements PluginListener<CustomWidgetPlugin> {
+
+ public static final MainThreadInitializedObject<CustomWidgetManager> INSTANCE =
+ new MainThreadInitializedObject<>(CustomWidgetManager::new);
+
+ /**
+ * auto provider Id is an ever-increasing number that serves as the providerId whenever a new
+ * custom widget has been connected.
+ */
+ private int mAutoProviderId = 0;
+ private final SparseArray<CustomWidgetPlugin> mPlugins;
+ private final SparseArray<WeakReference<Context>> mContexts;
+ private final List<CustomAppWidgetProviderInfo> mCustomWidgets;
+ private final SparseArray<ComponentName> mWidgetsIdMap;
+ private Consumer<PackageUserKey> mWidgetRefreshCallback;
+
+ private CustomWidgetManager(Context context) {
+ mPlugins = new SparseArray<>();
+ mContexts = new SparseArray<>();
+ mCustomWidgets = new ArrayList<>();
+ mWidgetsIdMap = new SparseArray<>();
+ PluginManagerWrapper.INSTANCE.get(context)
+ .addPluginListener(this, CustomWidgetPlugin.class, true);
+ }
+
+ @Override
+ public void onPluginConnected(CustomWidgetPlugin plugin, Context context) {
+ mPlugins.put(mAutoProviderId, plugin);
+ mContexts.put(mAutoProviderId, new WeakReference<>(context));
+ List<AppWidgetProviderInfo> providers = AppWidgetManager.getInstance(context)
+ .getInstalledProvidersForProfile(Process.myUserHandle());
+ if (providers.isEmpty()) return;
+ Parcel parcel = Parcel.obtain();
+ providers.get(0).writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ CustomAppWidgetProviderInfo info = newInfo(mAutoProviderId, plugin, parcel, context);
+ parcel.recycle();
+ mCustomWidgets.add(info);
+ mWidgetsIdMap.put(mAutoProviderId, info.provider);
+ mWidgetRefreshCallback.accept(null);
+ mAutoProviderId++;
+ }
+
+ @Override
+ public void onPluginDisconnected(CustomWidgetPlugin plugin) {
+ int providerId = findProviderId(plugin);
+ if (providerId == -1) return;
+ mPlugins.remove(providerId);
+ mContexts.remove(providerId);
+ mCustomWidgets.remove(getWidgetProvider(providerId));
+ mWidgetsIdMap.remove(providerId);
+ }
+
+ /**
+ * Inject a callback function to refresh the widgets.
+ */
+ public void setWidgetRefreshCallback(Consumer<PackageUserKey> cb) {
+ mWidgetRefreshCallback = cb;
+ }
+
+ /**
+ * Callback method to inform a plugin it's corresponding widget has been created.
+ */
+ public void onViewCreated(LauncherAppWidgetHostView view) {
+ CustomAppWidgetProviderInfo info = (CustomAppWidgetProviderInfo) view.getAppWidgetInfo();
+ CustomWidgetPlugin plugin = mPlugins.get(info.providerId);
+ WeakReference<Context> context = mContexts.get(info.providerId);
+ if (plugin == null) return;
+ plugin.onViewCreated(context == null ? null : context.get(), view);
+ }
+
+ /**
+ * Returns the list of custom widgets.
+ */
+ @NonNull
+ public List<CustomAppWidgetProviderInfo> getCustomWidgets() {
+ return mCustomWidgets;
+ }
+
+ /**
+ * Returns the widget id for a specific provider.
+ */
+ public int getWidgetIdForCustomProvider(@NonNull ComponentName provider) {
+ int index = mWidgetsIdMap.indexOfValue(provider);
+ if (index >= 0) {
+ return LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - mWidgetsIdMap.keyAt(index);
+ } else {
+ return AppWidgetManager.INVALID_APPWIDGET_ID;
+ }
+ }
+
+ /**
+ * Returns the widget provider in respect to given widget id.
+ */
+ @Nullable
+ public LauncherAppWidgetProviderInfo getWidgetProvider(int widgetId) {
+ ComponentName cn = mWidgetsIdMap.get(LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - widgetId);
+ for (LauncherAppWidgetProviderInfo info : mCustomWidgets) {
+ if (info.provider.equals(cn)) return info;
+ }
+ return null;
+ }
+
+ private static CustomAppWidgetProviderInfo newInfo(int providerId, CustomWidgetPlugin plugin,
+ Parcel parcel, Context context) {
+ CustomAppWidgetProviderInfo info = new CustomAppWidgetProviderInfo(
+ parcel, false, providerId);
+ info.provider = new ComponentName(
+ context.getPackageName(), CLS_CUSTOM_WIDGET_PREFIX + providerId);
+
+ info.label = plugin.getLabel(context);
+ info.resizeMode = plugin.getResizeMode(context);
+
+ info.spanX = plugin.getSpanX(context);
+ info.spanY = plugin.getSpanY(context);
+ info.minSpanX = plugin.getMinSpanX(context);
+ info.minSpanY = plugin.getMinSpanY(context);
+ return info;
+ }
+
+ private int findProviderId(CustomWidgetPlugin plugin) {
+ for (int i = 0; i < mPlugins.size(); i++) {
+ int providerId = mPlugins.keyAt(i);
+ if (mPlugins.get(providerId) == plugin) {
+ return providerId;
+ }
+ }
+ return -1;
+ }
+}
diff --git a/src/com/android/launcher3/widget/custom/CustomWidgetParser.java b/src/com/android/launcher3/widget/custom/CustomWidgetParser.java
deleted file mode 100644
index 00720c4..0000000
--- a/src/com/android/launcher3/widget/custom/CustomWidgetParser.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * 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 com.android.launcher3.widget.custom;
-
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.os.Parcel;
-import android.os.Process;
-import android.util.SparseArray;
-import android.util.Xml;
-
-import com.android.launcher3.LauncherAppWidgetInfo;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.R;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import static com.android.launcher3.LauncherAppWidgetProviderInfo.CLS_CUSTOM_WIDGET_PREFIX;
-
-/**
- * Utility class to parse {@ink CustomAppWidgetProviderInfo} definitions from xml
- */
-public class CustomWidgetParser {
-
- private static List<LauncherAppWidgetProviderInfo> sCustomWidgets;
- private static SparseArray<ComponentName> sWidgetsIdMap;
-
- public static List<LauncherAppWidgetProviderInfo> getCustomWidgets(Context context) {
- if (sCustomWidgets == null) {
- // Synchronization not needed as it it safe to load multiple times
- parseCustomWidgets(context);
- }
-
- return sCustomWidgets;
- }
-
- public static int getWidgetIdForCustomProvider(Context context, ComponentName provider) {
- if (sWidgetsIdMap == null) {
- parseCustomWidgets(context);
- }
- int index = sWidgetsIdMap.indexOfValue(provider);
- if (index >= 0) {
- return LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - sWidgetsIdMap.keyAt(index);
- } else {
- return AppWidgetManager.INVALID_APPWIDGET_ID;
- }
- }
-
- public static LauncherAppWidgetProviderInfo getWidgetProvider(Context context, int widgetId) {
- if (sWidgetsIdMap == null || sCustomWidgets == null) {
- parseCustomWidgets(context);
- }
- ComponentName cn = sWidgetsIdMap.get(LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - widgetId);
- for (LauncherAppWidgetProviderInfo info : sCustomWidgets) {
- if (info.provider.equals(cn)) {
- return info;
- }
- }
- return null;
- }
-
- private static void parseCustomWidgets(Context context) {
- ArrayList<LauncherAppWidgetProviderInfo> widgets = new ArrayList<>();
- SparseArray<ComponentName> idMap = new SparseArray<>();
-
- List<AppWidgetProviderInfo> providers = AppWidgetManager.getInstance(context)
- .getInstalledProvidersForProfile(Process.myUserHandle());
- if (providers.isEmpty()) {
- sCustomWidgets = widgets;
- sWidgetsIdMap = idMap;
- return;
- }
-
- Parcel parcel = Parcel.obtain();
- providers.get(0).writeToParcel(parcel, 0);
-
- try (XmlResourceParser parser = context.getResources().getXml(R.xml.custom_widgets)) {
- final int depth = parser.getDepth();
- int type;
-
- while (((type = parser.next()) != XmlPullParser.END_TAG ||
- parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
- if ((type == XmlPullParser.START_TAG) && "widget".equals(parser.getName())) {
- TypedArray a = context.obtainStyledAttributes(
- Xml.asAttributeSet(parser), R.styleable.CustomAppWidgetProviderInfo);
-
- parcel.setDataPosition(0);
- CustomAppWidgetProviderInfo info = newInfo(a, parcel, context);
- widgets.add(info);
- a.recycle();
-
- idMap.put(info.providerId, info.provider);
- }
- }
- } catch (IOException | XmlPullParserException e) {
- throw new RuntimeException(e);
- }
- parcel.recycle();
- sCustomWidgets = widgets;
- sWidgetsIdMap = idMap;
- }
-
- private static CustomAppWidgetProviderInfo newInfo(TypedArray a, Parcel parcel, Context context) {
- int providerId = a.getInt(R.styleable.CustomAppWidgetProviderInfo_providerId, 0);
- CustomAppWidgetProviderInfo info = new CustomAppWidgetProviderInfo(parcel, false, providerId);
- info.provider = new ComponentName(context.getPackageName(), CLS_CUSTOM_WIDGET_PREFIX + providerId);
-
- info.label = a.getString(R.styleable.CustomAppWidgetProviderInfo_android_label);
- info.initialLayout = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_initialLayout, 0);
- info.icon = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_icon, 0);
- info.previewImage = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_previewImage, 0);
- info.resizeMode = a.getInt(R.styleable.CustomAppWidgetProviderInfo_android_resizeMode, 0);
-
- info.spanX = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numColumns, 1);
- info.spanY = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numRows, 1);
- info.minSpanX = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numMinColumns, 1);
- info.minSpanY = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numMinRows, 1);
- return info;
- }
-}
diff --git a/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java b/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java
new file mode 100644
index 0000000..47aa94b
--- /dev/null
+++ b/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 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 com.android.systemui.plugins;
+
+import android.appwidget.AppWidgetHostView;
+import android.content.Context;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/**
+ * Implement this plugin interface to add a custom widget.
+ */
+@ProvidesInterface(action = CustomWidgetPlugin.ACTION, version = CustomWidgetPlugin.VERSION)
+public interface CustomWidgetPlugin extends Plugin {
+
+ String ACTION = "com.android.systemui.action.PLUGIN_CUSTOM_WIDGET";
+ int VERSION = 1;
+
+ /**
+ * The label to display to the user in the AppWidget picker.
+ */
+ String getLabel(Context context);
+
+ /**
+ * The default width of the widget when added to a host, in dp. The widget will get
+ * at least this width, and will often be given more, depending on the host.
+ */
+ int getSpanX(Context context);
+
+ /**
+ * The default height of the widget when added to a host, in dp. The widget will get
+ * at least this height, and will often be given more, depending on the host.
+ */
+ int getSpanY(Context context);
+
+ /**
+ * Minimum width (in dp) which the widget can be resized to. This field has no effect if it
+ * is greater than minWidth or if horizontal resizing isn't enabled.
+ */
+ int getMinSpanX(Context context);
+
+ /**
+ * Minimum height (in dp) which the widget can be resized to. This field has no effect if it
+ * is greater than minHeight or if vertical resizing isn't enabled.
+ */
+ int getMinSpanY(Context context);
+
+ /**
+ * The rules by which a widget can be resized.
+ */
+ int getResizeMode(Context context);
+
+ /**
+ * Notify the plugin that container of the widget has been rendered, where the custom widget
+ * can be attached to.
+ */
+ void onViewCreated(Context context, AppWidgetHostView parent);
+}
diff --git a/src_plugins/com/android/systemui/plugins/OverviewScreenshotActions.java b/src_plugins/com/android/systemui/plugins/OverviewScreenshotActions.java
new file mode 100644
index 0000000..8d9c0f4
--- /dev/null
+++ b/src_plugins/com/android/systemui/plugins/OverviewScreenshotActions.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 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 com.android.systemui.plugins;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.view.ViewGroup;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/**
+ * Implement this interface to add action buttons for overview screenshots, e.g. share, edit etc.
+ */
+@ProvidesInterface(
+ action = OverviewScreenshotActions.ACTION, version = OverviewScreenshotActions.VERSION)
+public interface OverviewScreenshotActions extends Plugin {
+ String ACTION = "com.android.systemui.action.PLUGIN_OVERVIEW_SCREENSHOT_ACTIONS";
+ int VERSION = 1;
+
+ /**
+ * Setup the actions for the screenshot, including edit, save, etc.
+ * @param parent The parent view to add buttons on.
+ * @param screenshot The screenshot we will do actions on.
+ * @param activity THe host activity.
+ */
+ void setupActions(ViewGroup parent, Bitmap screenshot, Activity activity);
+}
diff --git a/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java b/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java
index 6a6916e..4246096 100644
--- a/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java
+++ b/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java
@@ -104,7 +104,8 @@
case GET_SYSTEM_HEALTH_MESSAGE: {
final Bundle response = new Bundle();
- response.putString("result", TestHelpers.getSystemHealthMessage(getContext()));
+ response.putString("result",
+ TestHelpers.getSystemHealthMessage(getContext(), Long.parseLong(arg)));
return response;
}
}
diff --git a/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java b/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java
index e042357..f209fae 100644
--- a/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java
+++ b/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java
@@ -25,6 +25,10 @@
import android.util.Log;
import android.view.ViewConfiguration;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.launcher3.testcomponent.TouchEventGenerator;
import org.junit.Before;
@@ -33,10 +37,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SwipeDetectorTest {
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 17a5f50..0f50009 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -93,8 +93,7 @@
protected LooperExecutor mMainThreadExecutor = MAIN_EXECUTOR;
protected final UiDevice mDevice = UiDevice.getInstance(getInstrumentation());
- protected final LauncherInstrumentation mLauncher =
- new LauncherInstrumentation(getInstrumentation());
+ protected final LauncherInstrumentation mLauncher = new LauncherInstrumentation();
protected Context mTargetContext;
protected String mTargetPackage;
@@ -106,8 +105,9 @@
}
if (TestHelpers.isInLauncherProcess()) {
Utilities.enableRunningInTestHarnessForTests();
- mLauncher.setSystemHealthSupplier(() -> TestCommandReceiver.callCommand(
- TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE).getString("result"));
+ mLauncher.setSystemHealthSupplier(startTime -> TestCommandReceiver.callCommand(
+ TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE, startTime.toString()).
+ getString("result"));
mLauncher.setOnSettledStateAction(
containerType -> executeOnLauncher(
launcher ->
@@ -172,8 +172,6 @@
mTargetContext = InstrumentationRegistry.getTargetContext();
mTargetPackage = mTargetContext.getPackageName();
- // Unlock the phone
- mDevice.executeShellCommand("input keyevent 82");
}
@After
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
index 3f35a3a..e1b3ede 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -41,7 +41,6 @@
import com.android.launcher3.util.rule.ShellCommandRule;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -53,7 +52,8 @@
@RunWith(AndroidJUnit4.class)
public class AddConfigWidgetTest extends AbstractLauncherUiTest {
- @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
+ @Rule
+ public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
private LauncherAppWidgetProviderInfo mWidgetInfo;
private AppWidgetManager mAppWidgetManager;
@@ -70,14 +70,12 @@
@Test
@PortraitLandscape
- @org.junit.Ignore
public void testWidgetConfig() throws Throwable {
runTest(true);
}
@Test
@PortraitLandscape
- @org.junit.Ignore
public void testConfigCancelled() throws Throwable {
runTest(false);
}
diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
index 1edce22..b8ca5de 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
@@ -30,7 +30,6 @@
import com.android.launcher3.ui.TestViewHelpers;
import com.android.launcher3.util.rule.ShellCommandRule;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -42,11 +41,11 @@
@RunWith(AndroidJUnit4.class)
public class AddWidgetTest extends AbstractLauncherUiTest {
- @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
+ @Rule
+ public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
@Test
@PortraitLandscape
- @org.junit.Ignore
public void testDragIcon() throws Throwable {
clearHomescreen();
mDevice.pressHome();
diff --git a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
index 8391ae7..d7f41bf 100644
--- a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
+++ b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
@@ -37,11 +37,11 @@
private static final String TAG = "TestStabilityRule";
private static final Pattern LAUNCHER_BUILD =
Pattern.compile("^("
- + "(?<androidStudio>BuildFromAndroidStudio)|"
- + "(?<commandLine>[0-9]+-eng\\.[a-z]+\\.[0-9]+\\.[0-9]+)|"
- + "(?<presubmit>[0-9]+-P[0-9]+)|"
- + "(?<postsubmit>[0-9]+-[0-9]+|"
- + "(?<platform>[0-9]+))"
+ + "(?<local>(BuildFromAndroidStudio|"
+ + "([0-9]+|[A-Z])-eng\\.[a-z]+\\.[0-9]+\\.[0-9]+))|"
+ + "(?<presubmit>([0-9]+|[A-Z])-P[0-9]+)|"
+ + "(?<postsubmit>([0-9]+|[A-Z])-[0-9]+)|"
+ + "(?<platform>[0-9]+|[A-Z])"
+ ")$");
private static final Pattern PLATFORM_BUILD =
Pattern.compile("^("
@@ -61,71 +61,7 @@
return new Statement() {
@Override
public void evaluate() throws Throwable {
- final String launcherVersion =
- getInstrumentation().
- getContext().
- getPackageManager().
- getPackageInfo(
- UiDevice.getInstance(getInstrumentation()).
- getLauncherPackageName(),
- 0).
- versionName;
-
- final Matcher launcherBuildMatcher = LAUNCHER_BUILD.matcher(launcherVersion);
-
- boolean launcherLocalBuild = false;
- boolean launcherUnbundledPresubmit = false;
- boolean launcherUnbundledPostsubmit = false;
- boolean launcherPlatform = false;
-
- if (!launcherBuildMatcher.find()) {
- Log.e(TAG, "Match not found");
- } else if (launcherBuildMatcher.group("androidStudio") != null
- || launcherBuildMatcher.group("commandLine") != null) {
- launcherLocalBuild = true;
- } else if (launcherBuildMatcher.group("presubmit") != null) {
- launcherUnbundledPresubmit = true;
- } else if (launcherBuildMatcher.group("postsubmit") != null) {
- launcherUnbundledPostsubmit = true;
- } else if (launcherBuildMatcher.group("platform") != null) {
- launcherPlatform = true;
- } else {
- Log.e(TAG, "ERROR1");
- }
-
- boolean platformLocalBuild = false;
- boolean platformPresubmit = false;
- boolean platformPostsubmit = false;
-
- final String platformVersion = Build.VERSION.INCREMENTAL;
- final Matcher platformBuildMatcher = PLATFORM_BUILD.matcher(platformVersion);
- if (!platformBuildMatcher.find()) {
- Log.e(TAG, "Match not found");
- } else if (platformBuildMatcher.group("commandLine") != null) {
- platformLocalBuild = true;
- } else if (platformBuildMatcher.group("presubmit") != null) {
- platformPresubmit = true;
- } else if (platformBuildMatcher.group("postsubmit") != null) {
- platformPostsubmit = true;
- } else {
- Log.e(TAG, "ERROR2");
- }
-
- Log.d(TAG, "Launcher: " + launcherVersion + ", platform: " + platformVersion);
-
- if (launcherLocalBuild && (platformLocalBuild || platformPostsubmit)) {
- Log.d(TAG, "LOCAL RUN");
- } else if (launcherUnbundledPresubmit && platformPostsubmit) {
- Log.d(TAG, "UNBUNDLED PRESUBMIT");
- } else if (launcherUnbundledPostsubmit && platformPostsubmit) {
- Log.d(TAG, "UNBUNDLED POSTSUBMIT");
- } else if (launcherPlatform && platformPresubmit) {
- Log.d(TAG, "PLATFORM PRESUBMIT");
- } else if (launcherPlatform && platformPostsubmit) {
- Log.d(TAG, "PLATFORM POSTSUBMIT");
- } else {
- Log.e(TAG, "ERROR3");
- }
+ getRunFlavor();
base.evaluate();
}
@@ -134,4 +70,50 @@
return base;
}
}
+
+ private static void getRunFlavor() throws Exception {
+ final String launcherVersion = getInstrumentation().
+ getContext().
+ getPackageManager().
+ getPackageInfo(
+ UiDevice.getInstance(getInstrumentation()).
+ getLauncherPackageName(),
+ 0).
+ versionName;
+
+ final Matcher launcherBuildMatcher = LAUNCHER_BUILD.matcher(launcherVersion);
+
+ if (!launcherBuildMatcher.find()) {
+ Log.e(TAG, "Match not found");
+ }
+
+ final String platformVersion = Build.VERSION.INCREMENTAL;
+ final Matcher platformBuildMatcher = PLATFORM_BUILD.matcher(platformVersion);
+
+ if (!platformBuildMatcher.find()) {
+ Log.e(TAG, "Match not found");
+ }
+
+ Log.d(TAG, "Launcher: " + launcherVersion + ", platform: " + platformVersion);
+
+ if (launcherBuildMatcher.group("local") != null && (
+ platformBuildMatcher.group("commandLine") != null ||
+ platformBuildMatcher.group("postsubmit") != null)) {
+ Log.d(TAG, "LOCAL RUN");
+ } else if (launcherBuildMatcher.group("presubmit") != null
+ && platformBuildMatcher.group("postsubmit") != null) {
+ Log.d(TAG, "UNBUNDLED PRESUBMIT");
+ } else if (launcherBuildMatcher.group("postsubmit") != null
+ && platformBuildMatcher.group("postsubmit") != null) {
+ Log.d(TAG, "UNBUNDLED POSTSUBMIT");
+ } else if (launcherBuildMatcher.group("platform") != null
+ && platformBuildMatcher.group("presubmit") != null) {
+ Log.d(TAG, "PLATFORM PRESUBMIT");
+ } else if (launcherBuildMatcher.group("platform") != null
+ && platformBuildMatcher.group("postsubmit") != null) {
+ Log.d(TAG, "PLATFORM POSTSUBMIT");
+ } else {
+ Log.e(TAG, "ERROR3");
+ }
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index f070280..6dced8c 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -90,6 +90,7 @@
final UiObject2 allAppsContainer = verifyActiveContainer();
final UiObject2 appListRecycler = mLauncher.waitForObjectInContainer(allAppsContainer,
"apps_list_view");
+ final UiObject2 searchBox = getSearchBox(allAppsContainer);
allAppsContainer.setGestureMargins(
0,
getSearchBox(allAppsContainer).getVisibleBounds().bottom + 1,
@@ -103,7 +104,11 @@
int scroll = getScroll(allAppsContainer);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled")) {
while (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector)) {
- mLauncher.scroll(allAppsContainer, Direction.DOWN, 0.8f, null, 50);
+ mLauncher.scrollToLastVisibleRow(
+ allAppsContainer,
+ mLauncher.getObjectsInContainer(allAppsContainer, "icon"),
+ searchBox.getVisibleBounds().bottom -
+ allAppsContainer.getVisibleBounds().top);
final int newScroll = getScroll(allAppsContainer);
if (newScroll == scroll) break;
@@ -145,7 +150,7 @@
"Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
++attempts <= MAX_SCROLL_ATTEMPTS);
- mLauncher.scroll(allAppsContainer, Direction.UP, 1, margins, 50);
+ mLauncher.scroll(allAppsContainer, Direction.UP, margins, 50);
}
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled up")) {
@@ -172,7 +177,7 @@
final UiObject2 allAppsContainer = verifyActiveContainer();
// Start the gesture in the center to avoid starting at elements near the top.
mLauncher.scroll(
- allAppsContainer, Direction.DOWN, 1, new Rect(0, 0, 0, mHeight / 2), 10);
+ allAppsContainer, Direction.DOWN, new Rect(0, 0, 0, mHeight / 2), 10);
verifyActiveContainer();
}
}
@@ -186,7 +191,7 @@
final UiObject2 allAppsContainer = verifyActiveContainer();
// Start the gesture in the center, for symmetry with forward.
mLauncher.scroll(
- allAppsContainer, Direction.UP, 1, new Rect(0, mHeight / 2, 0, 0), 10);
+ allAppsContainer, Direction.UP, new Rect(0, mHeight / 2, 0, 0), 10);
verifyActiveContainer();
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 25e6e8c..49c0c89 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -55,7 +55,7 @@
final int leftMargin = mLauncher.getTestInfo(
TestProtocol.REQUEST_OVERVIEW_LEFT_GESTURE_MARGIN).
getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
- mLauncher.scroll(overview, Direction.LEFT, 1, new Rect(leftMargin, 0, 0, 0), 20);
+ mLauncher.scroll(overview, Direction.LEFT, new Rect(leftMargin, 0, 0, 0), 20);
verifyActiveContainer();
}
}
@@ -93,7 +93,7 @@
final int rightMargin = mLauncher.getTestInfo(
TestProtocol.REQUEST_OVERVIEW_RIGHT_GESTURE_MARGIN).
getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
- mLauncher.scroll(overview, Direction.RIGHT, 1, new Rect(0, 0, rightMargin, 0), 20);
+ mLauncher.scroll(overview, Direction.RIGHT, new Rect(0, 0, rightMargin, 0), 20);
verifyActiveContainer();
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 15615fc..52971d9 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -37,7 +37,6 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -52,6 +51,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.Configurator;
@@ -60,6 +60,7 @@
import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.Until;
+import com.android.launcher3.ResourceUtils;
import com.android.launcher3.testing.TestProtocol;
import com.android.systemui.shared.system.QuickStepContract;
@@ -68,12 +69,14 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;
+import java.util.Collection;
+import java.util.Collections;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
-import java.util.function.Supplier;
+import java.util.function.Function;
/**
* The main tapl object. The only object that can be explicitly constructed by the using code. It
@@ -84,6 +87,7 @@
private static final String TAG = "Tapl";
private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 20;
private static final int GESTURE_STEP_MS = 16;
+ private static long START_TIME = System.currentTimeMillis();
// Types for launcher containers that the user is interacting with. "Background" is a
// pseudo-container corresponding to inactive launcher covered by another app.
@@ -134,13 +138,22 @@
private int mExpectedRotation = Surface.ROTATION_0;
private final Uri mTestProviderUri;
private final Deque<String> mDiagnosticContext = new LinkedList<>();
- private Supplier<String> mSystemHealthSupplier;
+ private Function<Long, String> mSystemHealthSupplier;
private Consumer<ContainerType> mOnSettledStateAction;
/**
* Constructs the root of TAPL hierarchy. You get all other objects from it.
*/
+ public LauncherInstrumentation() {
+ this(InstrumentationRegistry.getInstrumentation());
+ }
+
+ /**
+ * Constructs the root of TAPL hierarchy. You get all other objects from it.
+ * Deprecated: use the constructor without parameters instead.
+ */
+ @Deprecated
public LauncherInstrumentation(Instrumentation instrumentation) {
mInstrumentation = instrumentation;
mDevice = UiDevice.getInstance(instrumentation);
@@ -238,10 +251,6 @@
return null;
}
- public static boolean isAvd() {
- return Build.MODEL.contains("Cuttlefish");
- }
-
static void log(String message) {
Log.d(TAG, message);
}
@@ -296,7 +305,7 @@
return "Background";
}
- public void setSystemHealthSupplier(Supplier<String> supplier) {
+ public void setSystemHealthSupplier(Function<Long, String> supplier) {
this.mSystemHealthSupplier = supplier;
}
@@ -316,8 +325,8 @@
}
return mSystemHealthSupplier != null
- ? mSystemHealthSupplier.get()
- : TestHelpers.getSystemHealthMessage(getContext());
+ ? mSystemHealthSupplier.apply(START_TIME)
+ : TestHelpers.getSystemHealthMessage(getContext(), START_TIME);
}
private void fail(String message) {
@@ -541,7 +550,7 @@
displaySize.x / 2, displaySize.y - 1,
displaySize.x / 2, 0,
ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME);
- assertTrue("Context menu is still visible afterswiping up to home",
+ assertTrue("Context menu is still visible after swiping up to home",
!hasLauncherObject("deep_shortcuts_container"));
}
if (hasLauncherObject(WORKSPACE_RES_ID)) {
@@ -769,7 +778,36 @@
TestProtocol.stateOrdinalToString(parcel.getInt(TestProtocol.STATE_FIELD)));
}
- void scroll(UiObject2 container, Direction direction, float percent, Rect margins, int steps) {
+ int getBottomGestureSize() {
+ return ResourceUtils.getNavbarSize(
+ ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, getResources()) + 1;
+ }
+
+ int getBottomGestureMargin(UiObject2 container) {
+ return container.getVisibleBounds().bottom - getRealDisplaySize().y +
+ getBottomGestureSize();
+ }
+
+ void scrollToLastVisibleRow(UiObject2 container, Collection<UiObject2> items, int topPadding) {
+ final UiObject2 lowestItem = Collections.max(items, (i1, i2) ->
+ Integer.compare(i1.getVisibleBounds().top, i2.getVisibleBounds().top));
+
+ final int gestureStart = lowestItem.getVisibleBounds().top + getTouchSlop();
+ final int distance = gestureStart - container.getVisibleBounds().top - topPadding;
+ final int bottomMargin = container.getVisibleBounds().height() - distance;
+
+ scroll(
+ container,
+ Direction.DOWN,
+ new Rect(
+ 0,
+ 0,
+ 0,
+ Math.max(bottomMargin, getBottomGestureMargin(container))),
+ 150);
+ }
+
+ void scroll(UiObject2 container, Direction direction, Rect margins, int steps) {
final Rect rect = container.getVisibleBounds();
if (margins != null) {
rect.left += margins.left;
@@ -787,7 +825,7 @@
case UP: {
startX = endX = rect.centerX();
final int vertCenter = rect.centerY();
- final float halfGestureHeight = rect.height() * percent / 2.0f;
+ final float halfGestureHeight = rect.height() / 2.0f;
startY = (int) (vertCenter - halfGestureHeight) + 1;
endY = (int) (vertCenter + halfGestureHeight);
}
@@ -795,7 +833,7 @@
case DOWN: {
startX = endX = rect.centerX();
final int vertCenter = rect.centerY();
- final float halfGestureHeight = rect.height() * percent / 2.0f;
+ final float halfGestureHeight = rect.height() / 2.0f;
startY = (int) (vertCenter + halfGestureHeight) - 1;
endY = (int) (vertCenter - halfGestureHeight);
}
@@ -803,7 +841,7 @@
case LEFT: {
startY = endY = rect.centerY();
final int horizCenter = rect.centerX();
- final float halfGestureWidth = rect.width() * percent / 2.0f;
+ final float halfGestureWidth = rect.width() / 2.0f;
startX = (int) (horizCenter - halfGestureWidth) + 1;
endX = (int) (horizCenter + halfGestureWidth);
}
@@ -811,7 +849,7 @@
case RIGHT: {
startY = endY = rect.centerY();
final int horizCenter = rect.centerX();
- final float halfGestureWidth = rect.width() * percent / 2.0f;
+ final float halfGestureWidth = rect.width() / 2.0f;
startX = (int) (horizCenter + halfGestureWidth) - 1;
endX = (int) (horizCenter - halfGestureWidth);
}
@@ -844,10 +882,6 @@
mDevice.waitForIdle();
}
- float getDisplayDensity() {
- return mInstrumentation.getTargetContext().getResources().getDisplayMetrics().density;
- }
-
int getTouchSlop() {
return ViewConfiguration.get(getContext()).getScaledTouchSlop();
}
diff --git a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java
index a089a52..0c9fda3 100644
--- a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java
+++ b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java
@@ -101,11 +101,11 @@
return ret.toString();
}
- private static String checkCrash(Context context, String label) {
+ private static String checkCrash(Context context, String label, long startTime) {
DropBoxManager dropbox = (DropBoxManager) context.getSystemService(Context.DROPBOX_SERVICE);
Assert.assertNotNull("Unable access the DropBoxManager service", dropbox);
- long timestamp = System.currentTimeMillis() - 5 * 60000;
+ long timestamp = startTime;
DropBoxManager.Entry entry;
StringBuilder errorDetails = new StringBuilder();
while (null != (entry = dropbox.getNextEntry(label, timestamp))) {
@@ -123,7 +123,7 @@
return errorDetails.length() != 0 ? errorDetails.toString() : null;
}
- public static String getSystemHealthMessage(Context context) {
+ public static String getSystemHealthMessage(Context context, long startTime) {
try {
StringBuilder errors = new StringBuilder();
@@ -131,7 +131,6 @@
"system_app_anr",
"system_app_crash",
"system_app_native_crash",
- "system_app_wtf",
"system_server_anr",
"system_server_crash",
"system_server_native_crash",
@@ -139,7 +138,7 @@
};
for (String label : labels) {
- final String crash = checkCrash(context, label);
+ final String crash = checkCrash(context, label, startTime);
if (crash != null) errors.append(crash);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 7d308af..51239c9 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -16,8 +16,6 @@
package com.android.launcher3.tapl;
-import static org.junit.Assert.fail;
-
import android.graphics.Point;
import android.graphics.Rect;
@@ -26,13 +24,12 @@
import androidx.test.uiautomator.Direction;
import androidx.test.uiautomator.UiObject2;
-import com.android.launcher3.ResourceUtils;
+import java.util.Collection;
/**
* All widgets container.
*/
public final class Widgets extends LauncherInstrumentation.VisibleContainer {
- private static final Rect MARGINS = new Rect(100, 100, 100, 100);
private static final int FLING_STEPS = 10;
Widgets(LauncherInstrumentation launcher) {
@@ -48,7 +45,11 @@
"want to fling forward in widgets")) {
LauncherInstrumentation.log("Widgets.flingForward enter");
final UiObject2 widgetsContainer = verifyActiveContainer();
- mLauncher.scroll(widgetsContainer, Direction.DOWN, 1f, MARGINS, FLING_STEPS);
+ mLauncher.scroll(
+ widgetsContainer,
+ Direction.DOWN,
+ new Rect(0, 0, 0, mLauncher.getBottomGestureMargin(widgetsContainer)),
+ FLING_STEPS);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung forward")) {
verifyActiveContainer();
}
@@ -64,7 +65,11 @@
"want to fling backwards in widgets")) {
LauncherInstrumentation.log("Widgets.flingBackward enter");
final UiObject2 widgetsContainer = verifyActiveContainer();
- mLauncher.scroll(widgetsContainer, Direction.UP, 1f, MARGINS, FLING_STEPS);
+ mLauncher.scroll(
+ widgetsContainer,
+ Direction.UP,
+ new Rect(0, 0, widgetsContainer.getVisibleBounds().width(), 0),
+ FLING_STEPS);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) {
verifyActiveContainer();
}
@@ -78,32 +83,33 @@
}
public Widget getWidget(String labelText) {
- final int margin = ResourceUtils.getNavbarSize(
- ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources()) + 1;
final UiObject2 widgetsContainer = verifyActiveContainer();
- widgetsContainer.setGestureMargins(0, 0, 0, margin);
-
final Point displaySize = mLauncher.getRealDisplaySize();
+ final BySelector labelSelector = By.clazz("android.widget.TextView").text(labelText);
int i = 0;
- final BySelector selector = By.clazz("android.widget.TextView").text(labelText);
-
for (; ; ) {
- final UiObject2 label = mLauncher.tryWaitForLauncherObject(selector, 300);
- if (label != null) {
+ final Collection<UiObject2> cells = mLauncher.getObjectsInContainer(
+ widgetsContainer, "widgets_cell_list_container");
+ mLauncher.assertTrue("Widgets doesn't have 2 rows", cells.size() >= 2);
+ for (UiObject2 cell : cells) {
+ final UiObject2 label = cell.findObject(labelSelector);
+ if (label == null) continue;
+
final UiObject2 widget = label.getParent().getParent();
mLauncher.assertEquals(
"View is not WidgetCell",
"com.android.launcher3.widget.WidgetCell",
widget.getClassName());
- if (widget.getVisibleBounds().bottom <= displaySize.y - margin) {
+ if (widget.getVisibleBounds().bottom <=
+ displaySize.y - mLauncher.getBottomGestureSize()) {
return new Widget(mLauncher, widget);
}
}
- if (++i > 40) fail("Too many attempts");
- mLauncher.scroll(widgetsContainer, Direction.DOWN, 0.7f, MARGINS, 50);
+ mLauncher.assertTrue("Too many attempts", ++i <= 40);
+ mLauncher.scrollToLastVisibleRow(widgetsContainer, cells, 0);
}
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 510ea14..0aa36dd 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -38,8 +38,6 @@
* Operations on the workspace screen.
*/
public final class Workspace extends Home {
- private static final float FLING_SPEED =
- LauncherInstrumentation.isAvd() ? 1500.0F : 3500.0F;
private static final int DRAG_DURACTION = 2000;
private static final int FLING_STEPS = 10;
private final UiObject2 mHotseat;
@@ -142,7 +140,7 @@
}
private boolean isWorkspaceScrollable(UiObject2 workspace) {
- return workspace.isScrollable();
+ return workspace.getChildCount() > 1;
}
@NonNull
@@ -182,7 +180,7 @@
*/
public void flingForward() {
final UiObject2 workspace = verifyActiveContainer();
- mLauncher.scroll(workspace, Direction.RIGHT, 1f,
+ mLauncher.scroll(workspace, Direction.RIGHT,
new Rect(0, 0, mLauncher.getEdgeSensitivityWidth(), 0),
FLING_STEPS);
verifyActiveContainer();
@@ -194,7 +192,7 @@
*/
public void flingBackward() {
final UiObject2 workspace = verifyActiveContainer();
- mLauncher.scroll(workspace, Direction.LEFT, 1f,
+ mLauncher.scroll(workspace, Direction.LEFT,
new Rect(mLauncher.getEdgeSensitivityWidth(), 0, 0, 0),
FLING_STEPS);
verifyActiveContainer();