diff options
35 files changed, 726 insertions, 786 deletions
diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 70f5b32c7..f6bb3adc8 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -89,6 +89,7 @@ <dimen name="widget_preview_key_shadow_distance">1dp</dimen> <dimen name="widget_preview_corner_radius">2dp</dimen> <dimen name="widget_preview_cell_divider_width">0.5dp</dimen> + <dimen name="widget_preview_shortcut_padding">8dp</dimen> <dimen name="widget_section_height">56dp</dimen> <dimen name="widget_section_icon_size">40dp</dimen> diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 0df8e5a89..e0fcbf04d 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -50,6 +50,7 @@ import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.accessibility.DragAndDropAccessibilityDelegate; import com.android.launcher3.accessibility.FolderAccessibilityHelper; import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper; +import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.config.ProviderConfig; import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.graphics.DragPreviewProvider; @@ -2097,12 +2098,13 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { } setInitialAnimationValues(true); - a = new LauncherViewPropertyAnimator(child) - .scaleX(initScale) - .scaleY(initScale) - .translationX(initDeltaX) - .translationY(initDeltaY) - .setDuration(REORDER_ANIMATION_DURATION); + a = LauncherAnimUtils.ofPropertyValuesHolder(child, + new PropertyListBuilder() + .scale(initScale) + .translationX(initDeltaX) + .translationY(initDeltaY) + .build()) + .setDuration(REORDER_ANIMATION_DURATION); a.setInterpolator(new android.view.animation.DecelerateInterpolator(1.5f)); a.start(); } @@ -2144,7 +2146,7 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { info.spanY = lp.cellVSpan; if (requiresDbUpdate) { - LauncherModel.modifyItemInDatabase(getContext(), info, container, screenId, + mLauncher.getModelWriter().modifyItemInDatabase(info, container, screenId, info.cellX, info.cellY, info.spanX, info.spanY); } } diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java index 5fff2e76b..2c69d0a69 100644 --- a/src/com/android/launcher3/FolderInfo.java +++ b/src/com/android/launcher3/FolderInfo.java @@ -16,9 +16,9 @@ package com.android.launcher3; -import android.content.Context; import android.os.Process; +import com.android.launcher3.model.ModelWriter; import com.android.launcher3.util.ContentWriter; import java.util.ArrayList; @@ -128,17 +128,17 @@ public class FolderInfo extends ItemInfo { /** * @param option flag to set or clear * @param isEnabled whether to set or clear the flag - * @param context if not null, save changes to the db. + * @param writer if not null, save changes to the db. */ - public void setOption(int option, boolean isEnabled, Context context) { + public void setOption(int option, boolean isEnabled, ModelWriter writer) { int oldOptions = options; if (isEnabled) { options |= option; } else { options &= ~option; } - if (context != null && oldOptions != options) { - LauncherModel.updateItemInDatabase(context, this); + if (writer != null && oldOptions != options) { + writer.updateItemInDatabase(this); } } } diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index e3c6965f7..8aeab8712 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -29,6 +29,7 @@ import android.view.WindowManager; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.config.ProviderConfig; +import com.android.launcher3.logging.FileLog; import com.android.launcher3.util.Thunk; import org.xmlpull.v1.XmlPullParser; @@ -187,6 +188,23 @@ public class InvariantDeviceProfile { } } + public void dumpDisplayInfo(Context context) { + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + Display display = wm.getDefaultDisplay(); + DisplayMetrics dm = new DisplayMetrics(); + display.getMetrics(dm); + + Point smallestSize = new Point(); + Point largestSize = new Point(); + display.getCurrentSizeRange(smallestSize, largestSize); + + FileLog.e("DisplayInfo", "Default Density: " + DisplayMetrics.DENSITY_DEFAULT); + FileLog.e("DisplayInfo", "Density: " + dm.densityDpi); + FileLog.e("DisplayInfo", "Smallest size: " + smallestSize); + FileLog.e("DisplayInfo", "Largest size: " + largestSize); + FileLog.e("DisplayInfo", "minWidth/Height DPS: " + minWidthDps + ", " + minHeightDps); + } + ArrayList<InvariantDeviceProfile> getPredefinedDeviceProfiles(Context context) { ArrayList<InvariantDeviceProfile> profiles = new ArrayList<>(); try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) { diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index a160c411e..14b9c8290 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -85,6 +85,7 @@ import com.android.launcher3.allapps.AllAppsContainerView; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.allapps.DefaultAppSearchController; import com.android.launcher3.anim.AnimationLayerSet; +import com.android.launcher3.model.ModelWriter; import com.android.launcher3.notification.NotificationListener; import com.android.launcher3.popup.PopupDataProvider; import com.android.launcher3.compat.AppWidgetManagerCompat; @@ -254,6 +255,7 @@ public class Launcher extends BaseActivity private ViewOnDrawExecutor mPendingExecutor; private LauncherModel mModel; + private ModelWriter mModelWriter; private IconCache mIconCache; private ExtractedColors mExtractedColors; private LauncherAccessibilityDelegate mAccessibilityDelegate; @@ -371,6 +373,7 @@ public class Launcher extends BaseActivity mSharedPrefs = Utilities.getPrefs(this); mIsSafeModeEnabled = getPackageManager().isSafeMode(); mModel = app.setLauncher(this); + mModelWriter = mModel.getWriter(mDeviceProfile.isVerticalBarLayout()); mIconCache = app.getIconCache(); mAccessibilityDelegate = new LauncherAccessibilityDelegate(this); @@ -1498,7 +1501,7 @@ public class Launcher extends BaseActivity return; } - LauncherModel.addItemToDatabase(this, info, container, screenId, cellXY[0], cellXY[1]); + getModelWriter().addItemToDatabase(info, container, screenId, cellXY[0], cellXY[1]); mWorkspace.addInScreen(view, info); } @@ -1526,7 +1529,7 @@ public class Launcher extends BaseActivity launcherInfo.minSpanY = itemInfo.minSpanY; launcherInfo.user = appWidgetInfo.getUser(); - LauncherModel.addItemToDatabase(this, launcherInfo, + getModelWriter().addItemToDatabase(launcherInfo, itemInfo.container, itemInfo.screenId, itemInfo.cellX, itemInfo.cellY); if (hostView == null) { @@ -1686,6 +1689,10 @@ public class Launcher extends BaseActivity return mModel; } + public ModelWriter getModelWriter() { + return mModelWriter; + } + public SharedPreferences getSharedPrefs() { return mSharedPrefs; } @@ -2127,8 +2134,7 @@ public class Launcher extends BaseActivity folderInfo.title = getText(R.string.folder_name); // Update the model - LauncherModel.addItemToDatabase(Launcher.this, folderInfo, container, screenId, - cellX, cellY); + getModelWriter().addItemToDatabase(folderInfo, container, screenId, cellX, cellY); // Create the view FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this, layout, folderInfo); @@ -2156,7 +2162,7 @@ public class Launcher extends BaseActivity mWorkspace.removeWorkspaceItem(v); } if (deleteFromDb) { - LauncherModel.deleteItemFromDatabase(this, itemInfo); + getModelWriter().deleteItemFromDatabase(itemInfo); } } else if (itemInfo instanceof FolderInfo) { final FolderInfo folderInfo = (FolderInfo) itemInfo; @@ -2165,7 +2171,7 @@ public class Launcher extends BaseActivity } mWorkspace.removeWorkspaceItem(v); if (deleteFromDb) { - LauncherModel.deleteFolderAndContentsFromDatabase(this, folderInfo); + getModelWriter().deleteFolderAndContentsFromDatabase(folderInfo); } } else if (itemInfo instanceof LauncherAppWidgetInfo) { final LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) itemInfo; @@ -2194,7 +2200,7 @@ public class Launcher extends BaseActivity } }.executeOnExecutor(Utilities.THREAD_POOL_EXECUTOR); } - LauncherModel.deleteItemFromDatabase(this, widgetInfo); + getModelWriter().deleteItemFromDatabase(widgetInfo); } @Override @@ -3373,7 +3379,7 @@ public class Launcher extends BaseActivity throw (new RuntimeException(desc)); } else { Log.d(TAG, desc); - LauncherModel.deleteItemFromDatabase(this, item); + getModelWriter().deleteItemFromDatabase(item); continue; } } @@ -3470,7 +3476,7 @@ public class Launcher extends BaseActivity + " belongs to component " + item.providerName + ", as the provider is null"); } - LauncherModel.deleteItemFromDatabase(this, item); + getModelWriter().deleteItemFromDatabase(item); return; } @@ -3517,14 +3523,14 @@ public class Launcher extends BaseActivity : LauncherAppWidgetInfo.FLAG_UI_NOT_READY; } - LauncherModel.updateItemInDatabase(this, item); + getModelWriter().updateItemInDatabase(item); } } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_UI_NOT_READY) && (appWidgetInfo.configure == null)) { // The widget was marked as UI not ready, but there is no configure activity to // update the UI. item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED; - LauncherModel.updateItemInDatabase(this, item); + getModelWriter().updateItemInDatabase(item); } } @@ -3574,7 +3580,7 @@ public class Launcher extends BaseActivity info.restoreStatus = finalRestoreFlag; mWorkspace.reinflateWidgetsIfNecessary(); - LauncherModel.updateItemInDatabase(this, info); + getModelWriter().updateItemInDatabase(info); return info; } diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index 55c370387..e0e53a647 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -28,6 +28,7 @@ import com.android.launcher3.compat.PackageInstallerCompat; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.config.ProviderConfig; import com.android.launcher3.dynamicui.ExtractionUtils; +import com.android.launcher3.model.GridSizeMigrationTask; import com.android.launcher3.util.ConfigMonitor; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.TestingUtils; @@ -53,6 +54,8 @@ public class LauncherAppState { if (INSTANCE == null) { if (Looper.myLooper() == Looper.getMainLooper()) { INSTANCE = new LauncherAppState(context.getApplicationContext()); + GridSizeMigrationTask.logDeviceProfileIfChanged( + INSTANCE.getInvariantDeviceProfile(), context); } else { try { return new MainThreadExecutor().submit(new Callable<LauncherAppState>() { diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 9ad8433e7..34d576d27 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -57,6 +57,7 @@ import com.android.launcher3.model.CacheDataUpdatedTask; import com.android.launcher3.model.ExtendedModelTask; import com.android.launcher3.model.GridSizeMigrationTask; import com.android.launcher3.model.LoaderCursor; +import com.android.launcher3.model.ModelWriter; import com.android.launcher3.model.PackageInstallStateChangedTask; import com.android.launcher3.model.PackageItemInfo; import com.android.launcher3.model.PackageUpdatedTask; @@ -266,19 +267,8 @@ public class LauncherModel extends BroadcastReceiver enqueueModelUpdateTask(new AddWorkspaceItemsTask(appsProvider)); } - /** - * Adds an item to the DB if it was not created previously, or move it to a new - * <container, screen, cellX, cellY> - */ - public static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container, - long screenId, int cellX, int cellY) { - if (item.container == ItemInfo.NO_ID) { - // From all apps - addItemToDatabase(context, item, container, screenId, cellX, cellY); - } else { - // From somewhere else - moveItemInDatabase(context, item, container, screenId, cellX, cellY); - } + public ModelWriter getWriter(boolean hasVerticalHotseat) { + return new ModelWriter(mApp.getContext(), sBgDataModel, hasVerticalHotseat); } static void checkItemInfoLocked( @@ -332,281 +322,6 @@ public class LauncherModel extends BroadcastReceiver runOnWorkerThread(r); } - 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); - final ContentResolver cr = context.getContentResolver(); - - final StackTraceElement[] stackTrace = new Throwable().getStackTrace(); - final Context appContext = context.getApplicationContext(); - Runnable r = new Runnable() { - public void run() { - cr.update(uri, writer.getValues(appContext), null, null); - updateItemArrays(item, itemId, stackTrace); - } - }; - runOnWorkerThread(r); - } - - static void updateItemsInDatabaseHelper(Context context, final ArrayList<ContentValues> valuesList, - final ArrayList<ItemInfo> items, final String callingFunction) { - final ContentResolver cr = context.getContentResolver(); - - final StackTraceElement[] stackTrace = new Throwable().getStackTrace(); - Runnable r = new Runnable() { - public void run() { - ArrayList<ContentProviderOperation> ops = - new ArrayList<ContentProviderOperation>(); - int count = items.size(); - for (int i = 0; i < count; i++) { - ItemInfo item = items.get(i); - final long itemId = item.id; - final Uri uri = LauncherSettings.Favorites.getContentUri(itemId); - ContentValues values = valuesList.get(i); - - ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build()); - updateItemArrays(item, itemId, stackTrace); - - } - try { - cr.applyBatch(LauncherProvider.AUTHORITY, ops); - } catch (Exception e) { - e.printStackTrace(); - } - } - }; - runOnWorkerThread(r); - } - - static void updateItemArrays(ItemInfo item, long itemId, StackTraceElement[] stackTrace) { - // Lock on mBgLock *after* the db operation - synchronized (sBgDataModel) { - checkItemInfoLocked(itemId, item, stackTrace); - - if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP && - item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) { - // Item is in a folder, make sure this folder exists - if (!sBgDataModel.folders.containsKey(item.container)) { - // An items container is being set to a that of an item which is not in - // the list of Folders. - String msg = "item: " + item + " container being set to: " + - item.container + ", not in the list of folders"; - Log.e(TAG, msg); - } - } - - // Items are added/removed from the corresponding FolderInfo elsewhere, such - // as in Workspace.onDrop. Here, we just add/remove them from the list of items - // that are on the desktop, as appropriate - ItemInfo modelItem = sBgDataModel.itemsIdMap.get(itemId); - if (modelItem != null && - (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP || - modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)) { - switch (modelItem.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_FOLDER: - if (!sBgDataModel.workspaceItems.contains(modelItem)) { - sBgDataModel.workspaceItems.add(modelItem); - } - break; - default: - break; - } - } else { - sBgDataModel.workspaceItems.remove(modelItem); - } - } - } - - /** - * Move an item in the DB to a new <container, screen, cellX, cellY> - */ - public static void moveItemInDatabase(Context context, final ItemInfo item, final long container, - final long screenId, final int cellX, final int cellY) { - item.container = container; - item.cellX = cellX; - item.cellY = cellY; - - // We store hotseat items in canonical form which is this orientation invariant position - // in the hotseat - if (context instanceof Launcher && screenId < 0 && - container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { - item.screenId = Launcher.getLauncher(context).getHotseat() - .getOrderInHotseat(cellX, cellY); - } else { - item.screenId = 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, writer, item, "moveItemInDatabase"); - } - - /** - * Move items in the DB to a new <container, screen, cellX, cellY>. We assume that the - * cellX, cellY have already been updated on the ItemInfos. - */ - public static void moveItemsInDatabase(Context context, final ArrayList<ItemInfo> items, - final long container, final int screen) { - - ArrayList<ContentValues> contentValues = new ArrayList<ContentValues>(); - int count = items.size(); - - for (int i = 0; i < count; i++) { - ItemInfo item = items.get(i); - item.container = container; - - // We store hotseat items in canonical form which is this orientation invariant position - // in the hotseat - if (context instanceof Launcher && screen < 0 && - container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { - item.screenId = Launcher.getLauncher(context).getHotseat().getOrderInHotseat(item.cellX, - item.cellY); - } else { - item.screenId = screen; - } - - 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); - - contentValues.add(values); - } - updateItemsInDatabaseHelper(context, contentValues, items, "moveItemInDatabase"); - } - - /** - * Move and/or resize item in the DB to a new <container, screen, cellX, cellY, spanX, spanY> - */ - static void modifyItemInDatabase(Context context, final ItemInfo item, final long container, - final long screenId, final int cellX, final int cellY, final int spanX, final int spanY) { - item.container = container; - item.cellX = cellX; - item.cellY = cellY; - item.spanX = spanX; - item.spanY = spanY; - - // We store hotseat items in canonical form which is this orientation invariant position - // in the hotseat - if (context instanceof Launcher && screenId < 0 && - container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { - item.screenId = Launcher.getLauncher(context).getHotseat() - .getOrderInHotseat(cellX, cellY); - } else { - item.screenId = 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, writer, item, "modifyItemInDatabase"); - } - - /** - * Update an item to the database in a specified container. - */ - public static void updateItemInDatabase(Context context, final ItemInfo item) { - ContentWriter writer = new ContentWriter(context); - item.onAddToDatabase(writer); - updateItemInDatabaseHelper(context, writer, item, "updateItemInDatabase"); - } - - /** - * Add an item to the database in a specified container. Sets the container, screen, cellX and - * cellY fields of the item. Also assigns an ID to the item. - */ - public static void addItemToDatabase(Context context, final ItemInfo item, final long container, - final long screenId, final int cellX, final int cellY) { - item.container = container; - item.cellX = cellX; - item.cellY = cellY; - // We store hotseat items in canonical form which is this orientation invariant position - // in the hotseat - if (context instanceof Launcher && screenId < 0 && - container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { - item.screenId = Launcher.getLauncher(context).getHotseat() - .getOrderInHotseat(cellX, cellY); - } else { - item.screenId = screenId; - } - - final ContentWriter writer = new ContentWriter(context); - final ContentResolver cr = context.getContentResolver(); - item.onAddToDatabase(writer); - - item.id = LauncherSettings.Settings.call(cr, LauncherSettings.Settings.METHOD_NEW_ITEM_ID) - .getLong(LauncherSettings.Settings.EXTRA_VALUE); - - writer.put(LauncherSettings.Favorites._ID, item.id); - - final StackTraceElement[] stackTrace = new Throwable().getStackTrace(); - final Context appContext = context.getApplicationContext(); - Runnable r = new Runnable() { - public void run() { - cr.insert(LauncherSettings.Favorites.CONTENT_URI, writer.getValues(appContext)); - - synchronized (sBgDataModel) { - checkItemInfoLocked(item.id, item, stackTrace); - sBgDataModel.addItem(appContext, item, true); - } - } - }; - runOnWorkerThread(r); - } - - /** - * Removes the specified item from the database - */ - public static void deleteItemFromDatabase(Context context, final ItemInfo item) { - ArrayList<ItemInfo> items = new ArrayList<>(); - items.add(item); - deleteItemsFromDatabase(context, items); - } - - /** - * Removes all the items from the database matching {@param matcher}. - */ - public static void deleteItemsFromDatabase(Context context, ItemInfoMatcher matcher) { - deleteItemsFromDatabase(context, matcher.filterItemInfos(sBgDataModel.itemsIdMap)); - } - - /** - * Removes the specified items from the database - */ - public static void deleteItemsFromDatabase(Context context, - final Iterable<? extends ItemInfo> items) { - final ContentResolver cr = context.getContentResolver(); - final Context appContext = context.getApplicationContext(); - Runnable r = new Runnable() { - public void run() { - for (ItemInfo item : items) { - final Uri uri = LauncherSettings.Favorites.getContentUri(item.id); - cr.delete(uri, null, null); - - sBgDataModel.removeItem(appContext, item); - } - } - }; - runOnWorkerThread(r); - } - /** * Update the order of the workspace screens in the database. The array list contains * a list of screen ids in the order that they should appear. @@ -656,27 +371,6 @@ public class LauncherModel extends BroadcastReceiver } /** - * Remove the specified folder and all its contents from the database. - */ - public static void deleteFolderAndContentsFromDatabase(Context context, final FolderInfo info) { - final ContentResolver cr = context.getContentResolver(); - final Context appContext = context.getApplicationContext(); - - Runnable r = new Runnable() { - public void run() { - cr.delete(LauncherSettings.Favorites.CONTENT_URI, - LauncherSettings.Favorites.CONTAINER + "=" + info.id, null); - sBgDataModel.removeItem(appContext, info.contents); - info.contents.clear(); - - cr.delete(LauncherSettings.Favorites.getContentUri(info.id), null, null); - sBgDataModel.removeItem(appContext, info); - } - }; - runOnWorkerThread(r); - } - - /** * Set this as the current Launcher activity object for the loader. */ public void initialize(Callbacks callbacks) { @@ -2193,6 +1887,11 @@ public class LauncherModel extends BroadcastReceiver } }); } + + public ModelWriter getModelWriter() { + // Updates from model task, do not deal with icon position in hotseat. + return mModel.getWriter(false /* hasVerticalHotseat */); + } } public void updateAndBindShortcutInfo(final ShortcutInfo si, final ShortcutInfoCompat info) { diff --git a/src/com/android/launcher3/LauncherViewPropertyAnimator.java b/src/com/android/launcher3/LauncherViewPropertyAnimator.java deleted file mode 100644 index 4406a2c5c..000000000 --- a/src/com/android/launcher3/LauncherViewPropertyAnimator.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (C) 2012 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; - -import android.animation.Animator; -import android.animation.Animator.AnimatorListener; -import android.animation.TimeInterpolator; -import android.view.View; -import android.view.ViewPropertyAnimator; - -import java.util.ArrayList; -import java.util.EnumSet; - -public class LauncherViewPropertyAnimator extends Animator implements AnimatorListener { - - enum Properties { - TRANSLATION_X, - TRANSLATION_Y, - SCALE_X, - SCALE_Y, - ROTATION_Y, - ALPHA, - START_DELAY, - DURATION, - INTERPOLATOR, - WITH_LAYER - } - EnumSet<Properties> mPropertiesToSet = EnumSet.noneOf(Properties.class); - ViewPropertyAnimator mViewPropertyAnimator; - View mTarget; - - float mTranslationX; - float mTranslationY; - float mScaleX; - float mScaleY; - float mRotationY; - float mAlpha; - long mStartDelay; - long mDuration; - TimeInterpolator mInterpolator; - ArrayList<Animator.AnimatorListener> mListeners = new ArrayList<>(); - boolean mRunning = false; - FirstFrameAnimatorHelper mFirstFrameHelper; - - public LauncherViewPropertyAnimator(View target) { - mTarget = target; - } - - @Override - public void addListener(Animator.AnimatorListener listener) { - mListeners.add(listener); - } - - @Override - public void cancel() { - if (mViewPropertyAnimator != null) { - mViewPropertyAnimator.cancel(); - } - } - - @Override - public Animator clone() { - throw new RuntimeException("Not implemented"); - } - - @Override - public void end() { - throw new RuntimeException("Not implemented"); - } - - @Override - public long getDuration() { - return mDuration; - } - - @Override - public ArrayList<Animator.AnimatorListener> getListeners() { - return mListeners; - } - - @Override - public long getStartDelay() { - return mStartDelay; - } - - @Override - public void onAnimationCancel(Animator animation) { - for (int i = 0; i < mListeners.size(); i++) { - Animator.AnimatorListener listener = mListeners.get(i); - listener.onAnimationCancel(this); - } - mRunning = false; - } - - @Override - public void onAnimationEnd(Animator animation) { - for (int i = 0; i < mListeners.size(); i++) { - Animator.AnimatorListener listener = mListeners.get(i); - listener.onAnimationEnd(this); - } - mRunning = false; - } - - @Override - public void onAnimationRepeat(Animator animation) { - for (int i = 0; i < mListeners.size(); i++) { - Animator.AnimatorListener listener = mListeners.get(i); - listener.onAnimationRepeat(this); - } - } - - @Override - public void onAnimationStart(Animator animation) { - // This is the first time we get a handle to the internal ValueAnimator - // used by the ViewPropertyAnimator. - mFirstFrameHelper.onAnimationStart(animation); - - for (int i = 0; i < mListeners.size(); i++) { - Animator.AnimatorListener listener = mListeners.get(i); - listener.onAnimationStart(this); - } - mRunning = true; - } - - @Override - public boolean isRunning() { - return mRunning; - } - - @Override - public boolean isStarted() { - return mViewPropertyAnimator != null; - } - - @Override - public void removeAllListeners() { - mListeners.clear(); - } - - @Override - public void removeListener(Animator.AnimatorListener listener) { - mListeners.remove(listener); - } - - @Override - public Animator setDuration(long duration) { - mPropertiesToSet.add(Properties.DURATION); - mDuration = duration; - return this; - } - - @Override - public void setInterpolator(TimeInterpolator value) { - mPropertiesToSet.add(Properties.INTERPOLATOR); - mInterpolator = value; - } - - @Override - public void setStartDelay(long startDelay) { - mPropertiesToSet.add(Properties.START_DELAY); - mStartDelay = startDelay; - } - - @Override - public void setTarget(Object target) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void setupEndValues() { - - } - - @Override - public void setupStartValues() { - } - - @Override - public void start() { - mViewPropertyAnimator = mTarget.animate(); - - // FirstFrameAnimatorHelper hooks itself up to the updates on the animator, - // and then adjusts the play time to keep the first two frames jank-free - mFirstFrameHelper = new FirstFrameAnimatorHelper(mViewPropertyAnimator, mTarget); - - if (mPropertiesToSet.contains(Properties.TRANSLATION_X)) { - mViewPropertyAnimator.translationX(mTranslationX); - } - if (mPropertiesToSet.contains(Properties.TRANSLATION_Y)) { - mViewPropertyAnimator.translationY(mTranslationY); - } - if (mPropertiesToSet.contains(Properties.SCALE_X)) { - mViewPropertyAnimator.scaleX(mScaleX); - } - if (mPropertiesToSet.contains(Properties.ROTATION_Y)) { - mViewPropertyAnimator.rotationY(mRotationY); - } - if (mPropertiesToSet.contains(Properties.SCALE_Y)) { - mViewPropertyAnimator.scaleY(mScaleY); - } - if (mPropertiesToSet.contains(Properties.ALPHA)) { - mViewPropertyAnimator.alpha(mAlpha); - } - if (mPropertiesToSet.contains(Properties.START_DELAY)) { - mViewPropertyAnimator.setStartDelay(mStartDelay); - } - if (mPropertiesToSet.contains(Properties.DURATION)) { - mViewPropertyAnimator.setDuration(mDuration); - } - if (mPropertiesToSet.contains(Properties.INTERPOLATOR)) { - mViewPropertyAnimator.setInterpolator(mInterpolator); - } - if (mPropertiesToSet.contains(Properties.WITH_LAYER)) { - mViewPropertyAnimator.withLayer(); - } - mViewPropertyAnimator.setListener(this); - mViewPropertyAnimator.start(); - LauncherAnimUtils.cancelOnDestroyActivity(this); - } - - public LauncherViewPropertyAnimator translationX(float value) { - mPropertiesToSet.add(Properties.TRANSLATION_X); - mTranslationX = value; - return this; - } - - public LauncherViewPropertyAnimator translationY(float value) { - mPropertiesToSet.add(Properties.TRANSLATION_Y); - mTranslationY = value; - return this; - } - - public LauncherViewPropertyAnimator scaleX(float value) { - mPropertiesToSet.add(Properties.SCALE_X); - mScaleX = value; - return this; - } - - public LauncherViewPropertyAnimator scaleY(float value) { - mPropertiesToSet.add(Properties.SCALE_Y); - mScaleY = value; - return this; - } - - public LauncherViewPropertyAnimator rotationY(float value) { - mPropertiesToSet.add(Properties.ROTATION_Y); - mRotationY = value; - return this; - } - - public LauncherViewPropertyAnimator alpha(float value) { - mPropertiesToSet.add(Properties.ALPHA); - mAlpha = value; - return this; - } - - public LauncherViewPropertyAnimator withLayer() { - mPropertiesToSet.add(Properties.WITH_LAYER); - return this; - } -} diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 76e2073f2..fb6a611e7 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -47,6 +47,7 @@ import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.Interpolator; +import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.pageindicators.PageIndicator; import com.android.launcher3.util.LauncherEdgeEffect; import com.android.launcher3.util.Thunk; @@ -1998,11 +1999,12 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // Animate the drag view back to the original position private void animateDragViewToOriginalPosition() { if (mDragView != null) { - Animator anim = new LauncherViewPropertyAnimator(mDragView) - .translationX(0) - .translationY(0) - .scaleX(1) - .scaleY(1) + Animator anim = LauncherAnimUtils.ofPropertyValuesHolder(mDragView, + new PropertyListBuilder() + .scale(1) + .translationX(0) + .translationY(0) + .build()) .setDuration(REORDERING_DROP_REPOSITION_DURATION); anim.addListener(new AnimatorListenerAdapter() { @Override diff --git a/src/com/android/launcher3/PinchAnimationManager.java b/src/com/android/launcher3/PinchAnimationManager.java index bae246e9e..f8196e5f6 100644 --- a/src/com/android/launcher3/PinchAnimationManager.java +++ b/src/com/android/launcher3/PinchAnimationManager.java @@ -24,6 +24,7 @@ import android.util.Log; import android.view.View; import android.view.animation.LinearInterpolator; +import com.android.launcher3.anim.AnimationLayerSet; import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; @@ -211,7 +212,8 @@ public class PinchAnimationManager { } private void animateShowHideView(int index, final View view, boolean show) { - Animator animator = new LauncherViewPropertyAnimator(view).alpha(show ? 1 : 0).withLayer(); + Animator animator = ObjectAnimator.ofFloat(view, View.ALPHA, show ? 1 : 0); + animator.addListener(new AnimationLayerSet(view)); if (show) { view.setVisibility(View.VISIBLE); } else { diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java index 3512210c7..689cc9b3e 100644 --- a/src/com/android/launcher3/WidgetPreviewLoader.java +++ b/src/com/android/launcher3/WidgetPreviewLoader.java @@ -14,22 +14,24 @@ import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.graphics.Canvas; -import android.graphics.ColorMatrix; -import android.graphics.ColorMatrixColorFilter; +import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Handler; import android.os.UserHandle; +import android.support.v4.graphics.ColorUtils; import android.util.Log; import android.util.LongSparseArray; import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.compat.ShortcutConfigActivityInfo; import com.android.launcher3.compat.UserManagerCompat; +import com.android.launcher3.graphics.LauncherIcons; import com.android.launcher3.graphics.ShadowGenerator; import com.android.launcher3.model.WidgetItem; import com.android.launcher3.util.ComponentKey; @@ -366,30 +368,13 @@ public class WidgetPreviewLoader { drawable.setBounds(x, 0, x + previewWidth, previewHeight); drawable.draw(c); } else { - Resources res = mContext.getResources(); - float shadowBlur = res.getDimension(R.dimen.widget_preview_shadow_blur); - float keyShadowDistance = res.getDimension(R.dimen.widget_preview_key_shadow_distance); - float corner = res.getDimension(R.dimen.widget_preview_corner_radius); - - RectF boxRect = new RectF(shadowBlur, shadowBlur, - previewWidth - shadowBlur, previewHeight - shadowBlur - keyShadowDistance); - final Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); - p.setColor(0xFFFFFFFF); - - // Key shadow - p.setShadowLayer(shadowBlur, 0, keyShadowDistance, - ShadowGenerator.KEY_SHADOW_ALPHA << 24); - c.drawRoundRect(boxRect, corner, corner, p); - - // Ambient shadow - p.setShadowLayer(shadowBlur, 0, 0, ShadowGenerator.AMBIENT_SHADOW_ALPHA << 24); - c.drawRoundRect(boxRect, corner, corner, p); + RectF boxRect = drawBoxWithShadow(c, p, previewWidth, previewHeight); // Draw horizontal and vertical lines to represent individual columns. - p.clearShadowLayer(); p.setStyle(Paint.Style.STROKE); - p.setStrokeWidth(res.getDimension(R.dimen.widget_preview_cell_divider_width)); + p.setStrokeWidth(mContext.getResources() + .getDimension(R.dimen.widget_preview_cell_divider_width)); p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); float t = boxRect.left; @@ -426,47 +411,63 @@ public class WidgetPreviewLoader { return preview; } + private RectF drawBoxWithShadow(Canvas c, Paint p, int width, int height) { + Resources res = mContext.getResources(); + float shadowBlur = res.getDimension(R.dimen.widget_preview_shadow_blur); + float keyShadowDistance = res.getDimension(R.dimen.widget_preview_key_shadow_distance); + float corner = res.getDimension(R.dimen.widget_preview_corner_radius); + + RectF bounds = new RectF(shadowBlur, shadowBlur, + width - shadowBlur, height - shadowBlur - keyShadowDistance); + p.setColor(Color.WHITE); + + // Key shadow + p.setShadowLayer(shadowBlur, 0, keyShadowDistance, + ShadowGenerator.KEY_SHADOW_ALPHA << 24); + c.drawRoundRect(bounds, corner, corner, p); + + // Ambient shadow + p.setShadowLayer(shadowBlur, 0, 0, + ColorUtils.setAlphaComponent(Color.BLACK, ShadowGenerator.AMBIENT_SHADOW_ALPHA)); + c.drawRoundRect(bounds, corner, corner, p); + + p.clearShadowLayer(); + return bounds; + } + private Bitmap generateShortcutPreview(BaseActivity launcher, ShortcutConfigActivityInfo info, int maxWidth, int maxHeight, Bitmap preview) { + int iconSize = launcher.getDeviceProfile().iconSizePx; + int padding = launcher.getResources() + .getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding); + + int size = iconSize + 2 * padding; + if (maxHeight < size || maxWidth < size) { + throw new RuntimeException("Max size is too small for preview"); + } final Canvas c = new Canvas(); - if (preview == null) { - preview = Bitmap.createBitmap(maxWidth, maxHeight, Config.ARGB_8888); + if (preview == null || preview.getWidth() < size || preview.getHeight() < size) { + preview = Bitmap.createBitmap(size, size, Config.ARGB_8888); c.setBitmap(preview); - } else if (preview.getWidth() != maxWidth || preview.getHeight() != maxHeight) { - throw new RuntimeException("Improperly sized bitmap passed as argument"); } else { + if (preview.getWidth() > size || preview.getHeight() > size) { + preview.reconfigure(size, size, preview.getConfig()); + } + // Reusing bitmap. Clear it. c.setBitmap(preview); c.drawColor(0, PorterDuff.Mode.CLEAR); } + Paint p = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + RectF boxRect = drawBoxWithShadow(c, p, size, size); - Drawable icon = mutateOnMainThread(info.getFullResIcon(mIconCache)); - icon.setFilterBitmap(true); - - // Draw a desaturated/scaled version of the icon in the background as a watermark - ColorMatrix colorMatrix = new ColorMatrix(); - colorMatrix.setSaturation(0); - icon.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); - icon.setAlpha((int) (255 * 0.06f)); - - Resources res = mContext.getResources(); - int paddingTop = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_top); - int paddingLeft = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_left); - int paddingRight = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_right); - int scaledIconWidth = (maxWidth - paddingLeft - paddingRight); - icon.setBounds(paddingLeft, paddingTop, - paddingLeft + scaledIconWidth, paddingTop + scaledIconWidth); - icon.draw(c); - - // Draw the final icon at top left corner. - // TODO: use top right for RTL - int appIconSize = launcher.getDeviceProfile().iconSizePx; - - icon.setAlpha(255); - icon.setColorFilter(null); - icon.setBounds(0, 0, appIconSize, appIconSize); - icon.draw(c); + Bitmap icon = LauncherIcons.createScaledBitmapWithoutShadow( + mutateOnMainThread(info.getFullResIcon(mIconCache)), mContext); + Rect src = new Rect(0, 0, icon.getWidth(), icon.getHeight()); + boxRect.set(0, 0, iconSize, iconSize); + boxRect.offset(padding, padding); + c.drawBitmap(icon, src, boxRect, p); c.setBitmap(null); return preview; } @@ -664,7 +665,6 @@ public class WidgetPreviewLoader { private static final class WidgetCacheKey extends ComponentKey { - // TODO: remove dependency on size @Thunk final String size; public WidgetCacheKey(ComponentName componentName, UserHandle user, String size) { diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 3aa882587..56aa69e5c 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -2654,8 +2654,8 @@ public class Workspace extends PagedView } } - LauncherModel.modifyItemInDatabase(mLauncher, info, container, screenId, lp.cellX, - lp.cellY, item.spanX, item.spanY); + mLauncher.getModelWriter().modifyItemInDatabase(info, container, screenId, + lp.cellX, lp.cellY, item.spanX, item.spanY); } else { if (!returnToOriginalCellToPreventShuffling) { onNoCellFound(dropTargetLayout); @@ -3387,7 +3387,7 @@ public class Workspace extends PagedView } // Add the item to DB before adding to screen ensures that the container and other // values of the info is properly updated. - LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId, + mLauncher.getModelWriter().addOrMoveItemInDatabase(info, container, screenId, mTargetCell[0], mTargetCell[1]); addInScreen(view, container, screenId, mTargetCell[0], mTargetCell[1], @@ -4025,7 +4025,7 @@ public class Workspace extends PagedView HashSet<String> packages = new HashSet<>(1); packages.add(packageName); ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(packages, user); - LauncherModel.deleteItemsFromDatabase(mLauncher, matcher); + mLauncher.getModelWriter().deleteItemsFromDatabase(matcher); removeItemsByMatcher(matcher); } diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java index 6a71befe4..482a2c93b 100644 --- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java +++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java @@ -31,6 +31,7 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.DecelerateInterpolator; import com.android.launcher3.anim.AnimationLayerSet; +import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.util.Thunk; @@ -337,10 +338,9 @@ public class WorkspaceStateTransitionAnimation { if (animated) { float oldBackgroundAlpha = cl.getBackgroundAlpha(); if (initialAlpha != finalAlpha) { - LauncherViewPropertyAnimator alphaAnim = - new LauncherViewPropertyAnimator(cl.getShortcutsAndWidgets()); - alphaAnim.alpha(finalAlpha) - .setDuration(duration) + Animator alphaAnim = ObjectAnimator.ofFloat( + cl.getShortcutsAndWidgets(), View.ALPHA, finalAlpha); + alphaAnim.setDuration(duration) .setInterpolator(mZoomInInterpolator); mStateAnimator.play(alphaAnim); } @@ -377,17 +377,16 @@ public class WorkspaceStateTransitionAnimation { .animateAlphaAtIndex(finalQsbAlpha, Workspace.QSB_ALPHA_INDEX_STATE_CHANGE); if (animated) { - LauncherViewPropertyAnimator scale = new LauncherViewPropertyAnimator(mWorkspace); - scale.scaleX(mNewScale) - .scaleY(mNewScale) - .translationY(finalWorkspaceTranslationY) - .setDuration(duration) - .setInterpolator(mZoomInInterpolator); + Animator scale = LauncherAnimUtils.ofPropertyValuesHolder(mWorkspace, + new PropertyListBuilder().scale(mNewScale) + .translationY(finalWorkspaceTranslationY).build()) + .setDuration(duration); + scale.setInterpolator(mZoomInInterpolator); mStateAnimator.play(scale); Animator hotseatAlpha = mWorkspace.createHotseatAlphaAnimator(finalHotseatAlpha); - LauncherViewPropertyAnimator overviewPanelAlpha = - new LauncherViewPropertyAnimator(overviewPanel).alpha(finalOverviewPanelAlpha); + Animator overviewPanelAlpha = ObjectAnimator.ofFloat( + overviewPanel, View.ALPHA, finalOverviewPanelAlpha); overviewPanelAlpha.addListener(new AlphaUpdateListener(overviewPanel, accessibilityEnabled)); diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java index b77493bef..a476650c9 100644 --- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java +++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java @@ -168,7 +168,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme public void run() { if (item instanceof AppInfo) { ShortcutInfo info = ((AppInfo) item).makeShortcut(); - LauncherModel.addItemToDatabase(mLauncher, info, + mLauncher.getModelWriter().addItemToDatabase(info, LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId, coordinates[0], coordinates[1]); @@ -194,7 +194,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme final int[] coordinates = new int[2]; final long screenId = findSpaceOnWorkspace(item, coordinates); - LauncherModel.moveItemInDatabase(mLauncher, info, + mLauncher.getModelWriter().moveItemInDatabase(info, LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId, coordinates[0], coordinates[1]); @@ -304,7 +304,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme ((LauncherAppWidgetHostView) host).updateAppWidgetSize(null, sizeRange.left, sizeRange.top, sizeRange.right, sizeRange.bottom); host.requestLayout(); - LauncherModel.updateItemInDatabase(mLauncher, info); + mLauncher.getModelWriter().updateItemInDatabase(info); announceConfirmation(mLauncher.getString(R.string.widget_resized, info.spanX, info.spanY)); } diff --git a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java index f7ca7034d..b784fe7f8 100644 --- a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java +++ b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java @@ -59,7 +59,7 @@ public class ShortcutMenuAccessibilityDelegate extends LauncherAccessibilityDele Runnable onComplete = new Runnable() { @Override public void run() { - LauncherModel.addItemToDatabase(mLauncher, info, + mLauncher.getModelWriter().addItemToDatabase(info, LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId, coordinates[0], coordinates[1]); ArrayList<ItemInfo> itemList = new ArrayList<>(); diff --git a/src/com/android/launcher3/anim/AnimationLayerSet.java b/src/com/android/launcher3/anim/AnimationLayerSet.java index d2f5e78a2..14bcd1718 100644 --- a/src/com/android/launcher3/anim/AnimationLayerSet.java +++ b/src/com/android/launcher3/anim/AnimationLayerSet.java @@ -29,7 +29,16 @@ import java.util.Map; */ public class AnimationLayerSet extends AnimatorListenerAdapter { - private final HashMap<View, Integer> mViewsToLayerTypeMap = new HashMap<>(); + private final HashMap<View, Integer> mViewsToLayerTypeMap; + + public AnimationLayerSet() { + mViewsToLayerTypeMap = new HashMap<>(); + } + + public AnimationLayerSet(View v) { + mViewsToLayerTypeMap = new HashMap<>(1); + addView(v); + } public void addView(View v) { mViewsToLayerTypeMap.put(v, v.getLayerType()); diff --git a/src/com/android/launcher3/anim/PropertyListBuilder.java b/src/com/android/launcher3/anim/PropertyListBuilder.java new file mode 100644 index 000000000..33e7f6659 --- /dev/null +++ b/src/com/android/launcher3/anim/PropertyListBuilder.java @@ -0,0 +1,50 @@ +package com.android.launcher3.anim; + +import android.animation.PropertyValuesHolder; +import android.view.View; + +import java.util.ArrayList; + +/** + * Helper class to build a list of {@link PropertyValuesHolder} for view properties + */ +public class PropertyListBuilder { + + private final ArrayList<PropertyValuesHolder> mProperties = new ArrayList<>(); + + public PropertyListBuilder translationX(float value) { + mProperties.add(PropertyValuesHolder.ofFloat(View.TRANSLATION_X, value)); + return this; + } + + public PropertyListBuilder translationY(float value) { + mProperties.add(PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, value)); + return this; + } + + public PropertyListBuilder scaleX(float value) { + mProperties.add(PropertyValuesHolder.ofFloat(View.SCALE_X, value)); + return this; + } + + public PropertyListBuilder scaleY(float value) { + mProperties.add(PropertyValuesHolder.ofFloat(View.SCALE_Y, value)); + return this; + } + + /** + * Helper method to set both scaleX and scaleY + */ + public PropertyListBuilder scale(float value) { + return scaleX(value).scaleY(value); + } + + public PropertyListBuilder alpha(float value) { + mProperties.add(PropertyValuesHolder.ofFloat(View.ALPHA, value)); + return this; + } + + public PropertyValuesHolder[] build() { + return mProperties.toArray(new PropertyValuesHolder[mProperties.size()]); + } +} diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java index eacea4add..3d28f2291 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -355,7 +355,7 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC // gets saved. String newTitle = mFolderName.getText().toString(); mInfo.setTitle(newTitle); - LauncherModel.updateItemInDatabase(mLauncher, mInfo); + mLauncher.getModelWriter().updateItemInDatabase(mInfo); Utilities.sendCustomAccessibilityEvent( this, AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED, @@ -445,7 +445,7 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC // TODO: Remove this, as with multi-page folders, there will never be any overflow for (ShortcutInfo item: overflow) { mInfo.remove(item, false); - LauncherModel.deleteItemFromDatabase(mLauncher, item); + mLauncher.getModelWriter().deleteItemFromDatabase(item); } DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams(); @@ -647,7 +647,8 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC mPageIndicator.playEntryAnimation(); if (updateAnimationFlag) { - mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, mLauncher); + mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, + mLauncher.getModelWriter()); } } }); @@ -973,7 +974,8 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC // been refreshed yet. if (getItemCount() <= mContent.itemsPerPage()) { // Show the animation, next time something is added to the folder. - mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, false, mLauncher); + mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, false, + mLauncher.getModelWriter()); } if (!isFlingToDelete) { @@ -1022,7 +1024,7 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC items.add(info); } - LauncherModel.moveItemsInDatabase(mLauncher, items, mInfo.id, 0); + mLauncher.getModelWriter().moveItemsInDatabase(items, mInfo.id, 0); } public void notifyDrop() { @@ -1189,8 +1191,8 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC mInfo.screenId); ShortcutInfo finalItem = mInfo.contents.remove(0); newIcon = mLauncher.createShortcut(cellLayout, finalItem); - LauncherModel.addOrMoveItemInDatabase(mLauncher, finalItem, mInfo.container, - mInfo.screenId, mInfo.cellX, mInfo.cellY); + mLauncher.getModelWriter().addOrMoveItemInDatabase(finalItem, + mInfo.container, mInfo.screenId, mInfo.cellX, mInfo.cellY); } // Remove the folder @@ -1301,8 +1303,8 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC currentDragView = mContent.createAndAddViewForRank(si, mEmptyCellRank); // Actually move the item in the database if it was an external drag. Call this // before creating the view, so that ShortcutInfo is updated appropriately. - LauncherModel.addOrMoveItemInDatabase( - mLauncher, si, mInfo.id, 0, si.cellX, si.cellY); + mLauncher.getModelWriter().addOrMoveItemInDatabase( + si, mInfo.id, 0, si.cellX, si.cellY); // We only need to update the locations if it doesn't get handled in #onDropCompleted. if (d.dragSource != this) { @@ -1342,7 +1344,7 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC if (mContent.getPageCount() > 1) { // The animation has already been shown while opening the folder. - mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, mLauncher); + mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, mLauncher.getModelWriter()); } if (d.stateAnnouncer != null) { @@ -1366,8 +1368,8 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC public void onAdd(ShortcutInfo item) { mContent.createAndAddViewForRank(item, mContent.allocateRankForNewItem()); mItemsInvalidated = true; - LauncherModel.addOrMoveItemInDatabase( - mLauncher, item, mInfo.id, 0, item.cellX, item.cellY); + mLauncher.getModelWriter().addOrMoveItemInDatabase( + item, mInfo.id, 0, item.cellX, item.cellY); } public void onRemove(ShortcutInfo item) { diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java index 4a2a7350b..9dfdfdc19 100644 --- a/src/com/android/launcher3/folder/FolderPagedView.java +++ b/src/com/android/launcher3/folder/FolderPagedView.java @@ -336,7 +336,7 @@ public class FolderPagedView extends PagedView { info.cellY = newY; info.rank = rank; if (saveChanges) { - LauncherModel.addOrMoveItemInDatabase(getContext(), info, + mFolder.mLauncher.getModelWriter().addOrMoveItemInDatabase(info, mFolder.mInfo.id, 0, info.cellX, info.cellY); } } diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java index c97b3b5cf..969605483 100644 --- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java +++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java @@ -95,7 +95,9 @@ public class AddWorkspaceItemsTask extends ExtendedModelTask { } // Add the shortcut to the db - addItemToDatabase(context, itemInfo, screenId, cordinates); + getModelWriter().addItemToDatabase(itemInfo, + LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId, + cordinates[0], cordinates[1]); // Save the ShortcutInfo for binding in the workspace addedItemsFinal.add(itemInfo); @@ -129,11 +131,6 @@ public class AddWorkspaceItemsTask extends ExtendedModelTask { } } - protected void addItemToDatabase(Context context, ItemInfo item, long screenId, int[] pos) { - LauncherModel.addItemToDatabase(context, item, - LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId, pos[0], pos[1]); - } - protected void updateScreens(Context context, ArrayList<Long> workspaceScreens) { LauncherModel.updateWorkspaceScreenOrder(context, workspaceScreens); } diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java index bbc7ae461..e50b912f6 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationTask.java +++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java @@ -27,6 +27,7 @@ import com.android.launcher3.Workspace; import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.compat.PackageInstallerCompat; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.logging.FileLog; import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.LongArrayMap; @@ -889,6 +890,23 @@ public class GridSizeMigrationTask { .apply(); } + public static void logDeviceProfileIfChanged(InvariantDeviceProfile idp, Context context) { + SharedPreferences prefs = Utilities.getPrefs(context); + String gridSizeString = getPointString(idp.numColumns, idp.numRows); + + int oldHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons); + String oldSize = prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString); + if (gridSizeString.equals(oldSize) && idp.numHotseatIcons == oldHotseatCount) { + // Skip if workspace and hotseat sizes have not changed. + return; + } + + FileLog.e(TAG, "Grid size changed" + gridSizeString); + FileLog.e(TAG, " oldSize: " + oldSize + " , hotseat: " + oldHotseatCount); + FileLog.e(TAG, " newSize: " + gridSizeString + " , hotseat: " + idp.numHotseatIcons); + idp.dumpDisplayInfo(context); + } + /** * Migrates the workspace and hotseat in case their sizes changed. * @return false if the migration failed. @@ -900,7 +918,7 @@ public class GridSizeMigrationTask { String gridSizeString = getPointString(idp.numColumns, idp.numRows); if (gridSizeString.equals(prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, "")) && - idp.numHotseatIcons != prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons)) { + idp.numHotseatIcons == prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons)) { // Skip if workspace and hotseat sizes have not changed. return true; } diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java new file mode 100644 index 000000000..4931dca14 --- /dev/null +++ b/src/com/android/launcher3/model/ModelWriter.java @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.model; + +import android.content.ContentProviderOperation; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.net.Uri; +import android.util.Log; + +import com.android.launcher3.FolderInfo; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherModel; +import com.android.launcher3.LauncherProvider; +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.LauncherSettings.Settings; +import com.android.launcher3.ShortcutInfo; +import com.android.launcher3.util.ContentWriter; +import com.android.launcher3.util.ItemInfoMatcher; +import com.android.launcher3.util.LooperExecuter; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.concurrent.Executor; + +/** + * Class for handling model updates. + */ +public class ModelWriter { + + private static final String TAG = "ModelWriter"; + + private final Context mContext; + private final BgDataModel mBgDataModel; + private final Executor mWorkerExecutor; + private final boolean mHasVerticalHotseat; + + public ModelWriter(Context context, BgDataModel dataModel, boolean hasVerticalHotseat) { + mContext = context; + mBgDataModel = dataModel; + mWorkerExecutor = new LooperExecuter(LauncherModel.getWorkerLooper()); + mHasVerticalHotseat = hasVerticalHotseat; + } + + private void updateItemInfoProps( + ItemInfo item, long container, long screenId, int cellX, int cellY) { + item.container = container; + item.cellX = cellX; + item.cellY = cellY; + // We store hotseat items in canonical form which is this orientation invariant position + // in the hotseat + if (container == Favorites.CONTAINER_HOTSEAT) { + item.screenId = mHasVerticalHotseat + ? LauncherAppState.getIDP(mContext).numHotseatIcons - cellY - 1 : cellX; + } else { + item.screenId = screenId; + } + } + + /** + * Adds an item to the DB if it was not created previously, or move it to a new + * <container, screen, cellX, cellY> + */ + public void addOrMoveItemInDatabase(ItemInfo item, + long container, long screenId, int cellX, int cellY) { + if (item.container == ItemInfo.NO_ID) { + // From all apps + addItemToDatabase(item, container, screenId, cellX, cellY); + } else { + // From somewhere else + moveItemInDatabase(item, container, screenId, cellX, cellY); + } + } + + private void checkItemInfoLocked(long itemId, ItemInfo item, StackTraceElement[] stackTrace) { + ItemInfo modelItem = mBgDataModel.itemsIdMap.get(itemId); + if (modelItem != null && item != modelItem) { + // check all the data is consistent + if (modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) { + ShortcutInfo modelShortcut = (ShortcutInfo) modelItem; + ShortcutInfo shortcut = (ShortcutInfo) item; + if (modelShortcut.title.toString().equals(shortcut.title.toString()) && + modelShortcut.intent.filterEquals(shortcut.intent) && + modelShortcut.id == shortcut.id && + modelShortcut.itemType == shortcut.itemType && + modelShortcut.container == shortcut.container && + modelShortcut.screenId == shortcut.screenId && + modelShortcut.cellX == shortcut.cellX && + modelShortcut.cellY == shortcut.cellY && + modelShortcut.spanX == shortcut.spanX && + modelShortcut.spanY == shortcut.spanY) { + // For all intents and purposes, this is the same object + return; + } + } + + // the modelItem needs to match up perfectly with item if our model is + // to be consistent with the database-- for now, just require + // modelItem == item or the equality check above + String msg = "item: " + ((item != null) ? item.toString() : "null") + + "modelItem: " + + ((modelItem != null) ? modelItem.toString() : "null") + + "Error: ItemInfo passed to checkItemInfo doesn't match original"; + RuntimeException e = new RuntimeException(msg); + if (stackTrace != null) { + e.setStackTrace(stackTrace); + } + throw e; + } + } + + /** + * Move an item in the DB to a new <container, screen, cellX, cellY> + */ + public void moveItemInDatabase(final ItemInfo item, + long container, long screenId, int cellX, int cellY) { + updateItemInfoProps(item, container, screenId, cellX, cellY); + + final ContentWriter writer = new ContentWriter(mContext) + .put(Favorites.CONTAINER, item.container) + .put(Favorites.CELLX, item.cellX) + .put(Favorites.CELLY, item.cellY) + .put(Favorites.RANK, item.rank) + .put(Favorites.SCREEN, item.screenId); + + mWorkerExecutor.execute(new UpdateItemRunnable(item, writer)); + } + + /** + * Move items in the DB to a new <container, screen, cellX, cellY>. We assume that the + * cellX, cellY have already been updated on the ItemInfos. + */ + public void moveItemsInDatabase(final ArrayList<ItemInfo> items, long container, int screen) { + ArrayList<ContentValues> contentValues = new ArrayList<>(); + int count = items.size(); + + for (int i = 0; i < count; i++) { + ItemInfo item = items.get(i); + updateItemInfoProps(item, container, screen, item.cellX, item.cellY); + + final ContentValues values = new ContentValues(); + values.put(Favorites.CONTAINER, item.container); + values.put(Favorites.CELLX, item.cellX); + values.put(Favorites.CELLY, item.cellY); + values.put(Favorites.RANK, item.rank); + values.put(Favorites.SCREEN, item.screenId); + + contentValues.add(values); + } + mWorkerExecutor.execute(new UpdateItemsRunnable(items, contentValues)); + } + + /** + * Move and/or resize item in the DB to a new <container, screen, cellX, cellY, spanX, spanY> + */ + public void modifyItemInDatabase(final ItemInfo item, + long container, long screenId, int cellX, int cellY, int spanX, int spanY) { + updateItemInfoProps(item, container, screenId, cellX, cellY); + item.spanX = spanX; + item.spanY = spanY; + + final ContentWriter writer = new ContentWriter(mContext) + .put(Favorites.CONTAINER, item.container) + .put(Favorites.CELLX, item.cellX) + .put(Favorites.CELLY, item.cellY) + .put(Favorites.RANK, item.rank) + .put(Favorites.SPANX, item.spanX) + .put(Favorites.SPANY, item.spanY) + .put(Favorites.SCREEN, item.screenId); + + mWorkerExecutor.execute(new UpdateItemRunnable(item, writer)); + } + + /** + * Update an item to the database in a specified container. + */ + public void updateItemInDatabase(ItemInfo item) { + ContentWriter writer = new ContentWriter(mContext); + item.onAddToDatabase(writer); + mWorkerExecutor.execute(new UpdateItemRunnable(item, writer)); + } + + /** + * Add an item to the database in a specified container. Sets the container, screen, cellX and + * cellY fields of the item. Also assigns an ID to the item. + */ + public void addItemToDatabase(final ItemInfo item, + long container, long screenId, int cellX, int cellY) { + updateItemInfoProps(item, container, screenId, cellX, cellY); + + final ContentWriter writer = new ContentWriter(mContext); + final ContentResolver cr = mContext.getContentResolver(); + item.onAddToDatabase(writer); + + item.id = Settings.call(cr, Settings.METHOD_NEW_ITEM_ID).getLong(Settings.EXTRA_VALUE); + writer.put(Favorites._ID, item.id); + + final StackTraceElement[] stackTrace = new Throwable().getStackTrace(); + mWorkerExecutor.execute(new Runnable() { + public void run() { + cr.insert(Favorites.CONTENT_URI, writer.getValues(mContext)); + + synchronized (mBgDataModel) { + checkItemInfoLocked(item.id, item, stackTrace); + mBgDataModel.addItem(mContext, item, true); + } + } + }); + } + + /** + * Removes the specified item from the database + */ + public void deleteItemFromDatabase(ItemInfo item) { + deleteItemsFromDatabase(Arrays.asList(item)); + } + + /** + * Removes all the items from the database matching {@param matcher}. + */ + public void deleteItemsFromDatabase(ItemInfoMatcher matcher) { + deleteItemsFromDatabase(matcher.filterItemInfos(mBgDataModel.itemsIdMap)); + } + + /** + * Removes the specified items from the database + */ + public void deleteItemsFromDatabase(final Iterable<? extends ItemInfo> items) { + mWorkerExecutor.execute(new Runnable() { + public void run() { + for (ItemInfo item : items) { + final Uri uri = Favorites.getContentUri(item.id); + mContext.getContentResolver().delete(uri, null, null); + + mBgDataModel.removeItem(mContext, item); + } + } + }); + } + + /** + * Remove the specified folder and all its contents from the database. + */ + public void deleteFolderAndContentsFromDatabase(final FolderInfo info) { + mWorkerExecutor.execute(new Runnable() { + public void run() { + ContentResolver cr = mContext.getContentResolver(); + cr.delete(LauncherSettings.Favorites.CONTENT_URI, + LauncherSettings.Favorites.CONTAINER + "=" + info.id, null); + mBgDataModel.removeItem(mContext, info.contents); + info.contents.clear(); + + cr.delete(LauncherSettings.Favorites.getContentUri(info.id), null, null); + mBgDataModel.removeItem(mContext, info); + } + }); + } + + private class UpdateItemRunnable extends UpdateItemBaseRunnable { + private final ItemInfo mItem; + private final ContentWriter mWriter; + private final long mItemId; + + UpdateItemRunnable(ItemInfo item, ContentWriter writer) { + mItem = item; + mWriter = writer; + mItemId = item.id; + } + + @Override + public void run() { + Uri uri = Favorites.getContentUri(mItemId); + mContext.getContentResolver().update(uri, mWriter.getValues(mContext), null, null); + updateItemArrays(mItem, mItemId); + } + } + + private class UpdateItemsRunnable extends UpdateItemBaseRunnable { + private final ArrayList<ContentValues> mValues; + private final ArrayList<ItemInfo> mItems; + + UpdateItemsRunnable(ArrayList<ItemInfo> items, ArrayList<ContentValues> values) { + mValues = values; + mItems = items; + } + + @Override + public void run() { + ArrayList<ContentProviderOperation> ops = new ArrayList<>(); + int count = mItems.size(); + for (int i = 0; i < count; i++) { + ItemInfo item = mItems.get(i); + final long itemId = item.id; + final Uri uri = Favorites.getContentUri(itemId); + ContentValues values = mValues.get(i); + + ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build()); + updateItemArrays(item, itemId); + } + try { + mContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY, ops); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + private abstract class UpdateItemBaseRunnable implements Runnable { + private final StackTraceElement[] mStackTrace; + + UpdateItemBaseRunnable() { + mStackTrace = new Throwable().getStackTrace(); + } + + protected void updateItemArrays(ItemInfo item, long itemId) { + // Lock on mBgLock *after* the db operation + synchronized (mBgDataModel) { + checkItemInfoLocked(itemId, item, mStackTrace); + + if (item.container != Favorites.CONTAINER_DESKTOP && + item.container != Favorites.CONTAINER_HOTSEAT) { + // Item is in a folder, make sure this folder exists + if (!mBgDataModel.folders.containsKey(item.container)) { + // An items container is being set to a that of an item which is not in + // the list of Folders. + String msg = "item: " + item + " container being set to: " + + item.container + ", not in the list of folders"; + Log.e(TAG, msg); + } + } + + // Items are added/removed from the corresponding FolderInfo elsewhere, such + // as in Workspace.onDrop. Here, we just add/remove them from the list of items + // that are on the desktop, as appropriate + ItemInfo modelItem = mBgDataModel.itemsIdMap.get(itemId); + if (modelItem != null && + (modelItem.container == Favorites.CONTAINER_DESKTOP || + modelItem.container == Favorites.CONTAINER_HOTSEAT)) { + switch (modelItem.itemType) { + case Favorites.ITEM_TYPE_APPLICATION: + case Favorites.ITEM_TYPE_SHORTCUT: + case Favorites.ITEM_TYPE_DEEP_SHORTCUT: + case Favorites.ITEM_TYPE_FOLDER: + if (!mBgDataModel.workspaceItems.contains(modelItem)) { + mBgDataModel.workspaceItems.add(modelItem); + } + break; + default: + break; + } + } else { + mBgDataModel.workspaceItems.remove(modelItem); + } + } + } + } +} diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index 211b9793f..ee7186aa4 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -270,7 +270,7 @@ public class PackageUpdatedTask extends ExtendedModelTask { updatedShortcuts.add(si); } if (infoUpdated) { - LauncherModel.updateItemInDatabase(context, si); + getModelWriter().updateItemInDatabase(si); } } else if (info instanceof LauncherAppWidgetInfo && mOp == OP_ADD) { LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info; @@ -287,7 +287,7 @@ public class PackageUpdatedTask extends ExtendedModelTask { widgetInfo.restoreStatus |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY; widgets.add(widgetInfo); - LauncherModel.updateItemInDatabase(context, widgetInfo); + getModelWriter().updateItemInDatabase(widgetInfo); } } } @@ -295,7 +295,7 @@ public class PackageUpdatedTask extends ExtendedModelTask { bindUpdatedShortcuts(updatedShortcuts, removedShortcuts, mUser); if (!removedShortcuts.isEmpty()) { - LauncherModel.deleteItemsFromDatabase(context, removedShortcuts); + getModelWriter().deleteItemsFromDatabase(removedShortcuts); } if (!widgets.isEmpty()) { @@ -332,10 +332,10 @@ public class PackageUpdatedTask extends ExtendedModelTask { } if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) { - LauncherModel.deleteItemsFromDatabase( - context, ItemInfoMatcher.ofPackages(removedPackages, mUser)); - LauncherModel.deleteItemsFromDatabase( - context, ItemInfoMatcher.ofComponents(removedComponents, mUser)); + getModelWriter().deleteItemsFromDatabase( + ItemInfoMatcher.ofPackages(removedPackages, mUser)); + getModelWriter().deleteItemsFromDatabase( + ItemInfoMatcher.ofComponents(removedComponents, mUser)); // Remove any queued items from the install queue InstallShortcutReceiver.removeFromInstallQueue(context, removedPackages, mUser); diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java index ba7112fd9..d8a429cba 100644 --- a/src/com/android/launcher3/model/ShortcutsChangedTask.java +++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java @@ -104,7 +104,7 @@ public class ShortcutsChangedTask extends ExtendedModelTask { bindUpdatedShortcuts(updatedShortcutInfos, removedShortcutInfos, mUser); if (!removedShortcutInfos.isEmpty()) { - LauncherModel.deleteItemsFromDatabase(context, removedShortcutInfos); + getModelWriter().deleteItemsFromDatabase(removedShortcutInfos); } if (mUpdateIdMap) { diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java index 25f2f9d50..363f1eeb1 100644 --- a/src/com/android/launcher3/model/UserLockStateChangedTask.java +++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java @@ -95,7 +95,7 @@ public class UserLockStateChangedTask extends ExtendedModelTask { } bindUpdatedShortcuts(updatedShortcutInfos, deletedShortcutInfos, mUser); if (!deletedShortcutInfos.isEmpty()) { - LauncherModel.deleteItemsFromDatabase(context, deletedShortcutInfos); + getModelWriter().deleteItemsFromDatabase(deletedShortcutInfos); } // Remove shortcut id map for that user diff --git a/src/com/android/launcher3/notification/NotificationFooterLayout.java b/src/com/android/launcher3/notification/NotificationFooterLayout.java index 58789f6e2..57ec5d17c 100644 --- a/src/com/android/launcher3/notification/NotificationFooterLayout.java +++ b/src/com/android/launcher3/notification/NotificationFooterLayout.java @@ -19,6 +19,7 @@ package com.android.launcher3.notification; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Rect; @@ -30,8 +31,8 @@ import android.widget.TextView; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAnimUtils; -import com.android.launcher3.LauncherViewPropertyAnimator; import com.android.launcher3.R; +import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.graphics.IconPalette; import com.android.launcher3.popup.PopupContainerWithArrow; @@ -154,10 +155,9 @@ public class NotificationFooterLayout extends LinearLayout { Rect fromBounds = sTempRect; firstNotification.getGlobalVisibleRect(fromBounds); float scale = (float) toBounds.height() / fromBounds.height(); - Animator moveAndScaleIcon = new LauncherViewPropertyAnimator(firstNotification) - .translationY(toBounds.top - fromBounds.top - + (fromBounds.height() * scale - fromBounds.height()) / 2) - .scaleX(scale).scaleY(scale); + Animator moveAndScaleIcon = LauncherAnimUtils.ofPropertyValuesHolder(firstNotification, + new PropertyListBuilder().scale(scale).translationY(toBounds.top - fromBounds.top + + (fromBounds.height() * scale - fromBounds.height()) / 2).build()); moveAndScaleIcon.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -172,7 +172,7 @@ public class NotificationFooterLayout extends LinearLayout { - (mOverflowNotifications.isEmpty() ? 0 : 1); for (int i = 1; i < numIcons; i++) { final View child = mIconRow.getChildAt(i); - Animator shiftChild = new LauncherViewPropertyAnimator(child).translationX(-gapWidth); + Animator shiftChild = ObjectAnimator.ofFloat(child, TRANSLATION_X, -gapWidth); shiftChild.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java index 206bb31d4..5c16176f5 100644 --- a/src/com/android/launcher3/notification/NotificationListener.java +++ b/src/com/android/launcher3/notification/NotificationListener.java @@ -80,9 +80,9 @@ public class NotificationListener extends NotificationListenerService { switch (message.what) { case MSG_NOTIFICATION_POSTED: if (sNotificationsChangedListener != null) { - Pair<PackageUserKey, String> pair - = (Pair<PackageUserKey, String>) message.obj; - sNotificationsChangedListener.onNotificationPosted(pair.first, pair.second); + NotificationPostedMsg msg = (NotificationPostedMsg) message.obj; + sNotificationsChangedListener.onNotificationPosted(msg.packageUserKey, + msg.notificationKey, msg.shouldBeFilteredOut); } break; case MSG_NOTIFICATION_REMOVED: @@ -149,23 +149,32 @@ public class NotificationListener extends NotificationListenerService { @Override public void onNotificationPosted(final StatusBarNotification sbn) { super.onNotificationPosted(sbn); - if (!shouldBeFilteredOut(sbn.getNotification())) { - Pair<PackageUserKey, String> packageUserKeyAndNotificationKey - = new Pair<>(PackageUserKey.fromNotification(sbn), sbn.getKey()); - mWorkerHandler.obtainMessage(MSG_NOTIFICATION_POSTED, packageUserKeyAndNotificationKey) - .sendToTarget(); + mWorkerHandler.obtainMessage(MSG_NOTIFICATION_POSTED, new NotificationPostedMsg(sbn)) + .sendToTarget(); + } + + /** + * An object containing data to send to MSG_NOTIFICATION_POSTED targets. + */ + private class NotificationPostedMsg { + PackageUserKey packageUserKey; + String notificationKey; + boolean shouldBeFilteredOut; + + NotificationPostedMsg(StatusBarNotification sbn) { + packageUserKey = PackageUserKey.fromNotification(sbn); + notificationKey = sbn.getKey(); + shouldBeFilteredOut = shouldBeFilteredOut(sbn.getNotification()); } } @Override public void onNotificationRemoved(final StatusBarNotification sbn) { super.onNotificationRemoved(sbn); - if (!shouldBeFilteredOut(sbn.getNotification())) { - Pair<PackageUserKey, String> packageUserKeyAndNotificationKey - = new Pair<>(PackageUserKey.fromNotification(sbn), sbn.getKey()); - mWorkerHandler.obtainMessage(MSG_NOTIFICATION_REMOVED, packageUserKeyAndNotificationKey) - .sendToTarget(); - } + Pair<PackageUserKey, String> packageUserKeyAndNotificationKey + = new Pair<>(PackageUserKey.fromNotification(sbn), sbn.getKey()); + mWorkerHandler.obtainMessage(MSG_NOTIFICATION_REMOVED, packageUserKeyAndNotificationKey) + .sendToTarget(); } /** This makes a potentially expensive binder call and should be run on a background thread. */ @@ -206,7 +215,8 @@ public class NotificationListener extends NotificationListenerService { } public interface NotificationsChangedListener { - void onNotificationPosted(PackageUserKey postedPackageUserKey, String notificationKey); + void onNotificationPosted(PackageUserKey postedPackageUserKey, String notificationKey, + boolean shouldBeFilteredOut); void onNotificationRemoved(PackageUserKey removedPackageUserKey, String notificationKey); void onNotificationFullRefresh(List<StatusBarNotification> activeNotifications); } diff --git a/src/com/android/launcher3/notification/NotificationMainView.java b/src/com/android/launcher3/notification/NotificationMainView.java index a05fef352..b3425259b 100644 --- a/src/com/android/launcher3/notification/NotificationMainView.java +++ b/src/com/android/launcher3/notification/NotificationMainView.java @@ -32,7 +32,6 @@ import android.widget.TextView; import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAnimUtils; -import com.android.launcher3.LauncherViewPropertyAnimator; import com.android.launcher3.R; import com.android.launcher3.graphics.IconPalette; import com.android.launcher3.userevent.nano.LauncherLogProto; @@ -102,8 +101,8 @@ public class NotificationMainView extends LinearLayout implements SwipeHelper.Ca setTag(new ItemInfo()); if (animate) { AnimatorSet animation = LauncherAnimUtils.createAnimatorSet(); - Animator textFade = new LauncherViewPropertyAnimator(mTextView).alpha(1); - Animator titleFade = new LauncherViewPropertyAnimator(mTitleView).alpha(1); + Animator textFade = ObjectAnimator.ofFloat(mTextView, View.ALPHA, 1); + Animator titleFade = ObjectAnimator.ofFloat(mTitleView, View.ALPHA, 1); ValueAnimator colorChange = ObjectAnimator.ofObject(mColorBackground, "color", mArgbEvaluator, mIconPalette.secondaryColor, mIconPalette.backgroundColor); animation.playTogether(textFade, titleFade, colorChange); diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index 7fda8b531..d34727c8d 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -19,6 +19,7 @@ package com.android.launcher3.popup; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.annotation.SuppressLint; @@ -53,12 +54,12 @@ import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherSettings; -import com.android.launcher3.LauncherViewPropertyAnimator; import com.android.launcher3.LogAccelerateInterpolator; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.accessibility.ShortcutMenuAccessibilityDelegate; +import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.badge.BadgeInfo; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragLayer; @@ -298,7 +299,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView anim.setInterpolator(interpolator); shortcutAnims.play(anim); - Animator fadeAnim = new LauncherViewPropertyAnimator(popupItemView).alpha(1); + Animator fadeAnim = ObjectAnimator.ofFloat(popupItemView, View.ALPHA, 1); fadeAnim.setInterpolator(fadeInterpolator); // We want the shortcut to be fully opaque before the arrow starts animating. fadeAnim.setDuration(arrowScaleDelay); @@ -318,9 +319,8 @@ public class PopupContainerWithArrow extends AbstractFloatingView // Animate the arrow mArrow.setScaleX(0); mArrow.setScaleY(0); - Animator arrowScale = new LauncherViewPropertyAnimator(mArrow).scaleX(1).scaleY(1); + Animator arrowScale = createArrowScaleAnim(1).setDuration(arrowScaleDuration); arrowScale.setStartDelay(arrowScaleDelay); - arrowScale.setDuration(arrowScaleDuration); shortcutAnims.play(arrowScale); mOpenCloseAnimator = shortcutAnims; @@ -603,7 +603,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView removeNotification.play(removeMargin); } removeNotification.play(reduceHeight); - Animator fade = new LauncherViewPropertyAnimator(notificationView).alpha(0) + Animator fade = ObjectAnimator.ofFloat(notificationView, ALPHA, 0) .setDuration(duration); fade.addListener(new AnimatorListenerAdapter() { @Override @@ -620,11 +620,9 @@ public class PopupContainerWithArrow extends AbstractFloatingView removeNotification.play(fade); final long arrowScaleDuration = getResources().getInteger( R.integer.config_deepShortcutArrowOpenDuration); - Animator hideArrow = new LauncherViewPropertyAnimator(mArrow) - .scaleX(0).scaleY(0).setDuration(arrowScaleDuration); + Animator hideArrow = createArrowScaleAnim(0).setDuration(arrowScaleDuration); hideArrow.setStartDelay(0); - Animator showArrow = new LauncherViewPropertyAnimator(mArrow) - .scaleX(1).scaleY(1).setDuration(arrowScaleDuration); + Animator showArrow = createArrowScaleAnim(1).setDuration(arrowScaleDuration); showArrow.setStartDelay((long) (duration - arrowScaleDuration * 1.5)); removeNotification.playSequentially(hideArrow, showArrow); removeNotification.start(); @@ -633,6 +631,10 @@ public class PopupContainerWithArrow extends AbstractFloatingView notificationView.trimNotifications(badgeInfo.getNotificationKeys()); } + private ObjectAnimator createArrowScaleAnim(float scale) { + return LauncherAnimUtils.ofPropertyValuesHolder( + mArrow, new PropertyListBuilder().scale(scale).build()); + } /** * Animates the translationY of this container if it is open above the icon. * If it is below the icon, the container already shifts up when the height @@ -640,8 +642,8 @@ public class PopupContainerWithArrow extends AbstractFloatingView */ public @Nullable Animator animateTranslationYBy(int translationY, int duration) { if (mIsAboveIcon) { - return new LauncherViewPropertyAnimator(this) - .translationY(getTranslationY() + translationY).setDuration(duration); + return ObjectAnimator.ofFloat(this, TRANSLATION_Y, getTranslationY() + translationY) + .setDuration(duration); } return null; } @@ -744,7 +746,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView : numOpenShortcuts - i - 1; anim.setStartDelay(stagger * animationIndex); - Animator fadeAnim = new LauncherViewPropertyAnimator(view).alpha(0); + Animator fadeAnim = ObjectAnimator.ofFloat(view, View.ALPHA, 0); // Don't start fading until the arrow is gone. fadeAnim.setStartDelay(stagger * animationIndex + arrowScaleDuration); fadeAnim.setDuration(duration - arrowScaleDuration); @@ -761,12 +763,13 @@ public class PopupContainerWithArrow extends AbstractFloatingView view.setPivotY(iconCenter.y); float scale = ((float) mLauncher.getDeviceProfile().iconSizePx) / view.getHeight(); - LauncherViewPropertyAnimator anim2 = new LauncherViewPropertyAnimator(view) - .scaleX(scale) - .scaleY(scale) - .translationX(mIconShift.x) - .translationY(mIconShift.y); - anim2.setDuration(DragView.VIEW_ZOOM_DURATION); + Animator anim2 = LauncherAnimUtils.ofPropertyValuesHolder(view, + new PropertyListBuilder() + .scale(scale) + .translationX(mIconShift.x) + .translationY(mIconShift.y) + .build()) + .setDuration(DragView.VIEW_ZOOM_DURATION); shortcutAnims.play(anim2); } anim.addListener(new AnimatorListenerAdapter() { @@ -777,8 +780,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView }); shortcutAnims.play(anim); } - Animator arrowAnim = new LauncherViewPropertyAnimator(mArrow) - .scaleX(0).scaleY(0).setDuration(arrowScaleDuration); + Animator arrowAnim = createArrowScaleAnim(0).setDuration(arrowScaleDuration); arrowAnim.setStartDelay(0); shortcutAnims.play(arrowAnim); diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java index c754fda99..e314b646b 100644 --- a/src/com/android/launcher3/popup/PopupDataProvider.java +++ b/src/com/android/launcher3/popup/PopupDataProvider.java @@ -58,19 +58,26 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan } @Override - public void onNotificationPosted(PackageUserKey postedPackageUserKey, String notificationKey) { + public void onNotificationPosted(PackageUserKey postedPackageUserKey, String notificationKey, + boolean shouldBeFilteredOut) { BadgeInfo badgeInfo = mPackageUserToBadgeInfos.get(postedPackageUserKey); - boolean notificationWasAdded; // As opposed to updated. + boolean notificationWasAddedOrRemoved; // As opposed to updated. if (badgeInfo == null) { - BadgeInfo newBadgeInfo = new BadgeInfo(postedPackageUserKey); - newBadgeInfo.addNotificationKeyIfNotExists(notificationKey); - mPackageUserToBadgeInfos.put(postedPackageUserKey, newBadgeInfo); - notificationWasAdded = true; + if (!shouldBeFilteredOut) { + BadgeInfo newBadgeInfo = new BadgeInfo(postedPackageUserKey); + newBadgeInfo.addNotificationKeyIfNotExists(notificationKey); + mPackageUserToBadgeInfos.put(postedPackageUserKey, newBadgeInfo); + notificationWasAddedOrRemoved = true; + } else { + notificationWasAddedOrRemoved = false; + } } else { - notificationWasAdded = badgeInfo.addNotificationKeyIfNotExists(notificationKey); + notificationWasAddedOrRemoved = shouldBeFilteredOut + ? badgeInfo.removeNotificationKey(notificationKey) + : badgeInfo.addNotificationKeyIfNotExists(notificationKey); } updateLauncherIconBadges(Utilities.singletonHashSet(postedPackageUserKey), - notificationWasAdded); + notificationWasAddedOrRemoved); } @Override diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java index af61554d0..577d19f8c 100644 --- a/src/com/android/launcher3/util/ManagedProfileHeuristic.java +++ b/src/com/android/launcher3/util/ManagedProfileHeuristic.java @@ -203,7 +203,7 @@ public class ManagedProfileHeuristic { long workFolderId, int startingRank, ArrayList<ShortcutInfo> workFolderApps) { for (ItemInfo info : workFolderApps) { info.rank = startingRank++; - LauncherModel.addItemToDatabase(mContext, info, workFolderId, 0, 0, 0); + mModel.getWriter(false).addItemToDatabase(info, workFolderId, 0, 0, 0); } } diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java index c723f9e8b..6f4c2864b 100644 --- a/src/com/android/launcher3/widget/PendingItemDragHelper.java +++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java @@ -29,6 +29,7 @@ import com.android.launcher3.DragSource; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.PendingAddItemInfo; +import com.android.launcher3.R; import com.android.launcher3.Workspace; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.graphics.DragPreviewProvider; @@ -112,6 +113,11 @@ public class PendingItemDragHelper extends DragPreviewProvider { DeviceProfile dp = launcher.getDeviceProfile(); int iconSize = dp.iconSizePx; + int padding = launcher.getResources() + .getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding); + previewBounds.left += padding; + previewBounds.top += padding; + dragRegion = new Rect(); dragRegion.left = (size[0] - iconSize) / 2; dragRegion.right = dragRegion.left + iconSize; diff --git a/src/com/android/launcher3/widget/WidgetImageView.java b/src/com/android/launcher3/widget/WidgetImageView.java index 1211c08a5..df2bcffc1 100644 --- a/src/com/android/launcher3/widget/WidgetImageView.java +++ b/src/com/android/launcher3/widget/WidgetImageView.java @@ -89,16 +89,25 @@ public class WidgetImageView extends View { } private void updateDstRectF() { - if (mBitmap.getWidth() > getWidth()) { - float scale = ((float) getWidth()) / mBitmap.getWidth(); - mDstRectF.set(0, 0, getWidth(), scale * mBitmap.getHeight()); + float myWidth = getWidth(); + float myHeight = getHeight(); + float bitmapWidth = mBitmap.getWidth(); + + final float scale = bitmapWidth > myWidth ? myWidth / bitmapWidth : 1; + float scaledWidth = bitmapWidth * scale; + float scaledHeight = mBitmap.getHeight() * scale; + + mDstRectF.left = (myWidth - scaledWidth) / 2; + mDstRectF.right = (myWidth + scaledWidth) / 2; + + if (scaledHeight > myHeight) { + mDstRectF.top = 0; + mDstRectF.bottom = scaledHeight; } else { - mDstRectF.set( - (getWidth() - mBitmap.getWidth()) * 0.5f, - 0, - (getWidth() + mBitmap.getWidth()) * 0.5f, - mBitmap.getHeight()); + mDstRectF.top = (myHeight - scaledHeight) / 2; + mDstRectF.bottom = (myHeight + scaledHeight) / 2; } + if (mBadge != null) { Rect bounds = mBadge.getBounds(); int left = Utilities.boundToRange( diff --git a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java index 207138940..d0ba9074c 100644 --- a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java +++ b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java @@ -53,14 +53,6 @@ public class AddWorkspaceItemsTaskTest extends BaseModelUpdateTaskTestCase { return new AddWorkspaceItemsTask(Provider.of(Arrays.asList(items))) { @Override - protected void addItemToDatabase(Context context, ItemInfo item, - long screenId, int[] pos) { - item.screenId = screenId; - item.cellX = pos[0]; - item.cellY = pos[1]; - } - - @Override protected void updateScreens(Context context, ArrayList<Long> workspaceScreens) { } }; } diff --git a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java b/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java index 9b7fc6ebf..b9944db98 100644 --- a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java +++ b/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java @@ -37,6 +37,7 @@ import java.lang.reflect.Field; import java.util.HashMap; import java.util.List; +import static org.mockito.Matchers.anyBoolean; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -54,6 +55,8 @@ public class BaseModelUpdateTaskTestCase extends ProviderTestCase2<TestLauncherP public InvariantDeviceProfile idp; public LauncherAppState appState; + public LauncherModel model; + public ModelWriter modelWriter; public MyIconCache iconCache; public BgDataModel bgDataModel; @@ -70,6 +73,11 @@ public class BaseModelUpdateTaskTestCase extends ProviderTestCase2<TestLauncherP callbacks = mock(Callbacks.class); appState = mock(LauncherAppState.class); + model = mock(LauncherModel.class); + modelWriter = mock(ModelWriter.class); + when(appState.getModel()).thenReturn(model); + when(model.getWriter(anyBoolean())).thenReturn(modelWriter); + myUser = Process.myUserHandle(); bgDataModel = new BgDataModel(); |