Merge "Defining various modes for CellLayout: Workspace, Hotseat & Folder" into ub-launcher3-master
diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto
index 6b27559..33041db 100644
--- a/protos/launcher_log.proto
+++ b/protos/launcher_log.proto
@@ -63,6 +63,7 @@
FOLDER_ICON = 4;
DEEPSHORTCUT = 5;
SEARCHBOX = 6;
+ EDITTEXT = 7;
}
// Used to define what type of container a Target would represent.
@@ -91,7 +92,9 @@
APPINFO_TARGET = 7;
RESIZE_HANDLE = 8;
VERTICAL_SCROLL = 9;
- // HOME, BACK, GO_TO_PLAYSTORE
+ HOME_INTENT = 10; // Deprecated, use enum Command instead
+ BACK_BUTTON = 11; // Deprecated, use enum Command instead
+ // GO_TO_PLAYSTORE
}
// Used to define the action component of the LauncherEvent.
@@ -99,6 +102,7 @@
enum Type {
TOUCH = 0;
AUTOMATED = 1;
+ COMMAND = 2;
// SOFT_KEYBOARD, HARD_KEYBOARD, ASSIST
}
enum Touch {
@@ -116,9 +120,16 @@
LEFT = 3;
RIGHT = 4;
}
+ enum Command {
+ HOME_INTENT = 0;
+ BACK = 1;
+ }
optional Type type = 1;
optional Touch touch = 2;
optional Direction dir = 3;
+ optional Command command = 4;
+ // Log if the action was performed on outside of the container
+ optional bool is_outside = 5;
}
//
diff --git a/res/values/config.xml b/res/values/config.xml
index 5b3ee46..d270def 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -79,6 +79,9 @@
<!-- Name of an icon provider class. -->
<string name="icon_provider_class" translatable="false"></string>
+ <!-- Name of a drawable factory class. -->
+ <string name="drawable_factory_class" translatable="false"></string>
+
<!-- Package name of the default wallpaper picker. -->
<string name="wallpaper_picker_package" translatable="false"></string>
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/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index 8b5a8a8..2a4212a 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -17,7 +17,6 @@
package com.android.launcher3;
import android.appwidget.AppWidgetHost;
-import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
@@ -437,7 +436,8 @@
return -1;
}
- ItemInfo.writeBitmap(mValues, LauncherIcons.createIconBitmap(icon, mContext));
+ mValues.put(LauncherSettings.Favorites.ICON,
+ Utilities.flattenBitmap(LauncherIcons.createIconBitmap(icon, mContext)));
mValues.put(Favorites.ICON_PACKAGE, mIconRes.getResourcePackageName(iconId));
mValues.put(Favorites.ICON_RESOURCE, mIconRes.getResourceName(iconId));
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index dbb797d..51cd052 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -16,7 +16,6 @@
package com.android.launcher3;
-import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
@@ -26,9 +25,7 @@
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Region;
-import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.os.Build;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.util.TypedValue;
@@ -42,6 +39,7 @@
import com.android.launcher3.IconCache.IconLoadRequest;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.graphics.HolographicOutlineHelper;
import com.android.launcher3.model.PackageItemInfo;
@@ -190,7 +188,7 @@
}
private void applyIconAndLabel(Bitmap icon, ItemInfo info) {
- FastBitmapDrawable iconDrawable = mLauncher.createIconDrawable(icon);
+ FastBitmapDrawable iconDrawable = DrawableFactory.get(getContext()).newIcon(icon, info);
iconDrawable.setIsDisabled(info.isDisabled());
setIcon(iconDrawable);
setText(info.title);
@@ -202,15 +200,6 @@
}
/**
- * Used for measurement only, sets some dummy values on this view.
- */
- public void applyDummyInfo() {
- ColorDrawable d = new ColorDrawable();
- setIcon(mLauncher.resizeIconDrawable(d));
- setText("");
- }
-
- /**
* Overrides the default long press timeout.
*/
public void setLongPressTimeout(int longPressTimeout) {
@@ -528,12 +517,9 @@
/**
* Sets the icon for this view based on the layout direction.
*/
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void setIcon(Drawable icon) {
mIcon = icon;
- if (mIconSize != -1) {
- mIcon.setBounds(0, 0, mIconSize, mIconSize);
- }
+ mIcon.setBounds(0, 0, mIconSize, mIconSize);
applyCompoundDrawables(mIcon);
}
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index af22cfa..c0087c4 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -1045,7 +1045,7 @@
// Offsets due to the size difference between the View and the dragOutline.
// There is a size difference to account for the outer blur, which may lie
// outside the bounds of the view.
- top += (v.getHeight() - dragOutline.getHeight()) / 2;
+ top += ((mCellHeight * spanY) - dragOutline.getHeight()) / 2;
// We center about the x axis
left += ((mCellWidth * spanX) - dragOutline.getWidth()) / 2;
} else {
@@ -2696,6 +2696,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;
@@ -2706,8 +2718,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 b38109c..fbff4eb 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;
@@ -124,6 +125,9 @@
public int allAppsIconDrawablePaddingPx;
public float allAppsIconTextSizePx;
+ // Widgets
+ public final PointF appWidgetScale = new PointF(1.0f, 1.0f);
+
// Drop Target
public int dropTargetBarSizePx;
@@ -221,6 +225,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/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index 7eaae5a..0cefc57 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -94,7 +94,7 @@
private static final ColorMatrix sTempBrightnessMatrix = new ColorMatrix();
private static final ColorMatrix sTempFilterMatrix = new ColorMatrix();
- private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
+ protected final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
private final Bitmap mBitmap;
private State mState = State.NORMAL;
private boolean mIsDisabled;
@@ -116,6 +116,17 @@
@Override
public void draw(Canvas canvas) {
+ drawInternal(canvas);
+ }
+
+ public void drawWithBrightness(Canvas canvas, float brightness) {
+ float oldBrightness = getBrightness();
+ setBrightness(brightness);
+ drawInternal(canvas);
+ setBrightness(oldBrightness);
+ }
+
+ protected void drawInternal(Canvas canvas) {
canvas.drawBitmap(mBitmap, null, getBounds(), mPaint);
}
@@ -278,7 +289,7 @@
/**
* Sets the saturation of this icon, 0 [full color] -> 1 [desaturated]
*/
- public void setDesaturation(float desaturation) {
+ private void setDesaturation(float desaturation) {
int newDesaturation = (int) Math.floor(desaturation * REDUCED_FILTER_VALUE_SPACE);
if (mDesaturation != newDesaturation) {
mDesaturation = newDesaturation;
@@ -293,7 +304,7 @@
/**
* Sets the brightness of this icon, 0 [no add. brightness] -> 1 [2bright2furious]
*/
- public void setBrightness(float brightness) {
+ private void setBrightness(float brightness) {
int newBrightness = (int) Math.floor(brightness * REDUCED_FILTER_VALUE_SPACE);
if (mBrightness != newBrightness) {
mBrightness = newBrightness;
@@ -301,7 +312,7 @@
}
}
- public float getBrightness() {
+ private float getBrightness() {
return (float) mBrightness / REDUCED_FILTER_VALUE_SPACE;
}
@@ -364,7 +375,6 @@
private AnimatorSet cancelAnimator(AnimatorSet animator) {
if (animator != null) {
- animator.removeAllListeners();
animator.cancel();
}
return null;
diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java
index 8b70d1c..c244235 100644
--- a/src/com/android/launcher3/FolderInfo.java
+++ b/src/com/android/launcher3/FolderInfo.java
@@ -16,10 +16,10 @@
package com.android.launcher3;
-import android.content.ContentValues;
import android.content.Context;
import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.util.ContentWriter;
import java.util.ArrayList;
@@ -93,10 +93,10 @@
}
@Override
- void onAddToDatabase(Context context, ContentValues values) {
- super.onAddToDatabase(context, values);
- values.put(LauncherSettings.Favorites.TITLE, title.toString());
- values.put(LauncherSettings.Favorites.OPTIONS, options);
+ void onAddToDatabase(ContentWriter writer) {
+ super.onAddToDatabase(writer);
+ writer.put(LauncherSettings.Favorites.TITLE, title)
+ .put(LauncherSettings.Favorites.OPTIONS, options);
}
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 7cddabb..2c9ebba 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -128,14 +128,15 @@
if (!FeatureFlags.NO_ALL_APPS_ICON) {
// Add the Apps button
Context context = getContext();
- int allAppsButtonRank = mLauncher.getDeviceProfile().inv.getAllAppsButtonRank();
+ DeviceProfile grid = mLauncher.getDeviceProfile();
+ int allAppsButtonRank = grid.inv.getAllAppsButtonRank();
LayoutInflater inflater = LayoutInflater.from(context);
TextView allAppsButton = (TextView)
inflater.inflate(R.layout.all_apps_button, mContent, false);
Drawable d = context.getResources().getDrawable(R.drawable.all_apps_button_icon);
+ d.setBounds(0, 0, grid.iconSizePx, grid.iconSizePx);
- mLauncher.resizeIconDrawable(d);
int scaleDownPx = getResources().getDimensionPixelSize(R.dimen.all_apps_button_scale_down);
Rect bounds = d.getBounds();
d.setBounds(bounds.left, bounds.top + scaleDownPx / 2, bounds.right - scaleDownPx,
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 04d0c8c..db72b2f 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -494,7 +494,6 @@
shortcutInfo.setIcon(getDefaultIcon(user));
shortcutInfo.title = "";
shortcutInfo.contentDescription = "";
- shortcutInfo.usingFallbackIcon = true;
shortcutInfo.usingLowResIcon = false;
} else {
LauncherActivityInfoCompat info = mLauncherApps.resolveActivity(intent, user);
@@ -512,7 +511,6 @@
shortcutInfo.setIcon(getNonNullIcon(entry, user));
shortcutInfo.title = Utilities.trim(entry.title);
shortcutInfo.contentDescription = entry.contentDescription;
- shortcutInfo.usingFallbackIcon = isDefaultIcon(entry.icon, user);
shortcutInfo.usingLowResIcon = entry.isLowResIcon;
}
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index 056facb..46bc3b3 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -16,6 +16,8 @@
package com.android.launcher3;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -32,18 +34,24 @@
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.shortcuts.DeepShortcutManager;
+import com.android.launcher3.shortcuts.ShortcutInfoCompat;
+import com.android.launcher3.shortcuts.ShortcutKey;
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;
import org.json.JSONObject;
import org.json.JSONStringer;
-import org.json.JSONTokener;
import java.net.URISyntaxException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
public class InstallShortcutReceiver extends BroadcastReceiver {
@@ -60,6 +68,8 @@
private static final String ICON_RESOURCE_PACKAGE_NAME_KEY = "iconResourcePackage";
private static final String APP_SHORTCUT_TYPE_KEY = "isAppShortcut";
+ private static final String DEEPSHORTCUT_TYPE_KEY = "isDeepShortcut";
+ private static final String APP_WIDGET_TYPE_KEY = "isAppWidget";
private static final String USER_HANDLE_KEY = "userHandle";
// The set of shortcuts that are pending install
@@ -76,11 +86,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();
}
@@ -99,32 +105,37 @@
Log.d(TAG, "APPS_PENDING_INSTALL: " + strings
+ ", removing packages: " + packageNames);
}
- if (strings != null) {
- Set<String> newStrings = new HashSet<String>(strings);
- Iterator<String> newStringsIter = newStrings.iterator();
- while (newStringsIter.hasNext()) {
- String encoded = newStringsIter.next();
- PendingInstallShortcutInfo info = decode(encoded, context);
- if (info == null || (packageNames.contains(info.getTargetPackage())
- && user.equals(info.user))) {
+ if (Utilities.isEmpty(strings)) {
+ return;
+ }
+ Set<String> newStrings = new HashSet<>(strings);
+ Iterator<String> newStringsIter = newStrings.iterator();
+ while (newStringsIter.hasNext()) {
+ String encoded = newStringsIter.next();
+ try {
+ Decoder decoder = new Decoder(encoded, context);
+ if (packageNames.contains(getIntentPackage(decoder.launcherIntent)) &&
+ user.equals(decoder.user)) {
newStringsIter.remove();
}
+ } catch (JSONException | URISyntaxException e) {
+ Log.d(TAG, "Exception reading shortcut to add: " + e);
+ newStringsIter.remove();
}
- sp.edit().putStringSet(APPS_PENDING_INSTALL, newStrings).apply();
}
+ sp.edit().putStringSet(APPS_PENDING_INSTALL, newStrings).apply();
}
}
- 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) {
@@ -180,7 +191,8 @@
return null;
}
- PendingInstallShortcutInfo info = new PendingInstallShortcutInfo(data, context);
+ PendingInstallShortcutInfo info = new PendingInstallShortcutInfo(
+ data, UserHandleCompat.myUserHandle(), context);
if (info.launchIntent == null || info.label == null) {
if (DBG) Log.e(TAG, "Invalid install shortcut intent");
return null;
@@ -191,7 +203,36 @@
public static ShortcutInfo fromShortcutIntent(Context context, Intent data) {
PendingInstallShortcutInfo info = createPendingInfo(context, data);
- return info == null ? null : info.getShortcutInfo();
+ return info == null ? null : (ShortcutInfo) info.getItemInfo();
+ }
+
+ public static void queueShortcut(ShortcutInfoCompat info, Context context) {
+ queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, context), context);
+ }
+
+ public static void queueWidget(AppWidgetProviderInfo info, int widgetId, Context context) {
+ queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, widgetId, context), context);
+ }
+
+ public static HashSet<ShortcutKey> getPendingShortcuts(Context context) {
+ HashSet<ShortcutKey> result = new HashSet<>();
+
+ Set<String> strings = Utilities.getPrefs(context).getStringSet(APPS_PENDING_INSTALL, null);
+ if (Utilities.isEmpty(strings)) {
+ return result;
+ }
+
+ for (String encoded : strings) {
+ try {
+ Decoder decoder = new Decoder(encoded, context);
+ if (decoder.optBoolean(DEEPSHORTCUT_TYPE_KEY)) {
+ result.add(ShortcutKey.fromIntent(decoder.launcherIntent, decoder.user));
+ }
+ } catch (JSONException | URISyntaxException e) {
+ Log.d(TAG, "Exception reading shortcut to add: " + e);
+ }
+ }
+ return result;
}
private static void queuePendingShortcutInfo(PendingInstallShortcutInfo info, Context context) {
@@ -212,36 +253,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));
}
}
@@ -265,6 +282,8 @@
private static class PendingInstallShortcutInfo {
final LauncherActivityInfoCompat activityInfo;
+ final ShortcutInfoCompat shortcutInfo;
+ final AppWidgetProviderInfo providerInfo;
final Intent data;
final Context mContext;
@@ -275,32 +294,73 @@
/**
* Initializes a PendingInstallShortcutInfo received from a different app.
*/
- public PendingInstallShortcutInfo(Intent data, Context context) {
+ public PendingInstallShortcutInfo(Intent data, UserHandleCompat user, Context context) {
+ activityInfo = null;
+ shortcutInfo = null;
+ providerInfo = null;
+
this.data = data;
+ this.user = user;
mContext = context;
launchIntent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
label = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
- user = UserHandleCompat.myUserHandle();
- activityInfo = null;
+
}
/**
* Initializes a PendingInstallShortcutInfo to represent a launcher target.
*/
public PendingInstallShortcutInfo(LauncherActivityInfoCompat info, Context context) {
- this.data = null;
- mContext = context;
activityInfo = info;
+ shortcutInfo = null;
+ providerInfo = null;
+
+ data = null;
user = info.getUser();
+ mContext = context;
launchIntent = AppInfo.makeLaunchIntent(context, info, user);
label = info.getLabel().toString();
}
+ /**
+ * Initializes a PendingInstallShortcutInfo to represent a launcher target.
+ */
+ public PendingInstallShortcutInfo(ShortcutInfoCompat info, Context context) {
+ activityInfo = null;
+ shortcutInfo = info;
+ providerInfo = null;
+
+ data = null;
+ mContext = context;
+ user = info.getUserHandle();
+
+ launchIntent = info.makeIntent(context);
+ label = info.getShortLabel().toString();
+ }
+
+ /**
+ * Initializes a PendingInstallShortcutInfo to represent a launcher target.
+ */
+ public PendingInstallShortcutInfo(
+ AppWidgetProviderInfo info, int widgetId, Context context) {
+ activityInfo = null;
+ shortcutInfo = null;
+ providerInfo = info;
+
+ data = null;
+ mContext = context;
+ user = UserHandleCompat.fromUser(info.getProfile());
+
+ launchIntent = new Intent().setComponent(info.provider)
+ .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
+ label = info.label;
+ }
+
public String encodeToString() {
- if (activityInfo != null) {
- try {
+ try {
+ if (activityInfo != null) {
// If it a launcher target, we only need component name, and user to
// recreate this.
return new JSONStringer()
@@ -310,30 +370,45 @@
.key(USER_HANDLE_KEY).value(UserManagerCompat.getInstance(mContext)
.getSerialNumberForUser(user))
.endObject().toString();
- } catch (JSONException e) {
- Log.d(TAG, "Exception when adding shortcut: " + e);
- return null;
+ } else if (shortcutInfo != null) {
+ // If it a launcher target, we only need component name, and user to
+ // recreate this.
+ return new JSONStringer()
+ .object()
+ .key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0))
+ .key(DEEPSHORTCUT_TYPE_KEY).value(true)
+ .key(USER_HANDLE_KEY).value(UserManagerCompat.getInstance(mContext)
+ .getSerialNumberForUser(user))
+ .endObject().toString();
+ } else if (providerInfo != null) {
+ // If it a launcher target, we only need component name, and user to
+ // recreate this.
+ return new JSONStringer()
+ .object()
+ .key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0))
+ .key(APP_WIDGET_TYPE_KEY).value(true)
+ .key(USER_HANDLE_KEY).value(UserManagerCompat.getInstance(mContext)
+ .getSerialNumberForUser(user))
+ .endObject().toString();
}
- }
- if (launchIntent.getAction() == null) {
- launchIntent.setAction(Intent.ACTION_VIEW);
- } else if (launchIntent.getAction().equals(Intent.ACTION_MAIN) &&
- launchIntent.getCategories() != null &&
- launchIntent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
- launchIntent.addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- }
+ if (launchIntent.getAction() == null) {
+ launchIntent.setAction(Intent.ACTION_VIEW);
+ } else if (launchIntent.getAction().equals(Intent.ACTION_MAIN) &&
+ launchIntent.getCategories() != null &&
+ launchIntent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
+ launchIntent.addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ }
- // This name is only used for comparisons and notifications, so fall back to activity
- // name if not supplied
- String name = ensureValidName(mContext, launchIntent, label).toString();
- Bitmap icon = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
- Intent.ShortcutIconResource iconResource =
- data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
+ // This name is only used for comparisons and notifications, so fall back to activity
+ // name if not supplied
+ String name = ensureValidName(mContext, launchIntent, label).toString();
+ Bitmap icon = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
+ Intent.ShortcutIconResource iconResource =
+ data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
- // Only encode the parameters which are supported by the API.
- try {
+ // Only encode the parameters which are supported by the API.
JSONStringer json = new JSONStringer()
.object()
.key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0))
@@ -352,57 +427,79 @@
return json.endObject().toString();
} catch (JSONException e) {
Log.d(TAG, "Exception when adding shortcut: " + e);
+ return null;
}
- return null;
}
- public ShortcutInfo getShortcutInfo() {
+ public ItemInfo getItemInfo() {
if (activityInfo != null) {
return new ShortcutInfo(activityInfo, mContext);
+ } else if (shortcutInfo != null) {
+ return new ShortcutInfo(shortcutInfo, mContext);
+ } else if (providerInfo != null) {
+ LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo
+ .fromProviderInfo(mContext, providerInfo);
+ LauncherAppWidgetInfo widgetInfo = new LauncherAppWidgetInfo(
+ launchIntent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 0),
+ info.provider);
+ InvariantDeviceProfile idp = LauncherAppState.getInstance()
+ .getInvariantDeviceProfile();
+ widgetInfo.minSpanX = info.minSpanX;
+ widgetInfo.minSpanY = info.minSpanY;
+ widgetInfo.spanX = Math.min(info.spanX, idp.numColumns);
+ widgetInfo.spanY = Math.min(info.spanY, idp.numRows);
+ return widgetInfo;
} else {
return LauncherAppState.getInstance().getModel().infoFromShortcutIntent(mContext, data);
}
}
- public String getTargetPackage() {
- String packageName = launchIntent.getPackage();
- if (packageName == null) {
- packageName = launchIntent.getComponent() == null ? null :
- launchIntent.getComponent().getPackageName();
- }
- return packageName;
- }
-
public boolean isLauncherActivity() {
return activityInfo != null;
}
}
+ private static String getIntentPackage(Intent intent) {
+ return intent.getComponent() == null
+ ? intent.getPackage() : intent.getComponent().getPackageName();
+ }
+
private static PendingInstallShortcutInfo decode(String encoded, Context context) {
try {
- JSONObject object = (JSONObject) new JSONTokener(encoded).nextValue();
- Intent launcherIntent = Intent.parseUri(object.getString(LAUNCH_INTENT_KEY), 0);
-
- if (object.optBoolean(APP_SHORTCUT_TYPE_KEY)) {
- // The is an internal launcher target shortcut.
- UserHandleCompat user = UserManagerCompat.getInstance(context)
- .getUserForSerialNumber(object.getLong(USER_HANDLE_KEY));
- if (user == null) {
+ Decoder decoder = new Decoder(encoded, context);
+ if (decoder.optBoolean(APP_SHORTCUT_TYPE_KEY)) {
+ LauncherActivityInfoCompat info = LauncherAppsCompat.getInstance(context)
+ .resolveActivity(decoder.launcherIntent, decoder.user);
+ return info == null ? null : new PendingInstallShortcutInfo(info, context);
+ } else if (decoder.optBoolean(DEEPSHORTCUT_TYPE_KEY)) {
+ DeepShortcutManager sm = DeepShortcutManager.getInstance(context);
+ List<ShortcutInfoCompat> si = sm.queryForFullDetails(
+ decoder.launcherIntent.getPackage(),
+ Arrays.asList(ShortcutInfoCompat.EXTRA_SHORTCUT_ID), decoder.user);
+ if (si.isEmpty()) {
+ return null;
+ } else {
+ return new PendingInstallShortcutInfo(si.get(0), context);
+ }
+ } else if (decoder.optBoolean(APP_WIDGET_TYPE_KEY)) {
+ int widgetId = decoder.launcherIntent
+ .getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 0);
+ AppWidgetProviderInfo info = AppWidgetManager.getInstance(context)
+ .getAppWidgetInfo(widgetId);
+ if (info == null || !info.provider.equals(decoder.launcherIntent.getComponent()) ||
+ !info.getProfile().equals(decoder.user.getUser())) {
return null;
}
-
- LauncherActivityInfoCompat info = LauncherAppsCompat.getInstance(context)
- .resolveActivity(launcherIntent, user);
- return info == null ? null : new PendingInstallShortcutInfo(info, context);
+ return new PendingInstallShortcutInfo(info, widgetId, context);
}
Intent data = new Intent();
- data.putExtra(Intent.EXTRA_SHORTCUT_INTENT, launcherIntent);
- data.putExtra(Intent.EXTRA_SHORTCUT_NAME, object.getString(NAME_KEY));
+ data.putExtra(Intent.EXTRA_SHORTCUT_INTENT, decoder.launcherIntent);
+ data.putExtra(Intent.EXTRA_SHORTCUT_NAME, decoder.getString(NAME_KEY));
- String iconBase64 = object.optString(ICON_KEY);
- String iconResourceName = object.optString(ICON_RESOURCE_NAME_KEY);
- String iconResourcePackageName = object.optString(ICON_RESOURCE_PACKAGE_NAME_KEY);
+ String iconBase64 = decoder.optString(ICON_KEY);
+ String iconResourceName = decoder.optString(ICON_RESOURCE_NAME_KEY);
+ String iconResourcePackageName = decoder.optString(ICON_RESOURCE_PACKAGE_NAME_KEY);
if (iconBase64 != null && !iconBase64.isEmpty()) {
byte[] iconArray = Base64.decode(iconBase64, Base64.DEFAULT);
Bitmap b = BitmapFactory.decodeByteArray(iconArray, 0, iconArray.length);
@@ -415,13 +512,29 @@
data.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource);
}
- return new PendingInstallShortcutInfo(data, context);
+ return new PendingInstallShortcutInfo(data, decoder.user, context);
} catch (JSONException | URISyntaxException e) {
Log.d(TAG, "Exception reading shortcut to add: " + e);
}
return null;
}
+ private static class Decoder extends JSONObject {
+ public final Intent launcherIntent;
+ public final UserHandleCompat user;
+
+ private Decoder(String encoded, Context context) throws JSONException, URISyntaxException {
+ super(encoded);
+ launcherIntent = Intent.parseUri(getString(LAUNCH_INTENT_KEY), 0);
+ user = has(USER_HANDLE_KEY) ? UserManagerCompat.getInstance(context)
+ .getUserForSerialNumber(getLong(USER_HANDLE_KEY))
+ : UserHandleCompat.myUserHandle();
+ if (user == null) {
+ throw new JSONException("Invalid user");
+ }
+ }
+ }
+
/**
* Tries to create a new PendingInstallShortcutInfo which represents the same target,
* but is an app target and not a shortcut.
@@ -445,4 +558,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 = getIntentPackage(pendingInfo.launchIntent);
+ 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.getItemInfo());
+ }
+ return installQueue;
+ }
+ }
}
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index 2043772..3e0ae4f 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -18,12 +18,10 @@
import android.content.ComponentName;
import android.content.ContentValues;
-import android.content.Context;
import android.content.Intent;
-import android.graphics.Bitmap;
import com.android.launcher3.compat.UserHandleCompat;
-import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.util.ContentWriter;
/**
* Represents an item in the launcher.
@@ -142,15 +140,15 @@
return getIntent() == null ? null : getIntent().getComponent();
}
- public void writeToValues(ContentValues values) {
- values.put(LauncherSettings.Favorites.ITEM_TYPE, itemType);
- values.put(LauncherSettings.Favorites.CONTAINER, container);
- values.put(LauncherSettings.Favorites.SCREEN, screenId);
- values.put(LauncherSettings.Favorites.CELLX, cellX);
- values.put(LauncherSettings.Favorites.CELLY, cellY);
- values.put(LauncherSettings.Favorites.SPANX, spanX);
- values.put(LauncherSettings.Favorites.SPANY, spanY);
- values.put(LauncherSettings.Favorites.RANK, rank);
+ public void writeToValues(ContentWriter writer) {
+ writer.put(LauncherSettings.Favorites.ITEM_TYPE, itemType)
+ .put(LauncherSettings.Favorites.CONTAINER, container)
+ .put(LauncherSettings.Favorites.SCREEN, screenId)
+ .put(LauncherSettings.Favorites.CELLX, cellX)
+ .put(LauncherSettings.Favorites.CELLY, cellY)
+ .put(LauncherSettings.Favorites.SPANX, spanX)
+ .put(LauncherSettings.Favorites.SPANY, spanY)
+ .put(LauncherSettings.Favorites.RANK, rank);
}
public void readFromValues(ContentValues values) {
@@ -166,26 +164,15 @@
/**
* Write the fields of this item to the DB
- *
- * @param context A context object to use for getting UserManagerCompat
- * @param values
*/
- void onAddToDatabase(Context context, ContentValues values) {
- writeToValues(values);
- long serialNumber = UserManagerCompat.getInstance(context).getSerialNumberForUser(user);
- values.put(LauncherSettings.Favorites.PROFILE_ID, serialNumber);
-
+ void onAddToDatabase(ContentWriter writer) {
if (screenId == Workspace.EXTRA_EMPTY_SCREEN_ID) {
// We should never persist an item on the extra empty screen.
throw new RuntimeException("Screen id should not be EXTRA_EMPTY_SCREEN_ID");
}
- }
- static void writeBitmap(ContentValues values, Bitmap bitmap) {
- if (bitmap != null) {
- byte[] data = Utilities.flattenBitmap(bitmap);
- values.put(LauncherSettings.Favorites.ICON, data);
- }
+ writeToValues(writer);
+ writer.put(LauncherSettings.Favorites.PROFILE_ID, user);
}
@Override
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 2f51054..9215024 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1470,9 +1470,7 @@
}
LauncherModel.addItemToDatabase(this, info, container, screenId, cellXY[0], cellXY[1]);
-
- mWorkspace.addInScreen(view, container, screenId, cellXY[0], cellXY[1], 1, 1,
- isWorkspaceLocked());
+ mWorkspace.addInScreen(view, info);
}
/**
@@ -1507,20 +1505,15 @@
hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
}
hostView.setVisibility(View.VISIBLE);
- addAppWidgetToWorkspace(hostView, launcherInfo, appWidgetInfo, isWorkspaceLocked());
+ prepareAppWidget(hostView, launcherInfo);
+ mWorkspace.addInScreen(hostView, launcherInfo);
}
- private void addAppWidgetToWorkspace(
- AppWidgetHostView hostView, LauncherAppWidgetInfo item,
- LauncherAppWidgetProviderInfo appWidgetInfo, boolean insert) {
+ private void prepareAppWidget(AppWidgetHostView hostView, LauncherAppWidgetInfo item) {
hostView.setTag(item);
item.onBindAppWidget(this, hostView);
-
hostView.setFocusable(true);
hostView.setOnFocusChangeListener(mFocusHandler);
-
- mWorkspace.addInScreen(hostView, item.container, item.screenId,
- item.cellX, item.cellY, item.spanX, item.spanY, insert);
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -1681,9 +1674,27 @@
// Can be cases where mWorkspace is null, this prevents a NPE
return;
}
- // In all these cases, only animate if we're already on home
+
+ // Note: There should be at most one log per method call. This is enforced implicitly
+ // by using if-else statements.
+ UserEventDispatcher ued = getUserEventDispatcher();
+
+ // TODO: Log this case.
mWorkspace.exitWidgetResizeMode();
+ AbstractFloatingView topOpenView = AbstractFloatingView.getTopOpenView(this);
+ if (topOpenView instanceof DeepShortcutsContainer) {
+ ued.logActionCommand(LauncherLogProto.Action.HOME_INTENT,
+ topOpenView.getExtendedTouchView(), LauncherLogProto.DEEPSHORTCUTS);
+ } else if (topOpenView instanceof Folder) {
+ ued.logActionCommand(LauncherLogProto.Action.HOME_INTENT,
+ ((Folder) topOpenView).getFolderIcon(), LauncherLogProto.FOLDER);
+ } else if (alreadyOnHome) {
+ ued.logActionCommand(LauncherLogProto.Action.HOME_INTENT,
+ mWorkspace.getState().containerType, mWorkspace.getCurrentPage());
+ }
+
+ // In all these cases, only animate if we're already on home
AbstractFloatingView.closeAllOpenViews(this, alreadyOnHome);
exitSpringLoadedDragMode();
@@ -2087,8 +2098,7 @@
// Create the view
FolderIcon newFolder =
FolderIcon.fromXml(R.layout.folder_icon, this, layout, folderInfo, mIconCache);
- mWorkspace.addInScreen(newFolder, container, screenId, cellX, cellY, 1, 1,
- isWorkspaceLocked());
+ mWorkspace.addInScreen(newFolder, folderInfo);
// Force measure the new folder icon
CellLayout parent = mWorkspace.getParentCellLayoutForView(newFolder);
parent.getShortcutsAndWidgets().measureChild(newFolder);
@@ -2187,20 +2197,34 @@
return;
}
+ // Note: There should be at most one log per method call. This is enforced implicitly
+ // by using if-else statements.
+ UserEventDispatcher ued = getUserEventDispatcher();
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this);
if (topView != null) {
if (topView.getActiveTextView() != null) {
topView.getActiveTextView().dispatchBackKey();
} else {
+ if (topView instanceof DeepShortcutsContainer) {
+ ued.logActionCommand(LauncherLogProto.Action.BACK,
+ topView.getExtendedTouchView(), LauncherLogProto.DEEPSHORTCUTS);
+ } else if (topView instanceof Folder) {
+ ued.logActionCommand(LauncherLogProto.Action.BACK,
+ ((Folder) topView).getFolderIcon(), LauncherLogProto.FOLDER);
+ }
topView.close(true);
}
} else if (isAppsViewVisible()) {
+ ued.logActionCommand(LauncherLogProto.Action.BACK, LauncherLogProto.ALLAPPS);
showWorkspace(true);
} else if (isWidgetsViewVisible()) {
+ ued.logActionCommand(LauncherLogProto.Action.BACK, LauncherLogProto.WIDGETS);
showOverviewMode(true);
} else if (mWorkspace.isInOverviewMode()) {
+ ued.logActionCommand(LauncherLogProto.Action.BACK, LauncherLogProto.OVERVIEW);
showWorkspace(true);
} else {
+ // TODO: Log this case.
mWorkspace.exitWidgetResizeMode();
// Back button is a no-op here, but give at least some feedback for the button press
@@ -2594,7 +2618,7 @@
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
String id = ((ShortcutInfo) info).getDeepShortcutId();
String packageName = intent.getPackage();
- LauncherAppState.getInstance().getShortcutManager().startShortcut(
+ DeepShortcutManager.getInstance(this).startShortcut(
packageName, id, intent.getSourceBounds(), optsBundle, info.user);
} else {
// Could be launching some bookkeeping activity
@@ -3272,25 +3296,25 @@
* Implementation of the method from LauncherModel.Callbacks.
*/
@Override
- public void bindItems(final ArrayList<ItemInfo> shortcuts, final int start, final int end,
+ public void bindItems(final ArrayList<ItemInfo> items, final int start, final int end,
final boolean forceAnimateIcons) {
Runnable r = new Runnable() {
public void run() {
- bindItems(shortcuts, start, end, forceAnimateIcons);
+ bindItems(items, start, end, forceAnimateIcons);
}
};
if (waitUntilResume(r)) {
return;
}
- // Get the list of added shortcuts and intersect them with the set of shortcuts here
+ // Get the list of added items and intersect them with the set of items here
final AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
final Collection<Animator> bounceAnims = new ArrayList<Animator>();
final boolean animateIcons = forceAnimateIcons && canRunNewAppsAnimation();
Workspace workspace = mWorkspace;
- long newShortcutsScreenId = -1;
+ long newItemsScreenId = -1;
for (int i = start; i < end; i++) {
- final ItemInfo item = shortcuts.get(i);
+ final ItemInfo item = items.get(i);
// Short circuit if we are loading dock items for a configuration which has no dock
if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
@@ -3302,15 +3326,33 @@
switch (item.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
+ case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: {
ShortcutInfo info = (ShortcutInfo) item;
view = createShortcut(info);
break;
- case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
+ }
+ case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: {
view = FolderIcon.fromXml(R.layout.folder_icon, this,
(ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),
(FolderInfo) item, mIconCache);
break;
+ }
+ case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: {
+ LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) item;
+ if (mIsSafeModeEnabled) {
+ view = new PendingAppWidgetHostView(this, info, mIconCache, true);
+ } else {
+ LauncherAppWidgetProviderInfo providerInfo =
+ mAppWidgetManager.getLauncherAppWidgetInfo(info.appWidgetId);
+ if (providerInfo == null) {
+ deleteWidgetInfo(info);
+ continue;
+ }
+ view = mAppWidgetHost.createView(this, info.appWidgetId, providerInfo);
+ }
+ prepareAppWidget((AppWidgetHostView) view, info);
+ break;
+ }
default:
throw new RuntimeException("Invalid Item Type");
}
@@ -3334,30 +3376,29 @@
}
}
}
- workspace.addInScreenFromBind(view, item.container, item.screenId, item.cellX,
- item.cellY, 1, 1);
+ workspace.addInScreenFromBind(view, item);
if (animateIcons) {
// Animate all the applications up now
view.setAlpha(0f);
view.setScaleX(0f);
view.setScaleY(0f);
bounceAnims.add(createNewAppBounceAnimation(view, i));
- newShortcutsScreenId = item.screenId;
+ newItemsScreenId = item.screenId;
}
}
if (animateIcons) {
// Animate to the correct page
- if (newShortcutsScreenId > -1) {
+ if (newItemsScreenId > -1) {
long currentScreenId = mWorkspace.getScreenIdForPageIndex(mWorkspace.getNextPage());
- final int newScreenIndex = mWorkspace.getPageIndexForScreenId(newShortcutsScreenId);
+ final int newScreenIndex = mWorkspace.getPageIndexForScreenId(newItemsScreenId);
final Runnable startBounceAnimRunnable = new Runnable() {
public void run() {
anim.playTogether(bounceAnims);
anim.start();
}
};
- if (newShortcutsScreenId != currentScreenId) {
+ if (newItemsScreenId != currentScreenId) {
// We post the animation slightly delayed to prevent slowdowns
// when we are loading right after we return to launcher.
mWorkspace.postDelayed(new Runnable() {
@@ -3377,15 +3418,6 @@
workspace.requestLayout();
}
- private void bindSafeModeWidget(LauncherAppWidgetInfo item) {
- PendingAppWidgetHostView view = new PendingAppWidgetHostView(this, item, true);
- view.updateIcon(mIconCache);
- view.updateAppWidget(null);
- view.setOnClickListener(this);
- addAppWidgetToWorkspace(view, item, null, false);
- mWorkspace.requestLayout();
- }
-
/**
* Add the views for a widget to the workspace.
*
@@ -3402,7 +3434,11 @@
}
if (mIsSafeModeEnabled) {
- bindSafeModeWidget(item);
+ PendingAppWidgetHostView view =
+ new PendingAppWidgetHostView(this, item, mIconCache, true);
+ prepareAppWidget(view, item);
+ mWorkspace.addInScreen(view, item);
+ mWorkspace.requestLayout();
return;
}
@@ -3490,6 +3526,7 @@
}
}
+ final AppWidgetHostView view;
if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
if (DEBUG_WIDGETS) {
Log.d(TAG, "bindAppWidget: id=" + item.appWidgetId + " belongs to component "
@@ -3505,16 +3542,12 @@
item.minSpanX = appWidgetInfo.minSpanX;
item.minSpanY = appWidgetInfo.minSpanY;
- addAppWidgetToWorkspace(
- mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo),
- item, appWidgetInfo, false);
+ view = mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo);
} else {
- PendingAppWidgetHostView view = new PendingAppWidgetHostView(this, item, false);
- view.updateIcon(mIconCache);
- view.updateAppWidget(null);
- view.setOnClickListener(this);
- addAppWidgetToWorkspace(view, item, null, false);
+ view = new PendingAppWidgetHostView(this, item, mIconCache, false);
}
+ prepareAppWidget(view, item);
+ mWorkspace.addInScreen(view, item);
mWorkspace.requestLayout();
if (DEBUG_WIDGETS) {
@@ -4004,24 +4037,6 @@
}
/**
- * Returns a FastBitmapDrawable with the icon, accurately sized.
- */
- public FastBitmapDrawable createIconDrawable(Bitmap icon) {
- FastBitmapDrawable d = new FastBitmapDrawable(icon);
- d.setFilterBitmap(true);
- resizeIconDrawable(d);
- return d;
- }
-
- /**
- * Resizes an icon drawable to the correct icon size.
- */
- public Drawable resizeIconDrawable(Drawable icon) {
- icon.setBounds(0, 0, mDeviceProfile.iconSizePx, mDeviceProfile.iconSizePx);
- return icon;
- }
-
- /**
* Prints out out state for debugging.
*/
public void dumpState() {
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 2a43aad..5937d78 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -28,8 +28,6 @@
import com.android.launcher3.config.ProviderConfig;
import com.android.launcher3.dynamicui.ExtractionUtils;
import com.android.launcher3.logging.FileLog;
-import com.android.launcher3.shortcuts.DeepShortcutManager;
-import com.android.launcher3.shortcuts.ShortcutCache;
import com.android.launcher3.util.ConfigMonitor;
import com.android.launcher3.util.TestingUtils;
import com.android.launcher3.util.Thunk;
@@ -44,7 +42,6 @@
@Thunk final LauncherModel mModel;
private final IconCache mIconCache;
private final WidgetPreviewLoader mWidgetCache;
- private final DeepShortcutManager mDeepShortcutManager;
@Thunk boolean mWallpaperChangedSinceLastCheck;
@@ -98,10 +95,9 @@
mInvariantDeviceProfile = new InvariantDeviceProfile(sContext);
mIconCache = new IconCache(sContext, mInvariantDeviceProfile);
mWidgetCache = new WidgetPreviewLoader(sContext, mIconCache);
- mDeepShortcutManager = new DeepShortcutManager(sContext, new ShortcutCache());
mAppFilter = AppFilter.loadByName(sContext.getString(R.string.app_filter_class));
- mModel = new LauncherModel(this, mIconCache, mAppFilter, mDeepShortcutManager);
+ mModel = new LauncherModel(this, mIconCache, mAppFilter);
LauncherAppsCompat.getInstance(sContext).addOnAppsChangedCallback(mModel);
@@ -173,10 +169,6 @@
return mWidgetCache;
}
- public DeepShortcutManager getShortcutManager() {
- return mDeepShortcutManager;
- }
-
public boolean hasWallpaperChangedSinceLastCheck() {
boolean result = mWallpaperChangedSinceLastCheck;
mWallpaperChangedSinceLastCheck = false;
diff --git a/src/com/android/launcher3/LauncherAppWidgetInfo.java b/src/com/android/launcher3/LauncherAppWidgetInfo.java
index 78f5b8e..2218767 100644
--- a/src/com/android/launcher3/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetInfo.java
@@ -18,11 +18,10 @@
import android.appwidget.AppWidgetHostView;
import android.content.ComponentName;
-import android.content.ContentValues;
-import android.content.Context;
import android.content.Intent;
import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.util.ContentWriter;
/**
* Represents a widget (either instantiated or about to be) in the Launcher.
@@ -127,13 +126,12 @@
}
@Override
- void onAddToDatabase(Context context, ContentValues values) {
- super.onAddToDatabase(context, values);
- values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
- values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER, providerName.flattenToString());
- values.put(LauncherSettings.Favorites.RESTORED, restoreStatus);
- values.put(LauncherSettings.Favorites.INTENT,
- bindOptions == null ? null : bindOptions.toUri(0));
+ void onAddToDatabase(ContentWriter writer) {
+ super.onAddToDatabase(writer);
+ writer.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId)
+ .put(LauncherSettings.Favorites.APPWIDGET_PROVIDER, providerName.flattenToString())
+ .put(LauncherSettings.Favorites.RESTORED, restoreStatus)
+ .put(LauncherSettings.Favorites.INTENT, bindOptions);
}
/**
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index c70a475..cc56d43 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -76,6 +76,7 @@
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.ContentWriter;
import com.android.launcher3.util.CursorIconInfo;
import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.ItemInfoMatcher;
@@ -84,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;
@@ -155,7 +157,8 @@
@Override
public void run() {
if (mDeepShortcutsLoaded) {
- boolean hasShortcutHostPermission = mDeepShortcutManager.hasHostPermission();
+ boolean hasShortcutHostPermission =
+ DeepShortcutManager.getInstance(mApp.getContext()).hasHostPermission();
if (hasShortcutHostPermission != mHasShortcutHostPermission) {
mApp.reloadWorkspace();
}
@@ -172,7 +175,6 @@
// </ only access in worker thread >
private final IconCache mIconCache;
- private final DeepShortcutManager mDeepShortcutManager;
private final LauncherAppsCompat mLauncherApps;
private final UserManagerCompat mUserManager;
@@ -209,14 +211,12 @@
public void bindDeepShortcutMap(MultiHashMap<ComponentKey, String> deepShortcutMap);
}
- LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter,
- DeepShortcutManager deepShortcutManager) {
+ LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {
Context context = app.getContext();
mApp = app;
mBgAllAppsList = new AllAppsList(iconCache, appFilter);
mBgWidgetsModel = new WidgetsModel(iconCache, appFilter);
mIconCache = iconCache;
- mDeepShortcutManager = deepShortcutManager;
mLauncherApps = LauncherAppsCompat.getInstance(context);
mUserManager = UserManagerCompat.getInstance(context);
@@ -261,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));
}
/**
@@ -332,7 +339,7 @@
runOnWorkerThread(r);
}
- static void updateItemInDatabaseHelper(Context context, final ContentValues values,
+ static void updateItemInDatabaseHelper(Context context, final ContentWriter writer,
final ItemInfo item, final String callingFunction) {
final long itemId = item.id;
final Uri uri = LauncherSettings.Favorites.getContentUri(itemId);
@@ -341,7 +348,7 @@
final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
Runnable r = new Runnable() {
public void run() {
- cr.update(uri, values, null, null);
+ cr.update(uri, writer.getValues(), null, null);
updateItemArrays(item, itemId, stackTrace);
}
};
@@ -439,14 +446,14 @@
item.screenId = screenId;
}
- final ContentValues values = new ContentValues();
- values.put(LauncherSettings.Favorites.CONTAINER, item.container);
- values.put(LauncherSettings.Favorites.CELLX, item.cellX);
- values.put(LauncherSettings.Favorites.CELLY, item.cellY);
- values.put(LauncherSettings.Favorites.RANK, item.rank);
- values.put(LauncherSettings.Favorites.SCREEN, item.screenId);
+ final ContentWriter writer = new ContentWriter(context)
+ .put(LauncherSettings.Favorites.CONTAINER, item.container)
+ .put(LauncherSettings.Favorites.CELLX, item.cellX)
+ .put(LauncherSettings.Favorites.CELLY, item.cellY)
+ .put(LauncherSettings.Favorites.RANK, item.rank)
+ .put(LauncherSettings.Favorites.SCREEN, item.screenId);
- updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");
+ updateItemInDatabaseHelper(context, writer, item, "moveItemInDatabase");
}
/**
@@ -506,25 +513,25 @@
item.screenId = screenId;
}
- final ContentValues values = new ContentValues();
- values.put(LauncherSettings.Favorites.CONTAINER, item.container);
- values.put(LauncherSettings.Favorites.CELLX, item.cellX);
- values.put(LauncherSettings.Favorites.CELLY, item.cellY);
- values.put(LauncherSettings.Favorites.RANK, item.rank);
- values.put(LauncherSettings.Favorites.SPANX, item.spanX);
- values.put(LauncherSettings.Favorites.SPANY, item.spanY);
- values.put(LauncherSettings.Favorites.SCREEN, item.screenId);
+ final ContentWriter writer = new ContentWriter(context)
+ .put(LauncherSettings.Favorites.CONTAINER, item.container)
+ .put(LauncherSettings.Favorites.CELLX, item.cellX)
+ .put(LauncherSettings.Favorites.CELLY, item.cellY)
+ .put(LauncherSettings.Favorites.RANK, item.rank)
+ .put(LauncherSettings.Favorites.SPANX, item.spanX)
+ .put(LauncherSettings.Favorites.SPANY, item.spanY)
+ .put(LauncherSettings.Favorites.SCREEN, item.screenId);
- updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase");
+ updateItemInDatabaseHelper(context, writer, item, "modifyItemInDatabase");
}
/**
* Update an item to the database in a specified container.
*/
public static void updateItemInDatabase(Context context, final ItemInfo item) {
- final ContentValues values = new ContentValues();
- item.onAddToDatabase(context, values);
- updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");
+ ContentWriter writer = new ContentWriter(context);
+ item.onAddToDatabase(writer);
+ updateItemInDatabaseHelper(context, writer, item, "updateItemInDatabase");
}
/**
@@ -546,19 +553,19 @@
item.screenId = screenId;
}
- final ContentValues values = new ContentValues();
+ final ContentWriter writer = new ContentWriter(context);
final ContentResolver cr = context.getContentResolver();
- item.onAddToDatabase(context, values);
+ item.onAddToDatabase(writer);
item.id = LauncherSettings.Settings.call(cr, LauncherSettings.Settings.METHOD_NEW_ITEM_ID)
.getLong(LauncherSettings.Settings.EXTRA_VALUE);
- values.put(LauncherSettings.Favorites._ID, item.id);
+ writer.put(LauncherSettings.Favorites._ID, item.id);
final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
Runnable r = new Runnable() {
public void run() {
- cr.insert(LauncherSettings.Favorites.CONTENT_URI, values);
+ cr.insert(LauncherSettings.Favorites.CONTENT_URI, writer.getValues());
synchronized (sBgDataModel) {
checkItemInfoLocked(item.id, item, stackTrace);
@@ -1190,6 +1197,7 @@
final PackageManager manager = context.getPackageManager();
final boolean isSafeMode = manager.isSafeMode();
final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
+ final DeepShortcutManager shortcutManager = DeepShortcutManager.getInstance(context);
final boolean isSdCardReady = Utilities.isBootCompleted();
final MultiHashMap<UserHandleCompat, String> pendingPackages = new MultiHashMap<>();
@@ -1287,8 +1295,8 @@
// We can only query for shortcuts when the user is unlocked.
if (userUnlocked) {
List<ShortcutInfoCompat> pinnedShortcuts =
- mDeepShortcutManager.queryForPinnedShortcuts(null, user);
- if (mDeepShortcutManager.wasLastCallSuccess()) {
+ shortcutManager.queryForPinnedShortcuts(null, user);
+ if (shortcutManager.wasLastCallSuccess()) {
for (ShortcutInfoCompat shortcut : pinnedShortcuts) {
shortcutKeyToPinnedShortcuts.put(ShortcutKey.fromInfo(shortcut),
shortcut);
@@ -1768,11 +1776,14 @@
}
// Unpin shortcuts that don't exist on the workspace.
+ HashSet<ShortcutKey> pendingShortcuts =
+ InstallShortcutReceiver.getPendingShortcuts(context);
for (ShortcutKey key : shortcutKeyToPinnedShortcuts.keySet()) {
MutableInt numTimesPinned = sBgDataModel.pinnedShortcutCounts.get(key);
- if (numTimesPinned == null || numTimesPinned.value == 0) {
+ if ((numTimesPinned == null || numTimesPinned.value == 0)
+ && !pendingShortcuts.contains(key)) {
// Shortcut is pinned but doesn't exist on the workspace; unpin it.
- mDeepShortcutManager.unpinShortcut(key);
+ shortcutManager.unpinShortcut(key);
}
}
@@ -2325,12 +2336,13 @@
}
if (!mDeepShortcutsLoaded) {
sBgDataModel.deepShortcutMap.clear();
- mHasShortcutHostPermission = mDeepShortcutManager.hasHostPermission();
+ DeepShortcutManager shortcutManager = DeepShortcutManager.getInstance(mContext);
+ mHasShortcutHostPermission = shortcutManager.hasHostPermission();
if (mHasShortcutHostPermission) {
for (UserHandleCompat user : mUserManager.getUserProfiles()) {
if (mUserManager.isUserUnlocked(user)) {
- List<ShortcutInfoCompat> shortcuts = mDeepShortcutManager
- .queryForAllShortcuts(user);
+ List<ShortcutInfoCompat> shortcuts =
+ shortcutManager.queryForAllShortcuts(user);
sBgDataModel.updateDeepShortcutMap(null, user, shortcuts);
}
}
@@ -2632,7 +2644,6 @@
// the fallback icon
if (icon == null) {
icon = mIconCache.getDefaultIcon(info.user);
- info.usingFallbackIcon = true;
}
info.setIcon(icon);
}
@@ -2669,7 +2680,6 @@
info.user = UserHandleCompat.myUserHandle();
if (icon == null) {
icon = mIconCache.getDefaultIcon(info.user);
- info.usingFallbackIcon = true;
}
info.setIcon(icon);
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/PendingAppWidgetHostView.java b/src/com/android/launcher3/PendingAppWidgetHostView.java
index bf39774..7c92f80 100644
--- a/src/com/android/launcher3/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/PendingAppWidgetHostView.java
@@ -36,6 +36,8 @@
import android.view.View;
import android.view.View.OnClickListener;
+import com.android.launcher3.graphics.DrawableFactory;
+
public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implements OnClickListener {
private static final float SETUP_ICON_SIZE_FACTOR = 2f / 5;
private static final float MIN_SATUNATION = 0.7f;
@@ -63,7 +65,7 @@
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public PendingAppWidgetHostView(Context context, LauncherAppWidgetInfo info,
- boolean disabledForSafeMode) {
+ IconCache cache, boolean disabledForSafeMode) {
super(new ContextThemeWrapper(context, R.style.WidgetContainerTheme));
mLauncher = Launcher.getLauncher(context);
@@ -82,6 +84,10 @@
if (Utilities.ATLEAST_LOLLIPOP) {
setElevation(getResources().getDimension(R.dimen.pending_widget_elevation));
}
+
+ updateIcon(cache);
+ updateAppWidget(null);
+ setOnClickListener(mLauncher);
}
@Override
@@ -117,7 +123,7 @@
mDrawableSizeChanged = true;
}
- public void updateIcon(IconCache cache) {
+ private void updateIcon(IconCache cache) {
Bitmap icon = cache.getIcon(mIconLookupIntent, mInfo.user);
if (mIcon == icon) {
return;
@@ -132,13 +138,14 @@
// 1) App icon in the center
// 2) Preload icon in the center
// 3) Setup icon in the center and app icon in the top right corner.
+ DrawableFactory drawableFactory = DrawableFactory.get(getContext());
if (mDisabledForSafeMode) {
- FastBitmapDrawable disabledIcon = mLauncher.createIconDrawable(mIcon);
+ FastBitmapDrawable disabledIcon = drawableFactory.newIcon(mIcon, mInfo);
disabledIcon.setIsDisabled(true);
mCenterDrawable = disabledIcon;
mSettingIconDrawable = null;
} else if (isReadyForClickSetup()) {
- mCenterDrawable = new FastBitmapDrawable(mIcon);
+ mCenterDrawable = drawableFactory.newIcon(mIcon, mInfo);
mSettingIconDrawable = getResources().getDrawable(R.drawable.ic_setting).mutate();
updateSettingColor();
@@ -148,7 +155,7 @@
sPreloaderTheme.applyStyle(R.style.PreloadIcon, true);
}
- FastBitmapDrawable drawable = mLauncher.createIconDrawable(mIcon);
+ FastBitmapDrawable drawable = drawableFactory.newIcon(mIcon, mInfo);
mCenterDrawable = new PreloadIconDrawable(drawable, sPreloaderTheme);
mCenterDrawable.setCallback(this);
mSettingIconDrawable = null;
diff --git a/src/com/android/launcher3/PinchAnimationManager.java b/src/com/android/launcher3/PinchAnimationManager.java
index c1d60fd..41074be 100644
--- a/src/com/android/launcher3/PinchAnimationManager.java
+++ b/src/com/android/launcher3/PinchAnimationManager.java
@@ -215,9 +215,18 @@
view.setVisibility(View.VISIBLE);
} else {
animator.addListener(new AnimatorListenerAdapter() {
+ private boolean mCancelled = false;
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+
@Override
public void onAnimationEnd(Animator animation) {
- view.setVisibility(View.INVISIBLE);
+ if (!mCancelled) {
+ view.setVisibility(View.INVISIBLE);
+ }
}
});
}
@@ -226,7 +235,6 @@
private void startAnimator(int index, Animator animator, long duration) {
if (mAnimators[index] != null) {
- mAnimators[index].removeAllListeners();
mAnimators[index].cancel();
}
mAnimators[index] = animator;
diff --git a/src/com/android/launcher3/PreloadIconDrawable.java b/src/com/android/launcher3/PreloadIconDrawable.java
index efc0eac..973e688 100644
--- a/src/com/android/launcher3/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/PreloadIconDrawable.java
@@ -177,8 +177,9 @@
// Set the paint color only when the level changes, so that the dominant color
// is only calculated when needed.
mPaint.setColor(getIndicatorColor());
- } else if (mIcon instanceof FastBitmapDrawable) {
- ((FastBitmapDrawable) mIcon).setIsDisabled(true);
+ }
+ if (mIcon instanceof FastBitmapDrawable) {
+ ((FastBitmapDrawable) mIcon).setIsDisabled(level < 100);
}
invalidateSelf();
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 9568d57..6c73762 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.view.View;
import android.view.ViewGroup;
@@ -100,20 +101,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 {
@@ -138,6 +139,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/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index fc08736..d6d03d3 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -18,7 +18,6 @@
import android.annotation.TargetApi;
import android.content.ComponentName;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
@@ -32,7 +31,9 @@
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
+import com.android.launcher3.util.ContentWriter;
/**
* Represents a launchable icon on the workspaces and in folders.
@@ -77,12 +78,6 @@
public Intent intent;
/**
- * Indicates whether we're using the default fallback icon instead of something from the
- * app.
- */
- public boolean usingFallbackIcon;
-
- /**
* Indicates whether we're using a low res icon
*/
boolean usingLowResIcon;
@@ -187,7 +182,6 @@
status = info.status;
mInstallProgress = info.mInstallProgress;
isDisabled = info.isDisabled;
- usingFallbackIcon = info.usingFallbackIcon;
}
/** TODO: Remove this. It's only called by ApplicationInfo.makeShortcut. */
@@ -240,25 +234,19 @@
}
@Override
- void onAddToDatabase(Context context, ContentValues values) {
- super.onAddToDatabase(context, values);
+ void onAddToDatabase(ContentWriter writer) {
+ super.onAddToDatabase(writer);
+ writer.put(LauncherSettings.BaseLauncherColumns.TITLE, title)
+ .put(LauncherSettings.BaseLauncherColumns.INTENT, getPromisedIntent())
+ .put(LauncherSettings.Favorites.RESTORED, status);
- String titleStr = title != null ? title.toString() : null;
- values.put(LauncherSettings.BaseLauncherColumns.TITLE, titleStr);
-
- String uri = promisedIntent != null ? promisedIntent.toUri(0)
- : (intent != null ? intent.toUri(0) : null);
- values.put(LauncherSettings.BaseLauncherColumns.INTENT, uri);
- values.put(LauncherSettings.Favorites.RESTORED, status);
-
- if (!usingFallbackIcon && !usingLowResIcon) {
- writeBitmap(values, mIcon);
+ if (!usingLowResIcon) {
+ writer.putIcon(mIcon, user);
}
if (iconResource != null) {
- values.put(LauncherSettings.BaseLauncherColumns.ICON_PACKAGE,
- iconResource.packageName);
- values.put(LauncherSettings.BaseLauncherColumns.ICON_RESOURCE,
- iconResource.resourceName);
+ writer.put(LauncherSettings.BaseLauncherColumns.ICON_PACKAGE, iconResource.packageName)
+ .put(LauncherSettings.BaseLauncherColumns.ICON_RESOURCE,
+ iconResource.resourceName);
}
}
@@ -308,7 +296,7 @@
// TODO: Use cache for this
LauncherAppState launcherAppState = LauncherAppState.getInstance();
- Drawable unbadgedDrawable = launcherAppState.getShortcutManager()
+ Drawable unbadgedDrawable = DeepShortcutManager.getInstance(context)
.getShortcutIconDrawable(shortcutInfo,
launcherAppState.getInvariantDeviceProfile().fillResIconDpi);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 01d87f4..10680b4 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -48,7 +48,6 @@
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityManager;
-import android.view.animation.Animation.AnimationListener;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.TextView;
@@ -183,18 +182,20 @@
// in all apps or customize mode)
public enum State {
- NORMAL (false, false),
- NORMAL_HIDDEN (false, false),
- SPRING_LOADED (false, true),
- OVERVIEW (true, true),
- OVERVIEW_HIDDEN (true, false);
+ NORMAL (false, false, LauncherLogProto.WORKSPACE),
+ NORMAL_HIDDEN (false, false, LauncherLogProto.ALLAPPS),
+ SPRING_LOADED (false, true, LauncherLogProto.WORKSPACE),
+ OVERVIEW (true, true, LauncherLogProto.OVERVIEW),
+ OVERVIEW_HIDDEN (true, false, LauncherLogProto.WIDGETS);
public final boolean shouldUpdateWidget;
public final boolean hasMultipleVisiblePages;
+ public final int containerType;
- State(boolean shouldUpdateWidget, boolean hasMultipleVisiblePages) {
+ State(boolean shouldUpdateWidget, boolean hasMultipleVisiblePages, int containerType) {
this.shouldUpdateWidget = shouldUpdateWidget;
this.hasMultipleVisiblePages = hasMultipleVisiblePages;
+ this.containerType = containerType;
}
}
@@ -1042,23 +1043,28 @@
}
}
- // See implementation for parameter definition.
- void addInScreen(View child, long container, long screenId,
- int x, int y, int spanX, int spanY) {
- addInScreen(child, container, screenId, x, y, spanX, spanY, false, false);
+ /**
+ * At bind time, we use the rank (screenId) to compute x and y for hotseat items.
+ * See {@link #addInScreen}.
+ */
+ public void addInScreenFromBind(View child, ItemInfo info) {
+ int x = info.cellX;
+ int y = info.cellY;
+ if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
+ int screenId = (int) info.screenId;
+ x = mLauncher.getHotseat().getCellXFromOrder(screenId);
+ y = mLauncher.getHotseat().getCellYFromOrder(screenId);
+ }
+ addInScreen(child, info.container, info.screenId, x, y, info.spanX, info.spanY);
}
- // At bind time, we use the rank (screenId) to compute x and y for hotseat items.
- // See implementation for parameter definition.
- public void addInScreenFromBind(View child, long container, long screenId, int x, int y,
- int spanX, int spanY) {
- addInScreen(child, container, screenId, x, y, spanX, spanY, false, true);
- }
-
- // See implementation for parameter definition.
- void addInScreen(View child, long container, long screenId, int x, int y, int spanX, int spanY,
- boolean insert) {
- addInScreen(child, container, screenId, x, y, spanX, spanY, insert, false);
+ /**
+ * Adds the specified child in the specified screen based on the {@param info}
+ * See {@link #addInScreen}.
+ */
+ public void addInScreen(View child, ItemInfo info) {
+ addInScreen(child, info.container, info.screenId, info.cellX, info.cellY,
+ info.spanX, info.spanY);
}
/**
@@ -1071,13 +1077,9 @@
* @param y The Y position of the child in the screen's grid.
* @param spanX The number of cells spanned horizontally by the child.
* @param spanY The number of cells spanned vertically by the child.
- * @param insert When true, the child is inserted at the beginning of the children list.
- * @param computeXYFromRank When true, we use the rank (stored in screenId) to compute
- * the x and y position in which to place hotseat items. Otherwise
- * we use the x and y position to compute the rank.
*/
- void addInScreen(View child, long container, long screenId, int x, int y, int spanX, int spanY,
- boolean insert, boolean computeXYFromRank) {
+ private void addInScreen(View child, long container, long screenId, int x, int y,
+ int spanX, int spanY) {
if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
if (getScreenWithId(screenId) == null) {
Log.e(TAG, "Skipping child, screenId " + screenId + " not found");
@@ -1100,13 +1102,6 @@
if (child instanceof FolderIcon) {
((FolderIcon) child).setTextVisible(false);
}
-
- if (computeXYFromRank) {
- x = mLauncher.getHotseat().getCellXFromOrder((int) screenId);
- y = mLauncher.getHotseat().getCellYFromOrder((int) screenId);
- } else {
- screenId = mLauncher.getHotseat().getOrderInHotseat(x, y);
- }
} else {
// Show folder title if not in the hotseat
if (child instanceof FolderIcon) {
@@ -1137,7 +1132,7 @@
int childId = mLauncher.getViewIdForItem(info);
boolean markCellsAsOccupied = !(child instanceof Folder);
- if (!layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) {
+ if (!layout.addViewToCellLayout(child, -1, childId, lp, markCellsAsOccupied)) {
// TODO: This branch occurs when the workspace is adding views
// outside of the defined grid
// maybe we should be deleting these items from the LauncherModel?
@@ -1969,7 +1964,7 @@
CellLayout cl = ((CellLayout) getChildAt(i));
mScreenOrder.add(getIdForScreen(cl));
}
-
+ mLauncher.getUserEventDispatcher().logOverviewReorder();
mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);
// Re-enable auto layout transitions for page deletion.
@@ -2054,7 +2049,7 @@
StateTransitionListener listener = new StateTransitionListener();
if (animated) {
ValueAnimator stepAnimator = ValueAnimator.ofFloat(0, 1);
- stepAnimator.addListener(listener);
+ stepAnimator.addUpdateListener(listener);
workspaceAnim.play(stepAnimator);
workspaceAnim.addListener(listener);
@@ -2518,7 +2513,7 @@
if (d.dragSource != this) {
final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0],
(int) mDragViewVisualCenter[1] };
- onDropExternal(touchXY, d.dragInfo, dropTargetLayout, false, d);
+ onDropExternal(touchXY, d.dragInfo, dropTargetLayout, d);
} else if (mDragInfo != null) {
final View cell = mDragInfo.cell;
boolean droppedOnOriginalCellDuringTransition = false;
@@ -3264,7 +3259,7 @@
* to add an item to one of the workspace screens.
*/
private void onDropExternal(final int[] touchXY, final ItemInfo dragInfo,
- final CellLayout cellLayout, boolean insertAtFirst, DragObject d) {
+ final CellLayout cellLayout, DragObject d) {
final Runnable exitSpringLoadedRunnable = new Runnable() {
@Override
public void run() {
@@ -3414,8 +3409,8 @@
LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId,
mTargetCell[0], mTargetCell[1]);
- addInScreen(view, container, screenId, mTargetCell[0], mTargetCell[1], info.spanX,
- info.spanY, insertAtFirst);
+ addInScreen(view, container, screenId, mTargetCell[0], mTargetCell[1],
+ info.spanX, info.spanY);
cellLayout.onDropChild(view);
cellLayout.getShortcutsAndWidgets().measureChild(view);
@@ -3466,14 +3461,14 @@
mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(layout, loc, true);
resetTransitionTransform(layout);
- float dragViewScaleX;
- float dragViewScaleY;
+ float dragViewScaleX = 1f;
+ float dragViewScaleY = 1f;
if (scale) {
- dragViewScaleX = (1.0f * r.width()) / dragView.getMeasuredWidth();
- dragViewScaleY = (1.0f * r.height()) / dragView.getMeasuredHeight();
- } else {
- dragViewScaleX = 1f;
- dragViewScaleY = 1f;
+ float width = info.spanX * layout.mCellWidth;
+ float height = info.spanY * layout.mCellHeight;
+
+ dragViewScaleX = r.width() / width;
+ dragViewScaleY = r.height() / height;
}
// The animation will scale the dragView about its center, so we need to center about
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 1f36468..6a71bef 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -356,7 +356,8 @@
cl.setShortcutAndWidgetAlpha(finalAlpha);
}
- if (Workspace.isQsbContainerPage(i)) {
+ if (Workspace.isQsbContainerPage(i) &&
+ states.stateIsNormal && mWorkspaceFadeInAdjacentScreens) {
if (animated) {
Animator anim = mWorkspace.mQsbAlphaController
.animateAlphaAtIndex(finalAlpha, Workspace.QSB_ALPHA_INDEX_PAGE_SCROLL);
@@ -372,8 +373,6 @@
final ViewGroup overviewPanel = mLauncher.getOverviewPanel();
- final View qsbContainer = mLauncher.getQsbContainer();
-
Animator qsbAlphaAnimation = mWorkspace.mQsbAlphaController
.animateAlphaAtIndex(finalQsbAlpha, Workspace.QSB_ALPHA_INDEX_STATE_CHANGE);
@@ -395,7 +394,7 @@
// For animation optimization, we may need to provide the Launcher transition
// with a set of views on which to force build and manage layers in certain scenarios.
layerViews.addView(overviewPanel);
- layerViews.addView(qsbContainer);
+ layerViews.addView(mLauncher.getQsbContainer());
layerViews.addView(mLauncher.getHotseat());
layerViews.addView(mWorkspace.getPageIndicator());
diff --git a/src/com/android/launcher3/allapps/AllAppsBackgroundDrawable.java b/src/com/android/launcher3/allapps/AllAppsBackgroundDrawable.java
index cfd07e6..bc602f3 100644
--- a/src/com/android/launcher3/allapps/AllAppsBackgroundDrawable.java
+++ b/src/com/android/launcher3/allapps/AllAppsBackgroundDrawable.java
@@ -188,7 +188,6 @@
private ObjectAnimator cancelAnimator(ObjectAnimator animator) {
if (animator != null) {
- animator.removeAllListeners();
animator.cancel();
}
return null;
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 53c12b5..a81b4ca 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -79,7 +79,6 @@
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.pageindicators.PageIndicatorDots;
-import com.android.launcher3.shortcuts.DeepShortcutsContainer;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.util.CircleRevealOutlineProvider;
@@ -388,6 +387,10 @@
return isEditingName() ? mFolderName : null;
}
+ public FolderIcon getFolderIcon() {
+ return mFolderIcon;
+ }
+
/**
* We need to handle touch events to prevent them from falling through to the workspace below.
*/
@@ -1222,8 +1225,7 @@
// We add the child after removing the folder to prevent both from existing
// at the same time in the CellLayout. We need to add the new item with
// addInScreenFromBind() to ensure that hotseat items are placed correctly.
- mLauncher.getWorkspace().addInScreenFromBind(newIcon, mInfo.container,
- mInfo.screenId, mInfo.cellX, mInfo.cellY, mInfo.spanX, mInfo.spanY);
+ mLauncher.getWorkspace().addInScreenFromBind(newIcon, mInfo);
// Focus the newly created child
newIcon.requestFocus();
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index a29a946..3745323 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -459,10 +459,7 @@
d.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize);
if (d instanceof FastBitmapDrawable) {
FastBitmapDrawable fd = (FastBitmapDrawable) d;
- float oldBrightness = fd.getBrightness();
- fd.setBrightness(params.overlayAlpha);
- d.draw(canvas);
- fd.setBrightness(oldBrightness);
+ fd.drawWithBrightness(canvas, params.overlayAlpha);
} else {
d.setColorFilter(Color.argb((int) (params.overlayAlpha * 255), 255, 255, 255),
PorterDuff.Mode.SRC_ATOP);
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index a7d4c63..e205c42 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -24,7 +24,9 @@
import android.view.View;
import android.widget.TextView;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetHostView;
import com.android.launcher3.PreloadIconDrawable;
import com.android.launcher3.Workspace;
import com.android.launcher3.config.ProviderConfig;
@@ -100,20 +102,31 @@
* Responsibility for the bitmap is transferred to the caller.
*/
public Bitmap createDragBitmap(Canvas canvas) {
- Bitmap b;
+ float scale = 1f;
+ int width = mView.getWidth();
+ int height = mView.getHeight();
if (mView instanceof TextView) {
Drawable d = Workspace.getTextViewIcon((TextView) mView);
Rect bounds = getDrawableBounds(d);
- b = Bitmap.createBitmap(bounds.width() + DRAG_BITMAP_PADDING,
- bounds.height() + DRAG_BITMAP_PADDING, Bitmap.Config.ARGB_8888);
- } else {
- b = Bitmap.createBitmap(mView.getWidth() + DRAG_BITMAP_PADDING,
- mView.getHeight() + DRAG_BITMAP_PADDING, Bitmap.Config.ARGB_8888);
+ width = bounds.width();
+ height = bounds.height();
+ } else if (mView instanceof LauncherAppWidgetHostView) {
+ DeviceProfile profile = Launcher.getLauncher(mView.getContext()).getDeviceProfile();
+ scale = Math.min(profile.appWidgetScale.x, profile.appWidgetScale.y);
+ width = (int) (mView.getWidth() * scale);
+ height = (int) (mView.getHeight() * scale);
}
+ Bitmap b = Bitmap.createBitmap(width + DRAG_BITMAP_PADDING, height + DRAG_BITMAP_PADDING,
+ Bitmap.Config.ARGB_8888);
canvas.setBitmap(b);
+
+ canvas.save();
+ canvas.scale(scale, scale);
drawDragView(canvas);
+ canvas.restore();
+
canvas.setBitmap(null);
return b;
@@ -132,12 +145,29 @@
* Responsibility for the bitmap is transferred to the caller.
*/
public Bitmap createDragOutline(Canvas canvas) {
- final Bitmap b = Bitmap.createBitmap(mView.getWidth() + DRAG_BITMAP_PADDING,
- mView.getHeight() + DRAG_BITMAP_PADDING, Bitmap.Config.ALPHA_8);
+ float scale = 1f;
+ int width = mView.getWidth();
+ int height = mView.getHeight();
+
+ if (mView instanceof LauncherAppWidgetHostView) {
+ DeviceProfile profile = Launcher.getLauncher(mView.getContext()).getDeviceProfile();
+ scale = Math.min(profile.appWidgetScale.x, profile.appWidgetScale.y);
+ width = (int) Math.floor(mView.getWidth() * scale);
+ height = (int) Math.floor(mView.getHeight() * scale);
+ }
+
+ Bitmap b = Bitmap.createBitmap(width + DRAG_BITMAP_PADDING, height + DRAG_BITMAP_PADDING,
+ Bitmap.Config.ALPHA_8);
canvas.setBitmap(b);
+
+ canvas.save();
+ canvas.scale(scale, scale);
drawDragView(canvas);
+ canvas.restore();
+
HolographicOutlineHelper.getInstance(mView.getContext())
.applyExpensiveOutlineWithBlur(b, canvas);
+
canvas.setBitmap(null);
return b;
}
@@ -160,8 +190,17 @@
public float getScaleAndPosition(Bitmap preview, int[] outPos) {
float scale = Launcher.getLauncher(mView.getContext())
.getDragLayer().getLocationInDragLayer(mView, outPos);
- outPos[0] = Math.round(outPos[0] - (preview.getWidth() - scale * mView.getWidth()) / 2);
- outPos[1] = Math.round(outPos[1] - (1 - scale) * preview.getHeight() / 2 - previewPadding / 2);
+ DeviceProfile profile = Launcher.getLauncher(mView.getContext()).getDeviceProfile();
+ if (mView instanceof LauncherAppWidgetHostView) {
+ // App widgets are technically scaled, but are drawn at their expected size -- so the
+ // app widget scale should not affect the scale of the preview.
+ scale /= Math.min(profile.appWidgetScale.x, profile.appWidgetScale.y);
+ }
+
+ outPos[0] = Math.round(outPos[0] -
+ (preview.getWidth() - scale * mView.getWidth() * mView.getScaleX()) / 2);
+ outPos[1] = Math.round(outPos[1] - (1 - scale) * preview.getHeight() / 2
+ - previewPadding / 2);
return scale;
}
}
diff --git a/src/com/android/launcher3/graphics/DrawableFactory.java b/src/com/android/launcher3/graphics/DrawableFactory.java
new file mode 100644
index 0000000..2926a29
--- /dev/null
+++ b/src/com/android/launcher3/graphics/DrawableFactory.java
@@ -0,0 +1,69 @@
+/*
+ * 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.graphics;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.text.TextUtils;
+
+import com.android.launcher3.FastBitmapDrawable;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.R;
+
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Factory for creating new drawables.
+ */
+public class DrawableFactory {
+
+ private static DrawableFactory sInstance;
+ private static final Object LOCK = new Object();
+
+ public static DrawableFactory get(Context context) {
+ synchronized (LOCK) {
+ if (sInstance == null) {
+ context = context.getApplicationContext();
+ sInstance = loadByName(context.getString(R.string.drawable_factory_class), context);
+ }
+ return sInstance;
+ }
+ }
+
+ public static DrawableFactory loadByName(String className, Context context) {
+ if (!TextUtils.isEmpty(className)) {
+ try {
+ Class<?> cls = Class.forName(className);
+ return (DrawableFactory)
+ cls.getDeclaredConstructor(Context.class).newInstance(context);
+ } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
+ | ClassCastException | NoSuchMethodException | InvocationTargetException e) {
+ return new DrawableFactory();
+ }
+ }
+ return new DrawableFactory();
+ }
+
+ /**
+ * Returns a FastBitmapDrawable with the icon.
+ */
+ public FastBitmapDrawable newIcon(Bitmap icon, ItemInfo info) {
+ FastBitmapDrawable d = new FastBitmapDrawable(icon);
+ d.setFilterBitmap(true);
+ return d;
+ }
+}
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
index c2b97eb..395daa5 100644
--- a/src/com/android/launcher3/logging/LoggerUtils.java
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -20,8 +20,16 @@
public class LoggerUtils {
private static final String TAG = "LoggerUtils";
- public static String getActionStr(LauncherLogProto.Action action) {
- switch(action.touch) {
+ private static String getCommandStr(Action action) {
+ switch (action.command) {
+ case Action.HOME_INTENT: return "HOME_INTENT";
+ case Action.BACK: return "BACK";
+ default: return "UNKNOWN";
+ }
+ }
+
+ private static String getTouchStr(Action action) {
+ switch (action.touch) {
case Action.TAP: return "TAP";
case Action.LONGPRESS: return "LONGPRESS";
case Action.DRAGDROP: return "DRAGDROP";
@@ -32,6 +40,14 @@
}
}
+ public static String getActionStr(LauncherLogProto.Action action) {
+ switch (action.type) {
+ case Action.TOUCH: return getTouchStr(action);
+ case Action.COMMAND: return getCommandStr(action);
+ default: return "UNKNOWN";
+ }
+ }
+
public static String getTargetStr(Target t) {
String typeStr = "";
if (t == null){
@@ -61,6 +77,7 @@
case LauncherLogProto.DEEPSHORTCUT: typeStr = "DEEPSHORTCUT"; break;
case LauncherLogProto.FOLDER_ICON: typeStr = "FOLDERICON"; break;
case LauncherLogProto.SEARCHBOX: typeStr = "SEARCHBOX"; break;
+ case LauncherLogProto.EDITTEXT: typeStr = "EDITTEXT"; break;
default: typeStr = "UNKNOWN";
}
@@ -173,23 +190,41 @@
}
/**
+ * Used for commands.
+ */
+ public static LauncherLogProto.LauncherEvent initLauncherEvent(int command,
+ boolean createSrcTarget) {
+ LauncherLogProto.LauncherEvent event = new LauncherLogProto.LauncherEvent();
+ event.action = new LauncherLogProto.Action();
+ event.action.type = Action.COMMAND;
+ event.action.command = command;
+ event.srcTarget = null;
+
+ if (createSrcTarget) {
+ event.srcTarget = new LauncherLogProto.Target[1];
+ event.srcTarget[0] = new LauncherLogProto.Target();
+ event.srcTarget[0].type = Target.CONTAINER;
+ }
+ return event;
+ }
+
+ /**
* Used for drag and drop interaction.
*/
public static LauncherLogProto.LauncherEvent initLauncherEvent(
int actionType,
- View v,
ItemInfo info,
int parentSrcTargetType,
View parentDestTargetType){
LauncherLogProto.LauncherEvent event = new LauncherLogProto.LauncherEvent();
event.srcTarget = new LauncherLogProto.Target[2];
- event.srcTarget[0] = initTarget(v, info);
+ event.srcTarget[0] = initTarget(info);
event.srcTarget[1] = new LauncherLogProto.Target();
event.srcTarget[1].type = parentSrcTargetType;
event.destTarget = new LauncherLogProto.Target[2];
- event.destTarget[0] = initTarget(v, info);
+ event.destTarget[0] = initTarget(info);
event.destTarget[1] = initDropTarget(parentDestTargetType);
event.action = new LauncherLogProto.Action();
@@ -197,7 +232,7 @@
return event;
}
- private static Target initTarget(View v, ItemInfo info) {
+ private static Target initTarget(ItemInfo info) {
Target t = new LauncherLogProto.Target();
t.type = Target.ITEM;
switch (info.itemType) {
@@ -243,6 +278,6 @@
if (!(v.getTag() instanceof ItemInfo)) {
return t;
}
- return initTarget(v, (ItemInfo) v.getTag());
+ return initTarget((ItemInfo) v.getTag());
}
}
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index 441d8e5..2fcdd39 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -27,6 +27,7 @@
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.ProviderConfig;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
@@ -116,29 +117,35 @@
Action.TOUCH, v, Target.CONTAINER);
event.action.touch = Action.TAP;
- // Fill in grid(x,y), pageIndex of the child and container type of the parent
- // TODO: make this percolate up the view hierarchy if needed.
+ // TODO: make idx percolate up the view hierarchy if needed.
int idx = 0;
- LogContainerProvider provider = getLaunchProviderRecursive(v);
- if (v == null || !(v.getTag() instanceof ItemInfo) || provider == null) {
- return null;
- }
- ItemInfo itemInfo = (ItemInfo) v.getTag();
- provider.fillInLogContainerData(v, itemInfo, event.srcTarget[idx], event.srcTarget[idx + 1]);
-
- event.srcTarget[idx].intentHash = intent.hashCode();
- ComponentName cn = intent.getComponent();
- if (cn != null) {
- event.srcTarget[idx].packageNameHash = cn.getPackageName().hashCode();
- event.srcTarget[idx].componentHash = cn.hashCode();
- if (mPredictedApps != null) {
- event.srcTarget[idx].predictedRank = mPredictedApps.indexOf(
- new ComponentKey(cn, itemInfo.user));
+ if (fillInLogContainerData(event, v)) {
+ ItemInfo itemInfo = (ItemInfo) v.getTag();
+ event.srcTarget[idx].intentHash = intent.hashCode();
+ ComponentName cn = intent.getComponent();
+ if (cn != null) {
+ event.srcTarget[idx].packageNameHash = cn.getPackageName().hashCode();
+ event.srcTarget[idx].componentHash = cn.hashCode();
+ if (mPredictedApps != null) {
+ event.srcTarget[idx].predictedRank = mPredictedApps.indexOf(
+ new ComponentKey(cn, itemInfo.user));
+ }
}
}
return event;
}
+ public boolean fillInLogContainerData(LauncherEvent event, View v) {
+ // Fill in grid(x,y), pageIndex of the child and container type of the parent
+ LogContainerProvider provider = getLaunchProviderRecursive(v);
+ if (v == null || !(v.getTag() instanceof ItemInfo) || provider == null) {
+ return false;
+ }
+ ItemInfo itemInfo = (ItemInfo) v.getTag();
+ provider.fillInLogContainerData(v, itemInfo, event.srcTarget[0], event.srcTarget[1]);
+ return true;
+ }
+
public void logAppLaunch(View v, Intent intent) {
LauncherEvent ev = createLauncherEvent(v, intent);
if (ev == null) {
@@ -147,10 +154,30 @@
dispatchUserEvent(ev, intent);
}
- public void logActionOnItem(int action, int itemType) {
- LauncherEvent event = LoggerUtils.initLauncherEvent(Action.TOUCH, Target.ITEM);
- event.action.touch = action;
- event.srcTarget[0].itemType = itemType;
+ public void logActionCommand(int command, int containerType) {
+ logActionCommand(command, containerType, 0);
+ }
+
+ public void logActionCommand(int command, int containerType, int pageIndex) {
+ LauncherEvent event = LoggerUtils.initLauncherEvent(command, true);
+ event.srcTarget[0].containerType = containerType;
+ event.srcTarget[0].pageIndex = pageIndex;
+ dispatchUserEvent(event, null);
+ }
+
+ /**
+ * TODO: Make this function work when a container view is passed as the 2nd param.
+ */
+ public void logActionCommand(int command, View itemView, int containerType) {
+ LauncherEvent event = LoggerUtils.initLauncherEvent(Action.COMMAND, itemView,
+ Target.CONTAINER);
+ event.action.command = command;
+ if (fillInLogContainerData(event, itemView)) {
+ // TODO: Remove the following two lines once fillInLogContainerData can take in a
+ // container view.
+ event.srcTarget[0].type = Target.CONTAINER;
+ event.srcTarget[0].containerType = containerType;
+ }
dispatchUserEvent(event, null);
}
@@ -193,9 +220,27 @@
mPredictedApps = predictedApps;
}
+ /* Currently we are only interested in whether this event happens or not and don't
+ * care about which screen moves to where. */
+ public void logOverviewReorder() {
+ LauncherEvent event = new LauncherLogProto.LauncherEvent();
+
+ event.srcTarget = new LauncherLogProto.Target[2];
+ event.srcTarget[0] = new LauncherLogProto.Target();
+ event.srcTarget[0].type = Target.CONTAINER;
+ event.srcTarget[0].containerType = LauncherLogProto.WORKSPACE;
+ event.srcTarget[1] = new LauncherLogProto.Target();
+ event.srcTarget[1].type = Target.CONTAINER;
+ event.srcTarget[1].containerType = LauncherLogProto.OVERVIEW;
+
+ event.action = new LauncherLogProto.Action();
+ event.action.type = Action.TOUCH;
+ event.action.touch = Action.DRAGDROP;
+ dispatchUserEvent(event, null);
+
+ }
public void logDragNDrop(DropTarget.DragObject dragObj, View dropTargetAsView) {
LauncherEvent event = LoggerUtils.initLauncherEvent(Action.TOUCH,
- dragObj.dragView,
dragObj.originalDragInfo,
Target.CONTAINER,
dropTargetAsView);
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index 986e163..4cbb087 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -26,6 +26,7 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherModel.CallbackTask;
import com.android.launcher3.LauncherModel.Callbacks;
@@ -33,39 +34,42 @@
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();
- final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();
- final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();
+ final ArrayList<ItemInfo> addedItemsFinal = new ArrayList<>();
+ final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<>();
// Get the list of workspace screens. We need to append to this list and
// can not use sBgWorkspaceScreens because loadWorkspace() may not have been
// 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)) {
@@ -74,13 +78,14 @@
}
// Find appropriate space for the item.
- Pair<Long, int[]> coords = findSpaceForItem(
- app, dataModel, workspaceScreens, addedWorkspaceScreensFinal, 1, 1);
+ Pair<Long, int[]> coords = findSpaceForItem(app, dataModel, workspaceScreens,
+ addedWorkspaceScreensFinal, item.spanX, item.spanY);
long screenId = coords.first;
int[] cordinates = coords.second;
ItemInfo itemInfo;
- if (item instanceof ShortcutInfo || item instanceof FolderInfo) {
+ if (item instanceof ShortcutInfo || item instanceof FolderInfo ||
+ item instanceof LauncherAppWidgetInfo) {
itemInfo = item;
} else if (item instanceof AppInfo) {
itemInfo = ((AppInfo) item).makeShortcut();
@@ -92,23 +97,23 @@
addItemToDatabase(context, itemInfo, screenId, cordinates);
// Save the ShortcutInfo for binding in the workspace
- addedShortcutsFinal.add(itemInfo);
+ addedItemsFinal.add(itemInfo);
}
}
// Update the workspace screens
updateScreens(context, workspaceScreens);
- if (!addedShortcutsFinal.isEmpty()) {
+ if (!addedItemsFinal.isEmpty()) {
scheduleCallbackTask(new CallbackTask() {
@Override
public void execute(Callbacks callbacks) {
final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();
final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();
- if (!addedShortcutsFinal.isEmpty()) {
- ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 1);
+ if (!addedItemsFinal.isEmpty()) {
+ ItemInfo info = addedItemsFinal.get(addedItemsFinal.size() - 1);
long lastScreenId = info.screenId;
- for (ItemInfo i : addedShortcutsFinal) {
+ for (ItemInfo i : addedItemsFinal) {
if (i.screenId == lastScreenId) {
addAnimated.add(i);
} else {
@@ -258,5 +263,4 @@
}
return occupied.findVacantCell(xy, spanX, spanY);
}
-
}
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index c18eeef..3d54637 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -15,10 +15,12 @@
*/
package com.android.launcher3.model;
+import android.content.Context;
import android.util.Log;
import android.util.MutableInt;
import com.android.launcher3.FolderInfo;
+import com.android.launcher3.InstallShortcutReceiver;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetInfo;
@@ -26,6 +28,7 @@
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.config.ProviderConfig;
+import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.ComponentKey;
@@ -122,9 +125,11 @@
// Decrement pinned shortcut count
ShortcutKey pinnedShortcut = ShortcutKey.fromShortcutInfo((ShortcutInfo) item);
MutableInt count = pinnedShortcutCounts.get(pinnedShortcut);
- if (count == null || --count.value == 0) {
- LauncherAppState.getInstance()
- .getShortcutManager().unpinShortcut(pinnedShortcut);
+ Context context = LauncherAppState.getInstance().getContext();
+ if ((count == null || --count.value == 0)
+ && !InstallShortcutReceiver.getPendingShortcuts(context)
+ .contains(pinnedShortcut)) {
+ DeepShortcutManager.getInstance(context).unpinShortcut(pinnedShortcut);
}
// Fall through.
}
@@ -161,7 +166,7 @@
// Since this is a new item, pin the shortcut in the system server.
if (newItem && count.value == 1) {
- LauncherAppState.getInstance().getShortcutManager()
+ DeepShortcutManager.getInstance(LauncherAppState.getInstance().getContext())
.pinShortcut(pinnedShortcut);
}
// Fall through
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index e3a2b24..176e8ea 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -214,7 +214,6 @@
si.iconResource.resourceName, context);
if (icon != null) {
si.setIcon(icon);
- si.usingFallbackIcon = false;
infoUpdated = true;
}
}
diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java
index 8f7c21d..3314353 100644
--- a/src/com/android/launcher3/model/ShortcutsChangedTask.java
+++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java
@@ -51,7 +51,8 @@
@Override
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
- DeepShortcutManager deepShortcutManager = app.getShortcutManager();
+ final Context context = app.getContext();
+ DeepShortcutManager deepShortcutManager = DeepShortcutManager.getInstance(context);
deepShortcutManager.onShortcutsChanged(mShortcuts);
// Find ShortcutInfo's that have changed on the workspace.
@@ -67,7 +68,6 @@
}
}
- final Context context = LauncherAppState.getInstance().getContext();
final ArrayList<ShortcutInfo> updatedShortcutInfos = new ArrayList<>();
if (!idsToWorkspaceShortcutInfos.isEmpty()) {
// Update the workspace to reflect the changes to updated shortcuts residing on it.
diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java
index b7b52a4..a89fe0b 100644
--- a/src/com/android/launcher3/model/UserLockStateChangedTask.java
+++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java
@@ -50,7 +50,7 @@
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
Context context = app.getContext();
boolean isUserUnlocked = UserManagerCompat.getInstance(context).isUserUnlocked(mUser);
- DeepShortcutManager deepShortcutManager = app.getShortcutManager();
+ DeepShortcutManager deepShortcutManager = DeepShortcutManager.getInstance(context);
HashMap<ShortcutKey, ShortcutInfoCompat> pinnedShortcuts = new HashMap<>();
if (isUserUnlocked) {
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index 12a6701..4f5edc9 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -72,18 +72,6 @@
}
};
- /**
- * Listener for keep running the animation until the final state is reached.
- */
- private final AnimatorListenerAdapter mAnimCycleListener = new AnimatorListenerAdapter() {
-
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimator = null;
- animateToPosition(mFinalPosition);
- }
- };
-
private final Paint mCirclePaint;
private final float mDotRadius;
private final int mActiveColor;
@@ -163,7 +151,7 @@
float positionForThisAnim = mCurrentPosition > mFinalPosition ?
mCurrentPosition - SHIFT_PER_ANIMATION : mCurrentPosition + SHIFT_PER_ANIMATION;
mAnimator = ObjectAnimator.ofFloat(this, CURRENT_POSITION, positionForThisAnim);
- mAnimator.addListener(mAnimCycleListener);
+ mAnimator.addListener(new AnimationCycleListener());
mAnimator.setDuration(ANIMATION_DURATION);
mAnimator.start();
}
@@ -171,7 +159,6 @@
public void stopAllAnimations() {
if (mAnimator != null) {
- mAnimator.removeAllListeners();
mAnimator.cancel();
mAnimator = null;
}
@@ -326,4 +313,25 @@
}
}
}
+
+ /**
+ * Listener for keep running the animation until the final state is reached.
+ */
+ private class AnimationCycleListener extends AnimatorListenerAdapter {
+
+ private boolean mCancelled = false;
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!mCancelled) {
+ mAnimator = null;
+ animateToPosition(mFinalPosition);
+ }
+ }
+ }
}
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutManager.java b/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
index c2c7c17..41f1a47 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
@@ -45,10 +45,22 @@
private static final int FLAG_GET_ALL = ShortcutQuery.FLAG_MATCH_DYNAMIC
| ShortcutQuery.FLAG_MATCH_MANIFEST | ShortcutQuery.FLAG_MATCH_PINNED;
+ private static DeepShortcutManager sInstance;
+ private static final Object sInstanceLock = new Object();
+
+ public static DeepShortcutManager getInstance(Context context) {
+ synchronized (sInstanceLock) {
+ if (sInstance == null) {
+ sInstance = new DeepShortcutManager(context.getApplicationContext());
+ }
+ return sInstance;
+ }
+ }
+
private final LauncherApps mLauncherApps;
private boolean mWasLastCallSuccess;
- public DeepShortcutManager(Context context, ShortcutCache shortcutCache) {
+ private DeepShortcutManager(Context context) {
mLauncherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
}
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
index 08ca242..314a862 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
@@ -52,7 +52,6 @@
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherViewPropertyAnimator;
@@ -103,7 +102,7 @@
public DeepShortcutsContainer(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mLauncher = Launcher.getLauncher(context);
- mDeepShortcutsManager = LauncherAppState.getInstance().getShortcutManager();
+ mDeepShortcutsManager = DeepShortcutManager.getInstance(context);
mStartDragThreshold = getResources().getDimensionPixelSize(
R.dimen.deep_shortcuts_start_drag_threshold);
diff --git a/src/com/android/launcher3/util/ContentWriter.java b/src/com/android/launcher3/util/ContentWriter.java
new file mode 100644
index 0000000..33d979c
--- /dev/null
+++ b/src/com/android/launcher3/util/ContentWriter.java
@@ -0,0 +1,98 @@
+package com.android.launcher3.util;
+
+/**
+ * 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.
+ */
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.compat.UserManagerCompat;
+
+/**
+ * A wrapper around {@link ContentValues} with some utility methods.
+ */
+public class ContentWriter {
+
+ private final ContentValues mValues;
+ private final Context mContext;
+
+ private Bitmap mIcon;
+ private UserHandleCompat mUser;
+
+ public ContentWriter(Context context) {
+ this(new ContentValues(), context);
+ }
+
+ public ContentWriter(ContentValues values, Context context) {
+ mValues = values;
+ mContext = context;
+ }
+
+ public ContentWriter put(String key, Integer value) {
+ mValues.put(key, value);
+ return this;
+ }
+
+ public ContentWriter put(String key, Long value) {
+ mValues.put(key, value);
+ return this;
+ }
+
+ public ContentWriter put(String key, String value) {
+ mValues.put(key, value);
+ return this;
+ }
+
+ public ContentWriter put(String key, CharSequence value) {
+ mValues.put(key, value == null ? null : value.toString());
+ return this;
+ }
+
+ public ContentWriter put(String key, Intent value) {
+ mValues.put(key, value == null ? null : value.toUri(0));
+ return this;
+ }
+
+ public ContentWriter putIcon(Bitmap value, UserHandleCompat user) {
+ mIcon = value;
+ mUser = user;
+ return this;
+ }
+
+ public ContentWriter put(String key, UserHandleCompat user) {
+ return put(key, UserManagerCompat.getInstance(mContext).getSerialNumberForUser(user));
+ }
+
+ /**
+ * Commits any pending validation and returns the final values.
+ * Must not be called on UI thread.
+ */
+ public ContentValues getValues() {
+ Preconditions.assertNonUiThread();
+ if (mIcon != null && !LauncherAppState.getInstance().getIconCache()
+ .isDefaultIcon(mIcon, mUser)) {
+ mValues.put(LauncherSettings.Favorites.ICON, Utilities.flattenBitmap(mIcon));
+ mIcon = null;
+ }
+ return mValues;
+ }
+}
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/PendingRequestArgs.java b/src/com/android/launcher3/util/PendingRequestArgs.java
index bade967..8eea28b 100644
--- a/src/com/android/launcher3/util/PendingRequestArgs.java
+++ b/src/com/android/launcher3/util/PendingRequestArgs.java
@@ -73,7 +73,7 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
ContentValues itemValues = new ContentValues();
- writeToValues(itemValues);
+ writeToValues(new ContentWriter(itemValues, null));
itemValues.writeToParcel(dest, flags);
dest.writeInt(mArg1);
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/Android.mk b/tests/Android.mk
index 5103ced..466146e 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -17,9 +17,9 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4
+#LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+#LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SDK_VERSION := current
LOCAL_MIN_SDK_VERSION := 21
diff --git a/tests/src/com/android/launcher3/BindWidgetTest.java b/tests/src/com/android/launcher3/BindWidgetTest.java
index c133bf6..6be2522 100644
--- a/tests/src/com/android/launcher3/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/BindWidgetTest.java
@@ -17,6 +17,7 @@
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.ui.LauncherInstrumentationTestCase;
+import com.android.launcher3.util.ContentWriter;
import com.android.launcher3.util.ManagedProfileHeuristic;
import com.android.launcher3.widget.PendingAddWidgetInfo;
import com.android.launcher3.widget.WidgetHostViewLoader;
@@ -218,14 +219,14 @@
mResolver.insert(LauncherSettings.WorkspaceScreens.CONTENT_URI, v);
// Insert the item
- v = new ContentValues();
+ ContentWriter writer = new ContentWriter(mTargetContext);
item.id = LauncherSettings.Settings.call(
mResolver, LauncherSettings.Settings.METHOD_NEW_ITEM_ID)
.getLong(LauncherSettings.Settings.EXTRA_VALUE);
item.screenId = screenId;
- item.onAddToDatabase(mTargetContext, v);
- v.put(LauncherSettings.Favorites._ID, item.id);
- mResolver.insert(LauncherSettings.Favorites.CONTENT_URI, v);
+ item.onAddToDatabase(writer);
+ writer.put(LauncherSettings.Favorites._ID, item.id);
+ mResolver.insert(LauncherSettings.Favorites.CONTENT_URI, writer.getValues());
// Reset loader
try {
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,