Merge "Including wrapper code in Launcher builds" into ub-launcher3-master
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 2e6b662..5799c01 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,23 +39,27 @@
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.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();
@@ -99,6 +103,7 @@
private boolean mOverlayEnabled;
private boolean mRotated;
+ private OverviewScreenshotActions mOverviewScreenshotActionsPlugin;
public TaskThumbnailView(Context context) {
this(context, null);
@@ -146,6 +151,10 @@
mPaint.setShader(null);
mOverlay.reset();
}
+ if (mOverviewScreenshotActionsPlugin != null) {
+ mOverviewScreenshotActionsPlugin
+ .setupActions((ViewGroup) getTaskView(), getThumbnail(), mActivity);
+ }
updateThumbnailPaintFilter();
}
@@ -210,6 +219,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/robolectric_tests/src/com/android/launcher3/config/FlagOverrideRule.java b/robolectric_tests/src/com/android/launcher3/config/FlagOverrideRule.java
index e49c67c..4bb9a53 100644
--- a/robolectric_tests/src/com/android/launcher3/config/FlagOverrideRule.java
+++ b/robolectric_tests/src/com/android/launcher3/config/FlagOverrideRule.java
@@ -7,7 +7,6 @@
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
-import org.robolectric.RuntimeEnvironment;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
@@ -15,6 +14,10 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
/**
* Test rule that makes overriding flags in Robolectric tests easier. This rule clears all flags
@@ -52,68 +55,48 @@
boolean value();
}
- private boolean ruleInProgress;
-
@Override
public Statement apply(Statement base, Description description) {
- return new Statement() {
- @Override
- public void evaluate() throws Throwable {
- FeatureFlags.initialize(RuntimeEnvironment.application.getApplicationContext());
- ruleInProgress = true;
- try {
- clearOverrides();
- applyAnnotationOverrides(description);
- base.evaluate();
- } finally {
- ruleInProgress = false;
- clearOverrides();
+ return new MyStatement(base, description);
+ }
+
+ private class MyStatement extends Statement {
+
+ private final Statement mBase;
+ private final Description mDescription;
+
+
+ MyStatement(Statement base, Description description) {
+ mBase = base;
+ mDescription = description;
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ Map<String, BaseTogglableFlag> allFlags = FeatureFlags.getTogglableFlags().stream()
+ .collect(Collectors.toMap(TogglableFlag::getKey, Function.identity()));
+
+ HashMap<BaseTogglableFlag, Boolean> changedValues = new HashMap<>();
+ FlagOverride[] overrides = new FlagOverride[0];
+ try {
+ for (Annotation annotation : mDescription.getAnnotations()) {
+ if (annotation.annotationType() == FlagOverride.class) {
+ overrides = new FlagOverride[] { (FlagOverride) annotation };
+ } else if (annotation.annotationType() == FlagOverrides.class) {
+ // Note: this branch is hit if the annotation is repeated
+ overrides = ((FlagOverrides) annotation).value();
+ }
}
- }
- };
- }
-
- private void override(BaseTogglableFlag flag, boolean newValue) {
- if (!ruleInProgress) {
- throw new IllegalStateException(
- "Rule isn't in progress. Did you remember to mark it with @Rule?");
- }
- flag.setForTests(newValue);
- }
-
- private void applyAnnotationOverrides(Description description) {
- for (Annotation annotation : description.getAnnotations()) {
- if (annotation.annotationType() == FlagOverride.class) {
- applyAnnotation((FlagOverride) annotation);
- } else if (annotation.annotationType() == FlagOverrides.class) {
- // Note: this branch is hit if the annotation is repeated
- for (FlagOverride flagOverride : ((FlagOverrides) annotation).value()) {
- applyAnnotation(flagOverride);
+ for (FlagOverride override : overrides) {
+ BaseTogglableFlag flag = allFlags.get(override.key());
+ changedValues.put(flag, flag.get());
+ flag.setForTests(override.value());
}
+ mBase.evaluate();
+ } finally {
+ // Clear the values
+ changedValues.forEach(BaseTogglableFlag::setForTests);
}
}
}
-
- private void applyAnnotation(FlagOverride flagOverride) {
- boolean found = false;
- for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
- if (flag.getKey().equals(flagOverride.key())) {
- override(flag, flagOverride.value());
- found = true;
- break;
- }
- }
- if (!found) {
- throw new IllegalStateException("Flag " + flagOverride.key() + " not found");
- }
- }
-
- /**
- * Resets all flags to their default values.
- */
- private void clearOverrides() {
- for (BaseTogglableFlag flag : FeatureFlags.getTogglableFlags()) {
- flag.setForTests(flag.getDefaultValue());
- }
- }
}
diff --git a/robolectric_tests/src/com/android/launcher3/logging/FileLogTest.java b/robolectric_tests/src/com/android/launcher3/logging/FileLogTest.java
index 096db57..410a077 100644
--- a/robolectric_tests/src/com/android/launcher3/logging/FileLogTest.java
+++ b/robolectric_tests/src/com/android/launcher3/logging/FileLogTest.java
@@ -1,20 +1,22 @@
package com.android.launcher3.logging;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
+import org.robolectric.util.Scheduler;
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Calendar;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
/**
* Tests for {@link FileLog}
*/
@@ -22,9 +24,10 @@
public class FileLogTest {
private File mTempDir;
+ private boolean mTestActive;
@Before
- public void setUp() throws Exception {
+ public void setUp() {
int count = 0;
do {
mTempDir = new File(RuntimeEnvironment.application.getCacheDir(),
@@ -32,14 +35,24 @@
} while (!mTempDir.mkdir());
FileLog.setDir(mTempDir);
+
+ mTestActive = true;
+ Scheduler scheduler = Shadows.shadowOf(FileLog.getHandler().getLooper()).getScheduler();
+ new Thread(() -> {
+ while (mTestActive) {
+ scheduler.advanceToLastPostedRunnable();
+ }
+ }).start();
}
@After
- public void tearDown() throws Exception {
+ public void tearDown() {
// Clear existing logs
new File(mTempDir, "log-0").delete();
new File(mTempDir, "log-1").delete();
mTempDir.delete();
+
+ mTestActive = false;
}
@Test
@@ -49,12 +62,12 @@
}
FileLog.print("Testing", "hoolalala");
StringWriter writer = new StringWriter();
- FileLog.flushAll(new PrintWriter(writer));
+ assertTrue(FileLog.flushAll(new PrintWriter(writer)));
assertTrue(writer.toString().contains("hoolalala"));
FileLog.print("Testing", "abracadabra", new Exception("cat! cat!"));
writer = new StringWriter();
- FileLog.flushAll(new PrintWriter(writer));
+ assertTrue(FileLog.flushAll(new PrintWriter(writer)));
assertTrue(writer.toString().contains("abracadabra"));
// Exception is also printed
assertTrue(writer.toString().contains("cat! cat!"));
@@ -70,7 +83,7 @@
}
FileLog.print("Testing", "hoolalala");
StringWriter writer = new StringWriter();
- FileLog.flushAll(new PrintWriter(writer));
+ assertTrue(FileLog.flushAll(new PrintWriter(writer)));
assertTrue(writer.toString().contains("hoolalala"));
Calendar threeDaysAgo = Calendar.getInstance();
@@ -80,7 +93,7 @@
FileLog.print("Testing", "abracadabra", new Exception("cat! cat!"));
writer = new StringWriter();
- FileLog.flushAll(new PrintWriter(writer));
+ assertTrue(FileLog.flushAll(new PrintWriter(writer)));
assertTrue(writer.toString().contains("abracadabra"));
// Exception is also printed
assertTrue(writer.toString().contains("cat! cat!"));
diff --git a/robolectric_tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java b/robolectric_tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
index bc936b7..32eb2ec 100644
--- a/robolectric_tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
+++ b/robolectric_tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
@@ -15,17 +15,20 @@
import android.os.Process;
import android.os.UserHandle;
+import androidx.annotation.NonNull;
+
import com.android.launcher3.AppFilter;
import com.android.launcher3.AppInfo;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
-import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.LauncherModel.ModelUpdateTask;
import com.android.launcher3.LauncherProvider;
+import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.icons.cache.CachingLogic;
+import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.TestLauncherProvider;
@@ -44,8 +47,6 @@
import java.util.concurrent.Executor;
import java.util.function.Supplier;
-import androidx.annotation.NonNull;
-
/**
* Base class for writing tests for Model update tasks.
*/
@@ -79,6 +80,7 @@
model = mock(LauncherModel.class);
modelWriter = mock(ModelWriter.class);
+ LauncherAppState.INSTANCE.initializeForTesting(appState);
when(appState.getModel()).thenReturn(model);
when(model.getWriter(anyBoolean(), anyBoolean())).thenReturn(modelWriter);
when(model.getCallback()).thenReturn(callbacks);
@@ -216,5 +218,10 @@
public Bitmap newIcon() {
return Bitmap.createBitmap(1, 1, Config.ARGB_8888);
}
+
+ @Override
+ public synchronized BitmapInfo getDefaultIcon(UserHandle user) {
+ return BitmapInfo.fromBitmap(newIcon());
+ }
}
}
diff --git a/robolectric_tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
index 42848f4..81b9043 100644
--- a/robolectric_tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
@@ -11,7 +11,6 @@
import com.android.launcher3.WorkspaceItemInfo;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@@ -41,7 +40,6 @@
}
@Test
- @Ignore("This test fails with resource errors") // b/131115553
public void testCacheUpdate_update_apps() throws Exception {
// Clear all icons from apps list so that its easy to check what was updated
for (AppInfo info : allAppsList.data) {
@@ -66,7 +64,6 @@
}
@Test
- @Ignore("This test fails with resource errors") // b/131115553
public void testSessionUpdate_ignores_normal_apps() throws Exception {
executeTaskForTest(newTask(CacheDataUpdatedTask.OP_SESSION_UPDATE, "app1"));
@@ -75,7 +72,6 @@
}
@Test
- @Ignore("This test fails with resource errors") // b/131115553
public void testSessionUpdate_updates_pending_apps() throws Exception {
executeTaskForTest(newTask(CacheDataUpdatedTask.OP_SESSION_UPDATE, "app3"));
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index d70abc2..db94bdb 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -44,7 +44,7 @@
public static final String ACTION_FORCE_ROLOAD = "force-reload-launcher";
// We do not need any synchronization for this variable as its only written on UI thread.
- private static final MainThreadInitializedObject<LauncherAppState> INSTANCE =
+ public static final MainThreadInitializedObject<LauncherAppState> INSTANCE =
new MainThreadInitializedObject<>(LauncherAppState::new);
private final Context mContext;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index cdce5c0..431a149 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1496,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/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index e6eced1..c502dd7 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -238,14 +238,7 @@
@Override
public int hashCode() {
- int h$ = 1;
- h$ *= 1000003;
- h$ ^= key.hashCode();
- h$ *= 1000003;
- h$ ^= getDefaultValue() ? 1231 : 1237;
- h$ *= 1000003;
- h$ ^= description.hashCode();
- return h$;
+ return key.hashCode();
}
}
}
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/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/logging/FileLog.java b/src/com/android/launcher3/logging/FileLog.java
index 923a89b..04cf20a 100644
--- a/src/com/android/launcher3/logging/FileLog.java
+++ b/src/com/android/launcher3/logging/FileLog.java
@@ -8,6 +8,8 @@
import android.util.Log;
import android.util.Pair;
+import androidx.annotation.VisibleForTesting;
+
import com.android.launcher3.util.IOUtils;
import java.io.BufferedReader;
@@ -88,7 +90,8 @@
Message.obtain(getHandler(), LogWriterCallback.MSG_WRITE, out).sendToTarget();
}
- private static Handler getHandler() {
+ @VisibleForTesting
+ static Handler getHandler() {
synchronized (DATE_FORMAT) {
if (sHandler == null) {
sHandler = new Handler(createAndStartNewLooper("file-logger"),
@@ -102,15 +105,16 @@
* Blocks until all the pending logs are written to the disk
* @param out if not null, all the persisted logs are copied to the writer.
*/
- public static void flushAll(PrintWriter out) throws InterruptedException {
+ public static boolean flushAll(PrintWriter out) throws InterruptedException {
if (!ENABLED) {
- return;
+ return false;
}
CountDownLatch latch = new CountDownLatch(1);
Message.obtain(getHandler(), LogWriterCallback.MSG_FLUSH,
Pair.create(out, latch)).sendToTarget();
latch.await(2, TimeUnit.SECONDS);
+ return latch.getCount() == 0;
}
/**
diff --git a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
index cf3e26d..b3569f2 100644
--- a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
+++ b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
@@ -50,13 +50,18 @@
public static final MainThreadInitializedObject<CustomWidgetManager> INSTANCE =
new MainThreadInitializedObject<>(CustomWidgetManager::new);
- private final List<CustomWidgetPlugin> mPlugins;
+ /**
+ * 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 List<CustomAppWidgetProviderInfo> mCustomWidgets;
private final SparseArray<ComponentName> mWidgetsIdMap;
private Consumer<PackageUserKey> mWidgetRefreshCallback;
private CustomWidgetManager(Context context) {
- mPlugins = new ArrayList<>();
+ mPlugins = new SparseArray<>();
mCustomWidgets = new ArrayList<>();
mWidgetsIdMap = new SparseArray<>();
PluginManagerWrapper.INSTANCE.get(context)
@@ -65,25 +70,28 @@
@Override
public void onPluginConnected(CustomWidgetPlugin plugin, Context context) {
- mPlugins.add(plugin);
+ mPlugins.put(mAutoProviderId, plugin);
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(plugin, parcel, context);
+ CustomAppWidgetProviderInfo info = newInfo(mAutoProviderId, plugin, parcel, context);
parcel.recycle();
mCustomWidgets.add(info);
- mWidgetsIdMap.put(plugin.getProviderId(), info.provider);
+ mWidgetsIdMap.put(mAutoProviderId, info.provider);
mWidgetRefreshCallback.accept(null);
+ mAutoProviderId++;
}
@Override
public void onPluginDisconnected(CustomWidgetPlugin plugin) {
- mPlugins.remove(plugin);
- mCustomWidgets.remove(getWidgetProvider(plugin.getProviderId()));
- mWidgetsIdMap.remove(plugin.getProviderId());
+ int providerId = findProviderId(plugin);
+ if (providerId == -1) return;
+ mPlugins.remove(providerId);
+ mCustomWidgets.remove(getWidgetProvider(providerId));
+ mWidgetsIdMap.remove(providerId);
}
/**
@@ -98,7 +106,7 @@
*/
public void onViewCreated(LauncherAppWidgetHostView view) {
CustomAppWidgetProviderInfo info = (CustomAppWidgetProviderInfo) view.getAppWidgetInfo();
- CustomWidgetPlugin plugin = findPlugin(info.providerId);
+ CustomWidgetPlugin plugin = mPlugins.get(info.providerId);
if (plugin == null) return;
plugin.onViewCreated(view);
}
@@ -135,17 +143,14 @@
return null;
}
- private static CustomAppWidgetProviderInfo newInfo(
- CustomWidgetPlugin plugin, Parcel parcel, Context context) {
- int providerId = plugin.getProviderId();
+ 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();
- info.icon = plugin.getIcon();
- info.previewImage = plugin.getPreviewImage();
info.resizeMode = plugin.getResizeMode();
info.spanX = plugin.getSpanX();
@@ -155,9 +160,13 @@
return info;
}
- @Nullable
- private CustomWidgetPlugin findPlugin(int providerId) {
- return mPlugins.stream().filter((p) -> p.getProviderId() == providerId).findFirst()
- .orElse(null);
+ 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_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java b/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java
index 77ad7ea..56ebcc5 100644
--- a/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java
+++ b/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java
@@ -30,28 +30,11 @@
int VERSION = 1;
/**
- * An unique identifier for this widget. Must be a non-negative integer.
- */
- int getProviderId();
-
- /**
* The label to display to the user in the AppWidget picker.
*/
String getLabel();
/**
- * A preview of what the AppWidget will look like after it's configured.
- * If not supplied, the AppWidget's icon will be used.
- */
- int getPreviewImage();
-
- /**
- * The icon to display for this AppWidget in the AppWidget picker. If not supplied in the
- * xml, the application icon will be used.
- */
- int getIcon();
-
- /**
* 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.
*/
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/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/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 2a04d46..39cb0bf 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;
@@ -28,11 +26,13 @@
import com.android.launcher3.ResourceUtils;
+import java.util.Collection;
+import java.util.Collections;
+
/**
* 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,12 +48,12 @@
"want to fling forward in widgets")) {
LauncherInstrumentation.log("Widgets.flingForward enter");
final UiObject2 widgetsContainer = verifyActiveContainer();
- final int margin = widgetsContainer.getVisibleBounds().bottom -
- mLauncher.getRealDisplaySize().y +
- ResourceUtils.getNavbarSize(
- ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources());
mLauncher.scroll(
- widgetsContainer, Direction.DOWN, 1f, new Rect(0, 0, 0, margin), FLING_STEPS);
+ widgetsContainer,
+ Direction.DOWN,
+ 1f,
+ new Rect(0, 0, 0, getBottomGestureMargin(widgetsContainer)),
+ FLING_STEPS);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung forward")) {
verifyActiveContainer();
}
@@ -61,6 +61,16 @@
}
}
+ private int getBottomGestureMargin(UiObject2 widgetsContainer) {
+ return widgetsContainer.getVisibleBounds().bottom - mLauncher.getRealDisplaySize().y +
+ getBottomGestureSize();
+ }
+
+ private int getBottomGestureSize() {
+ return ResourceUtils.getNavbarSize(
+ ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources()) + 1;
+ }
+
/**
* Flings backward (up) and waits the fling's end.
*/
@@ -69,7 +79,12 @@
"want to fling backwards in widgets")) {
LauncherInstrumentation.log("Widgets.flingBackward enter");
final UiObject2 widgetsContainer = verifyActiveContainer();
- mLauncher.scroll(widgetsContainer, Direction.UP, 1f, null, FLING_STEPS);
+ mLauncher.scroll(
+ widgetsContainer,
+ Direction.UP,
+ 1f,
+ new Rect(0, 0, widgetsContainer.getVisibleBounds().width(), 0),
+ FLING_STEPS);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) {
verifyActiveContainer();
}
@@ -83,32 +98,48 @@
}
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 - 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);
+ final UiObject2 lowestCell = Collections.max(cells, (c1, c2) ->
+ Integer.compare(c1.getVisibleBounds().top, c2.getVisibleBounds().top));
+
+ final int gestureStart = lowestCell.getVisibleBounds().top + mLauncher.getTouchSlop();
+ final int distance = gestureStart - widgetsContainer.getVisibleBounds().top;
+ final int bottomMargin = widgetsContainer.getVisibleBounds().height() - distance;
+
+ mLauncher.scroll(
+ widgetsContainer,
+ Direction.DOWN,
+ 1f,
+ new Rect(
+ 0,
+ 0,
+ 0,
+ Math.max(bottomMargin, getBottomGestureMargin(widgetsContainer))),
+ 150);
}
}
}