Merge "Bug fix: QSB sometimes gets stuck to transparent." into ub-launcher3-master
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 0380923..c45ff7b 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -355,10 +355,11 @@
public void snapToWidget(boolean animate) {
final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
- int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding
- - mWidgetPadding.left - mWidgetPadding.right;
- int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding
- - mWidgetPadding.top - mWidgetPadding.bottom;
+ DeviceProfile profile = mLauncher.getDeviceProfile();
+ int newWidth = (int) (mWidgetView.getWidth() * profile.appWidgetScale.x)
+ + 2 * mBackgroundPadding - mWidgetPadding.left - mWidgetPadding.right;
+ int newHeight = (int) (mWidgetView.getHeight() * profile.appWidgetScale.y)
+ + 2 * mBackgroundPadding - mWidgetPadding.top - mWidgetPadding.bottom;
mTmpPt[0] = mWidgetView.getLeft();
mTmpPt[1] = mWidgetView.getTop();
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 3564cec..9eaef90 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -2690,6 +2690,18 @@
}
public void setup(int cellWidth, int cellHeight, boolean invertHorizontally, int colCount) {
+ setup(cellWidth, cellHeight, invertHorizontally, colCount, 1.0f, 1.0f);
+ }
+
+ /**
+ * Use this method, as opposed to {@link #setup(int, int, boolean, int)}, if the view needs
+ * to be scaled.
+ *
+ * ie. In multi-window mode, we setup widgets so that they are measured and laid out
+ * using their full/invariant device profile sizes.
+ */
+ public void setup(int cellWidth, int cellHeight, boolean invertHorizontally, int colCount,
+ float cellScaleX, float cellScaleY) {
if (isLockedToGrid) {
final int myCellHSpan = cellHSpan;
final int myCellVSpan = cellVSpan;
@@ -2700,8 +2712,8 @@
myCellX = colCount - myCellX - cellHSpan;
}
- width = myCellHSpan * cellWidth - leftMargin - rightMargin;
- height = myCellVSpan * cellHeight - topMargin - bottomMargin;
+ width = (int) (myCellHSpan * cellWidth / cellScaleX - leftMargin - rightMargin);
+ height = (int) (myCellVSpan * cellHeight / cellScaleY - topMargin - bottomMargin);
x = (myCellX * cellWidth + leftMargin);
y = (myCellY * cellHeight + topMargin);
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 59ec56a..eb1db1c 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.view.Gravity;
@@ -123,6 +124,9 @@
public int allAppsIconDrawablePaddingPx;
public float allAppsIconTextSizePx;
+ // Widgets
+ public final PointF appWidgetScale = new PointF(1.0f, 1.0f);
+
// Drop Target
public int dropTargetBarSizePx;
@@ -220,6 +224,12 @@
// The nav bar is black so we add bottom padding to visually center hotseat icons.
profile.hotseatBarBottomPaddingPx = profile.hotseatBarTopPaddingPx;
+ // We use these scales to measure and layout the widgets using their full invariant profile
+ // sizes and then draw them scaled and centered to fit in their multi-window mode cellspans.
+ float appWidgetScaleX = (float) profile.getCellSize().x / getCellSize().x;
+ float appWidgetScaleY = (float) profile.getCellSize().y / getCellSize().y;
+ profile.appWidgetScale.set(appWidgetScaleX, appWidgetScaleY);
+
return profile;
}
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index 056facb..d2f25a4 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -33,6 +33,8 @@
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.Provider;
import com.android.launcher3.util.Thunk;
import org.json.JSONException;
@@ -44,6 +46,7 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
public class InstallShortcutReceiver extends BroadcastReceiver {
@@ -76,11 +79,7 @@
String encoded = info.encodeToString();
if (encoded != null) {
Set<String> strings = sharedPrefs.getStringSet(APPS_PENDING_INSTALL, null);
- if (strings == null) {
- strings = new HashSet<String>(1);
- } else {
- strings = new HashSet<String>(strings);
- }
+ strings = (strings != null) ? new HashSet<>(strings) : new HashSet<String>(1);
strings.add(encoded);
sharedPrefs.edit().putStringSet(APPS_PENDING_INSTALL, strings).apply();
}
@@ -115,16 +114,15 @@
}
}
- private static ArrayList<PendingInstallShortcutInfo> getAndClearInstallQueue(
- SharedPreferences sharedPrefs, Context context) {
+ private static ArrayList<PendingInstallShortcutInfo> getAndClearInstallQueue(Context context) {
+ SharedPreferences sharedPrefs = Utilities.getPrefs(context);
synchronized(sLock) {
+ ArrayList<PendingInstallShortcutInfo> infos = new ArrayList<>();
Set<String> strings = sharedPrefs.getStringSet(APPS_PENDING_INSTALL, null);
if (DBG) Log.d(TAG, "Getting and clearing APPS_PENDING_INSTALL: " + strings);
if (strings == null) {
- return new ArrayList<PendingInstallShortcutInfo>();
+ return infos;
}
- ArrayList<PendingInstallShortcutInfo> infos =
- new ArrayList<PendingInstallShortcutInfo>();
for (String encoded : strings) {
PendingInstallShortcutInfo info = decode(encoded, context);
if (info != null) {
@@ -212,36 +210,12 @@
mUseInstallQueue = false;
flushInstallQueue(context);
}
+
static void flushInstallQueue(Context context) {
- SharedPreferences sp = Utilities.getPrefs(context);
- ArrayList<PendingInstallShortcutInfo> installQueue = getAndClearInstallQueue(sp, context);
- if (!installQueue.isEmpty()) {
- Iterator<PendingInstallShortcutInfo> iter = installQueue.iterator();
- ArrayList<ItemInfo> addShortcuts = new ArrayList<ItemInfo>();
- while (iter.hasNext()) {
- final PendingInstallShortcutInfo pendingInfo = iter.next();
-
- // If the intent specifies a package, make sure the package exists
- String packageName = pendingInfo.getTargetPackage();
- if (!TextUtils.isEmpty(packageName)) {
- UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle();
- if (!LauncherAppsCompat.getInstance(context)
- .isPackageEnabledForProfile(packageName, myUserHandle)) {
- if (DBG) Log.d(TAG, "Ignoring shortcut for absent package: "
- + pendingInfo.launchIntent);
- continue;
- }
- }
-
- // Generate a shortcut info to add into the model
- addShortcuts.add(pendingInfo.getShortcutInfo());
- }
-
- // Add the new apps to the model and bind them
- if (!addShortcuts.isEmpty()) {
- LauncherAppState app = LauncherAppState.getInstance();
- app.getModel().addAndBindAddedWorkspaceItems(addShortcuts);
- }
+ ArrayList<PendingInstallShortcutInfo> items = getAndClearInstallQueue(context);
+ if (!items.isEmpty()) {
+ LauncherAppState.getInstance().getModel().addAndBindAddedWorkspaceItems(
+ new LazyShortcutsProvider(context.getApplicationContext(), items));
}
}
@@ -445,4 +419,40 @@
// Ignore any conflicts in the label name, as that can change based on locale.
return new PendingInstallShortcutInfo(info, original.mContext);
}
+
+ private static class LazyShortcutsProvider extends Provider<List<ItemInfo>> {
+
+ private final Context mContext;
+ private final ArrayList<PendingInstallShortcutInfo> mPendingItems;
+
+ public LazyShortcutsProvider(Context context, ArrayList<PendingInstallShortcutInfo> items) {
+ mContext = context;
+ mPendingItems = items;
+ }
+
+ /**
+ * This must be called on the background thread as this requires multiple calls to
+ * packageManager and icon cache.
+ */
+ @Override
+ public ArrayList<ItemInfo> get() {
+ Preconditions.assertNonUiThread();
+ ArrayList<ItemInfo> installQueue = new ArrayList<>();
+ LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext);
+ for (PendingInstallShortcutInfo pendingInfo : mPendingItems) {
+ // If the intent specifies a package, make sure the package exists
+ String packageName = pendingInfo.getTargetPackage();
+ if (!TextUtils.isEmpty(packageName) && !launcherApps.isPackageEnabledForProfile(
+ packageName, pendingInfo.user)) {
+ if (DBG) Log.d(TAG, "Ignoring shortcut for absent package: "
+ + pendingInfo.launchIntent);
+ continue;
+ }
+
+ // Generate a shortcut info to add into the model
+ installQueue.add(pendingInfo.getShortcutInfo());
+ }
+ return installQueue;
+ }
+ }
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index cfb28f9..c7bb188 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -85,6 +85,7 @@
import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.Provider;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.ViewOnDrawExecutor;
@@ -260,9 +261,16 @@
/**
* Adds the provided items to the workspace.
*/
+ public void addAndBindAddedWorkspaceItems(List<ItemInfo> workspaceApps) {
+ addAndBindAddedWorkspaceItems(Provider.of(workspaceApps));
+ }
+
+ /**
+ * Adds the provided items to the workspace.
+ */
public void addAndBindAddedWorkspaceItems(
- final ArrayList<? extends ItemInfo> workspaceApps) {
- enqueueModelUpdateTask(new AddWorkspaceItemsTask(workspaceApps));
+ Provider<List<ItemInfo>> appsProvider) {
+ enqueueModelUpdateTask(new AddWorkspaceItemsTask(appsProvider));
}
/**
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 349f094..b30c3f3 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -650,7 +650,7 @@
if (mWidgetHostResetHandler != null) {
new AppWidgetHost(mContext, Launcher.APPWIDGET_HOST_ID).deleteHost();
mWidgetHostResetHandler.sendEmptyMessage(
- ChangeListenerWrapper.MSG_EXTRACTED_COLORS_CHANGED);
+ ChangeListenerWrapper.MSG_APP_WIDGET_HOST_RESET);
}
// Set the flag for empty DB
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 5f89af6..342479f 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -18,6 +18,7 @@
import android.app.WallpaperManager;
import android.content.Context;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.support.annotation.IntDef;
import android.view.View;
@@ -120,20 +121,20 @@
}
public void measureChild(View child) {
- final DeviceProfile grid = mLauncher.getDeviceProfile();
- final int cellWidth = mCellWidth;
- final int cellHeight = mCellHeight;
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
if (!lp.isFullscreen) {
- lp.setup(cellWidth, cellHeight, invertLayoutHorizontally(), mCountX);
+ final DeviceProfile profile = mLauncher.getDeviceProfile();
if (child instanceof LauncherAppWidgetHostView) {
- // Widgets have their own padding, so skip
+ lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX,
+ profile.appWidgetScale.x, profile.appWidgetScale.y);
+ // Widgets have their own padding
} else {
- // Otherwise, center the icon/folder
+ lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX);
+ // Center the icon/folder
int cHeight = getCellContentHeight();
int cellPaddingY = (int) Math.max(0, ((lp.height - cHeight) / 2f));
- int cellPaddingX = (int) (grid.edgeMarginPx / 2f);
+ int cellPaddingX = (int) (profile.edgeMarginPx / 2f);
child.setPadding(cellPaddingX, cellPaddingY, cellPaddingX, 0);
}
} else {
@@ -158,6 +159,21 @@
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
+
+ if (child instanceof LauncherAppWidgetHostView) {
+ // Scale and center the widget to fit within its cells.
+ DeviceProfile profile = mLauncher.getDeviceProfile();
+ float scaleX = profile.appWidgetScale.x;
+ float scaleY = profile.appWidgetScale.y;
+
+ float scale = Math.min(scaleX, scaleY);
+ child.setScaleX(scale);
+ child.setScaleY(scale);
+
+ child.setTranslationX(-(lp.width - (lp.width * scaleX)) / 2.0f);
+ child.setTranslationY(-(lp.height - (lp.height * scaleY)) / 2.0f);
+ }
+
int childLeft = lp.x;
int childTop = lp.y;
child.layout(childLeft, childTop, childLeft + lp.width, childTop + lp.height);
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index 986e163..97335cb 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -33,26 +33,29 @@
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.util.GridOccupancy;
+import com.android.launcher3.util.Provider;
import java.util.ArrayList;
+import java.util.List;
/**
* Task to add auto-created workspace items.
*/
public class AddWorkspaceItemsTask extends ExtendedModelTask {
- private final ArrayList<? extends ItemInfo> mWorkspaceApps;
+ private final Provider<List<ItemInfo>> mAppsProvider;
/**
- * @param workspaceApps items to add on the workspace
+ * @param appsProvider items to add on the workspace
*/
- public AddWorkspaceItemsTask(ArrayList<? extends ItemInfo> workspaceApps) {
- mWorkspaceApps = workspaceApps;
+ public AddWorkspaceItemsTask(Provider<List<ItemInfo>> appsProvider) {
+ mAppsProvider = appsProvider;
}
@Override
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
- if (mWorkspaceApps.isEmpty()) {
+ List<ItemInfo> workspaceApps = mAppsProvider.get();
+ if (workspaceApps.isEmpty()) {
return;
}
Context context = app.getContext();
@@ -65,7 +68,7 @@
// called.
ArrayList<Long> workspaceScreens = LauncherModel.loadWorkspaceScreensDb(context);
synchronized(dataModel) {
- for (ItemInfo item : mWorkspaceApps) {
+ for (ItemInfo item : workspaceApps) {
if (item instanceof ShortcutInfo) {
// Short-circuit this logic if the icon exists somewhere on the workspace
if (shortcutExists(dataModel, item.getIntent(), item.user)) {
@@ -258,5 +261,4 @@
}
return occupied.findVacantCell(xy, spanX, spanY);
}
-
}
diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
index 78b7a3e..817a38a 100644
--- a/src/com/android/launcher3/util/ManagedProfileHeuristic.java
+++ b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
@@ -121,7 +121,7 @@
// getting filled with the managed user apps, when it start with a fresh DB (or after
// a very long time).
if (userAppsExisted && !homescreenApps.isEmpty()) {
- mModel.addAndBindAddedWorkspaceItems(homescreenApps);
+ mModel.addAndBindAddedWorkspaceItems(new ArrayList<ItemInfo>(homescreenApps));
}
}
@@ -173,7 +173,7 @@
}
// Add the item to home screen and DB. This also generates an item id synchronously.
- ArrayList<ItemInfo> itemList = new ArrayList<ItemInfo>(1);
+ ArrayList<ItemInfo> itemList = new ArrayList<>(1);
itemList.add(workFolder);
mModel.addAndBindAddedWorkspaceItems(itemList);
mPrefs.edit().putLong(folderIdKey, workFolder.id).apply();
diff --git a/src/com/android/launcher3/util/Provider.java b/src/com/android/launcher3/util/Provider.java
new file mode 100644
index 0000000..1cdd8d6
--- /dev/null
+++ b/src/com/android/launcher3/util/Provider.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+/**
+ * Utility class to allow lazy initialization of objects.
+ */
+public abstract class Provider<T> {
+
+ /**
+ * Initializes and returns the object. This may contain expensive operations not suitable
+ * to UI thread.
+ */
+ public abstract T get();
+
+ public static <T> Provider<T> of (final T value) {
+ return new Provider<T>() {
+ @Override
+ public T get() {
+ return value;
+ }
+ };
+ }
+}
diff --git a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
index ecb3782..b2f0cbb 100644
--- a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
+++ b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
@@ -15,6 +15,7 @@
import com.android.launcher3.config.ProviderConfig;
import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.LongArrayMap;
+import com.android.launcher3.util.Provider;
import org.mockito.ArgumentCaptor;
@@ -48,8 +49,8 @@
idp.numRows = 5;
}
- private <T extends ItemInfo> AddWorkspaceItemsTask newTask(T... items) {
- return new AddWorkspaceItemsTask(new ArrayList<>(Arrays.asList(items))) {
+ private AddWorkspaceItemsTask newTask(ItemInfo... items) {
+ return new AddWorkspaceItemsTask(Provider.of(Arrays.asList(items))) {
@Override
protected void addItemToDatabase(Context context, ItemInfo item,