From 57251be2d77ad94f05c49d42d682ec008a6e211d Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Mon, 10 Feb 2014 15:39:10 -0800 Subject: [PATCH 1/4] Import translations. DO NOT MERGE Change-Id: Icfe6248a812a2aa103c830a9fabe22de9ff228bb Auto-generated-cl: translation import --- res/values-lo-rLA/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/values-lo-rLA/strings.xml b/res/values-lo-rLA/strings.xml index 79a0a4a48c..5ced01ab02 100644 --- a/res/values-lo-rLA/strings.xml +++ b/res/values-lo-rLA/strings.xml @@ -52,9 +52,9 @@ "ແອັບຯ" "ໜ້າຫຼັກ" "ລຶບ" - "ຖອນການຕິດຕັ້ງ" + "ຖອນ​ການ​ຕິດ​ຕັ້ງ" "ລຶບ" - "ຖອນການຕິດຕັ້ງ" + "ຖອນ​ການ​ຕິດ​ຕັ້ງ" "ຂໍ້ມູນແອັບຯ" "ຊອກຫາ" "ຊອກຫາດ້ວຍສຽງ" From 30e43d723db46364c9380a80fdbefef5adc000e7 Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Mon, 10 Feb 2014 15:40:51 -0800 Subject: [PATCH 2/4] Import translations. DO NOT MERGE Change-Id: Icb76bf81b4253215543f7e384efac9eb23e0c432 Auto-generated-cl: translation import --- res/values-lo-rLA/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/values-lo-rLA/strings.xml b/res/values-lo-rLA/strings.xml index 79a0a4a48c..5ced01ab02 100644 --- a/res/values-lo-rLA/strings.xml +++ b/res/values-lo-rLA/strings.xml @@ -52,9 +52,9 @@ "ແອັບຯ" "ໜ້າຫຼັກ" "ລຶບ" - "ຖອນການຕິດຕັ້ງ" + "ຖອນ​ການ​ຕິດ​ຕັ້ງ" "ລຶບ" - "ຖອນການຕິດຕັ້ງ" + "ຖອນ​ການ​ຕິດ​ຕັ້ງ" "ຂໍ້ມູນແອັບຯ" "ຊອກຫາ" "ຊອກຫາດ້ວຍສຽງ" From 085c853a5702c45865e9b017d21fa15cf2b151b9 Mon Sep 17 00:00:00 2001 From: Yura Date: Tue, 11 Feb 2014 15:15:29 +0000 Subject: [PATCH 3/4] Do updateWorkspaceScreenOrder inside a single transaction. The workspacescreens table is updated in LauncherModel.updateWorkspaceScreenOrder and that the operation to remove all screens, then reinsert the new list of screens in not inside a single transaction, so if the app is updating or crashes between ContentResolver.delete and ContentResolver.bulkInsert then the data will be lost. This CL makes it all happen inside 1 transaction. Bug: 12523285 Change-Id: I409dbc9f48fa9c8bd4bf3b1453204a4daac1689a --- src/com/android/launcher3/LauncherModel.java | 13 +++++++++---- src/com/android/launcher3/LauncherProvider.java | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index ff8a356477..f4fa10ffac 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -1063,18 +1063,23 @@ public class LauncherModel extends BroadcastReceiver { Runnable r = new Runnable() { @Override public void run() { + ArrayList ops = new ArrayList(); // Clear the table - cr.delete(uri, null, null); + ops.add(ContentProviderOperation.newDelete(uri).build()); int count = screensCopy.size(); - ContentValues[] values = new ContentValues[count]; for (int i = 0; i < count; i++) { ContentValues v = new ContentValues(); long screenId = screensCopy.get(i); v.put(LauncherSettings.WorkspaceScreens._ID, screenId); v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i); - values[i] = v; + ops.add(ContentProviderOperation.newInsert(uri).withValues(v).build()); + } + + try { + cr.applyBatch(LauncherProvider.AUTHORITY, ops); + } catch (Exception ex) { + throw new RuntimeException(ex); } - cr.bulkInsert(uri, values); synchronized (sBgLock) { sBgWorkspaceScreens.clear(); diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index cec9167f39..a69f4235d8 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -22,11 +22,14 @@ import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; import android.content.ContentProvider; +import android.content.ContentProviderOperation; +import android.content.ContentProviderResult; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.Intent; +import android.content.OperationApplicationException; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; @@ -193,6 +196,20 @@ public class LauncherProvider extends ContentProvider { return values.length; } + @Override + public ContentProviderResult[] applyBatch(ArrayList operations) + throws OperationApplicationException { + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + db.beginTransaction(); + try { + ContentProviderResult[] result = super.applyBatch(operations); + db.setTransactionSuccessful(); + return result; + } finally { + db.endTransaction(); + } + } + @Override public int delete(Uri uri, String selection, String[] selectionArgs) { SqlArguments args = new SqlArguments(uri, selection, selectionArgs); From 55bd9725d5c0373b89f7b9bbd9547550ea3bbc63 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Thu, 16 Jan 2014 15:30:42 -0800 Subject: [PATCH 4/4] Implement spring-loading of folders when dragging over. Bug: 8912132 Change-Id: Id81889a133e56461df2e20599c4b40020818ba18 --- .../launcher3/AppsCustomizePagedView.java | 2 +- src/com/android/launcher3/DragLayer.java | 35 ++--- src/com/android/launcher3/Folder.java | 141 +++++++++++++----- src/com/android/launcher3/FolderIcon.java | 31 ++++ src/com/android/launcher3/Launcher.java | 1 + 5 files changed, 148 insertions(+), 62 deletions(-) diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java index 49b12b1b18..251ae2108e 100644 --- a/src/com/android/launcher3/AppsCustomizePagedView.java +++ b/src/com/android/launcher3/AppsCustomizePagedView.java @@ -817,7 +817,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen */ private void endDragging(View target, boolean isFlingToDelete, boolean success) { if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() && - !(target instanceof DeleteDropTarget))) { + !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) { // Exit spring loaded mode if we have not successfully dropped or have not handled the // drop in Workspace mLauncher.getWorkspace().removeExtraEmptyScreen(true, new Runnable() { diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java index ab0469d53f..862ceca28e 100644 --- a/src/com/android/launcher3/DragLayer.java +++ b/src/com/android/launcher3/DragLayer.java @@ -65,8 +65,6 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang private boolean mHoverPointClosesFolder = false; private Rect mHitRect = new Rect(); - private int mWorkspaceIndex = -1; - private int mQsbIndex = -1; public static final int ANIMATION_END_DISAPPEAR = 0; public static final int ANIMATION_END_FADE_OUT = 1; public static final int ANIMATION_END_REMAIN_VISIBLE = 2; @@ -75,6 +73,8 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang private final Rect mInsets = new Rect(); + private int mDragViewIndex; + /** * Used to create a new DragLayer from XML. * @@ -771,31 +771,26 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang } private void updateChildIndices() { - if (mLauncher != null) { - mWorkspaceIndex = indexOfChild(mLauncher.getWorkspace()); - mQsbIndex = indexOfChild(mLauncher.getSearchBar()); + mDragViewIndex = -1; + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + if (getChildAt(i) instanceof DragView) { + mDragViewIndex = i; + } } } @Override protected int getChildDrawingOrder(int childCount, int i) { - // TODO: We have turned off this custom drawing order because it now effects touch - // dispatch order. We need to sort that issue out and then decide how to go about this. - if (true || LauncherAppState.isScreenLandscape(getContext()) || - mWorkspaceIndex == -1 || mQsbIndex == -1 || - mLauncher.getWorkspace().isDrawingBackgroundGradient()) { + if (mDragViewIndex == -1) { + return i; + } else if (i == mDragViewIndex) { + return getChildCount()-1; + } else if (i < mDragViewIndex) { return i; - } - - // This ensures that the workspace is drawn above the hotseat and qsb, - // except when the workspace is drawing a background gradient, in which - // case we want the workspace to stay behind these elements. - if (i == mQsbIndex) { - return mWorkspaceIndex; - } else if (i == mWorkspaceIndex) { - return mQsbIndex; } else { - return i; + // i > mDragViewIndex + return i-1; } } diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java index a9134e105d..b4c399266c 100644 --- a/src/com/android/launcher3/Folder.java +++ b/src/com/android/launcher3/Folder.java @@ -24,7 +24,6 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.PointF; import android.graphics.Rect; -import android.graphics.drawable.Drawable; import android.os.SystemClock; import android.support.v4.widget.AutoScrollHelper; import android.text.InputType; @@ -70,6 +69,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList static final int STATE_ANIMATING = 1; static final int STATE_OPEN = 2; + private static final int CLOSE_FOLDER_DELAY_MS = 150; + private int mExpandDuration; protected CellLayout mContent; private ScrollView mScrollView; @@ -85,10 +86,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList private int mMaxCountY; private int mMaxNumItems; private ArrayList mItemsInReadingOrder = new ArrayList(); - private Drawable mIconDrawable; boolean mItemsInvalidated = false; private ShortcutInfo mCurrentDragInfo; private View mCurrentDragView; + private boolean mIsExternalDrag; boolean mSuppressOnAdd = false; private int[] mTargetCell = new int[2]; private int[] mPreviousTargetCell = new int[2]; @@ -242,7 +243,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mLauncher.getWorkspace().onDragStartedWithItem(v); mLauncher.getWorkspace().beginDragShared(v, this); - mIconDrawable = ((TextView) v).getCompoundDrawables()[1]; mCurrentDragInfo = item; mEmptyCell[0] = item.cellX; @@ -303,10 +303,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList return mFolderName; } - public Drawable getDragDrawable() { - return mIconDrawable; - } - /** * We need to handle touch events to prevent them from falling through to the workspace below. */ @@ -381,7 +377,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList int count = 0; for (int i = 0; i < children.size(); i++) { ShortcutInfo child = (ShortcutInfo) children.get(i); - if (!createAndAddShortcut(child)) { + if (createAndAddShortcut(child) == null) { overflow.add(child); } else { count++; @@ -466,11 +462,15 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList public void onAnimationEnd(Animator animation) { mState = STATE_OPEN; setLayerType(LAYER_TYPE_NONE, null); - Cling cling = mLauncher.getLauncherClings().showFoldersCling(); - if (cling != null) { - cling.bringScrimToFront(); - bringToFront(); - cling.bringToFront(); + + // Only show cling if we are not in the middle of a drag - this would be quite jarring. + if (!mDragController.isDragging()) { + Cling cling = mLauncher.getLauncherClings().showFoldersCling(); + if (cling != null) { + cling.bringScrimToFront(); + bringToFront(); + cling.bringToFront(); + } } setFocusOnFirstChild(); } @@ -478,6 +478,23 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList oa.setDuration(mExpandDuration); setLayerType(LAYER_TYPE_HARDWARE, null); oa.start(); + + // Make sure the folder picks up the last drag move even if the finger doesn't move. + if (mDragController.isDragging()) { + mDragController.forceTouchMove(); + } + } + + public void beginExternalDrag(ShortcutInfo item) { + setupContentForNumItems(getItemCount() + 1); + findAndSetEmptyCells(item); + + mCurrentDragInfo = item; + mEmptyCell[0] = item.cellX; + mEmptyCell[1] = item.cellY; + mIsExternalDrag = true; + + mDragInProgress = true; } private void sendCustomAccessibilityEvent(int type, String text) { @@ -544,7 +561,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } } - protected boolean createAndAddShortcut(ShortcutInfo item) { + protected View createAndAddShortcut(ShortcutInfo item) { final BubbleTextView textView = (BubbleTextView) mInflater.inflate(R.layout.application, this, false); textView.setCompoundDrawables(null, @@ -565,7 +582,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList // This shouldn't happen, log it. Log.e(TAG, "Folder order not properly persisted during bind"); if (!findAndSetEmptyCells(item)) { - return false; + return null; } } @@ -574,7 +591,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList boolean insert = false; textView.setOnKeyListener(new FolderKeyEventListener()); mContent.addViewToCellLayout(textView, insert ? 0 : -1, (int)item.id, lp, true); - return true; + return textView; } public void onDragEnter(DragObject d) { @@ -723,6 +740,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mCurrentDragView = null; mSuppressOnAdd = false; mRearrangeOnClose = true; + mIsExternalDrag = false; } public void onDragExit(DragObject d) { @@ -756,7 +774,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList success && (!beingCalledAfterUninstall || mUninstallSuccessful); if (successfulDrop) { - if (mDeleteFolderOnDropCompleted && !mItemAddedBackToSelfViaIcon) { + if (mDeleteFolderOnDropCompleted && !mItemAddedBackToSelfViaIcon && target != this) { replaceFolderWithFinalItem(); } } else { @@ -1152,34 +1170,75 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } public void onDrop(DragObject d) { - ShortcutInfo item; - if (d.dragInfo instanceof AppInfo) { - // Came from all apps -- make a copy - item = ((AppInfo) d.dragInfo).makeShortcut(); - item.spanX = 1; - item.spanY = 1; - } else { - item = (ShortcutInfo) d.dragInfo; + Runnable cleanUpRunnable = null; + + // If we are coming from All Apps space, we need to remove the extra empty screen (which is + // normally done in Workspace#onDropExternal, as well zoom back in and close the folder. + if (d.dragSource != mLauncher.getWorkspace() && !(d.dragSource instanceof Folder)) { + cleanUpRunnable = new Runnable() { + @Override + public void run() { + mLauncher.getWorkspace().removeExtraEmptyScreen(false, new Runnable() { + @Override + public void run() { + mLauncher.closeFolder(); + mLauncher.exitSpringLoadedDragModeDelayed(true, + Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT_FOLDER_CLOSE, + null); + } + }, CLOSE_FOLDER_DELAY_MS, false); + } + }; } - // Dragged from self onto self, currently this is the only path possible, however - // we keep this as a distinct code path. - if (item == mCurrentDragInfo) { - ShortcutInfo si = (ShortcutInfo) mCurrentDragView.getTag(); - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mCurrentDragView.getLayoutParams(); + + View currentDragView; + ShortcutInfo si = mCurrentDragInfo; + if (mIsExternalDrag) { + si.cellX = mEmptyCell[0]; + si.cellY = mEmptyCell[1]; + currentDragView = createAndAddShortcut(si); + } else { + currentDragView = mCurrentDragView; + CellLayout.LayoutParams lp = (CellLayout.LayoutParams) currentDragView.getLayoutParams(); si.cellX = lp.cellX = mEmptyCell[0]; si.cellX = lp.cellY = mEmptyCell[1]; - mContent.addViewToCellLayout(mCurrentDragView, -1, (int)item.id, lp, true); - if (d.dragView.hasDrawn()) { - mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, mCurrentDragView); - } else { - d.deferDragViewCleanupPostAnimation = false; - mCurrentDragView.setVisibility(VISIBLE); - } - mItemsInvalidated = true; - setupContentDimensions(getItemCount()); - mSuppressOnAdd = true; + mContent.addViewToCellLayout(currentDragView, -1, (int) si.id, lp, true); } - mInfo.add(item); + + if (d.dragView.hasDrawn()) { + + // Temporarily reset the scale such that the animation target gets calculated correctly. + float scaleX = getScaleX(); + float scaleY = getScaleY(); + setScaleX(1.0f); + setScaleY(1.0f); + mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, currentDragView, + cleanUpRunnable, null); + setScaleX(scaleX); + setScaleY(scaleY); + } else { + d.deferDragViewCleanupPostAnimation = false; + currentDragView.setVisibility(VISIBLE); + } + mItemsInvalidated = true; + setupContentDimensions(getItemCount()); + + // Actually move the item in the database if it was an external drag. + if (mIsExternalDrag) { + LauncherModel.addOrMoveItemInDatabase( + mLauncher, 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) { + updateItemLocationsInDatabaseBatch(); + } + mIsExternalDrag = false; + } + + // Temporarily suppress the listener, as we did all the work already here. + mSuppressOnAdd = true; + mInfo.add(si); + mSuppressOnAdd = false; } // This is used so the item doesn't immediately appear in the folder when added. In one case diff --git a/src/com/android/launcher3/FolderIcon.java b/src/com/android/launcher3/FolderIcon.java index 644db47acf..78026f162f 100644 --- a/src/com/android/launcher3/FolderIcon.java +++ b/src/com/android/launcher3/FolderIcon.java @@ -75,10 +75,16 @@ public class FolderIcon extends FrameLayout implements FolderListener { // Flag as to whether or not to draw an outer ring. Currently none is designed. public static final boolean HAS_OUTER_RING = true; + // Flag whether the folder should open itself when an item is dragged over is enabled. + public static final boolean SPRING_LOADING_ENABLED = true; + // The degree to which the item in the back of the stack is scaled [0...1] // (0 means it's not scaled at all, 1 means it's scaled to nothing) private static final float PERSPECTIVE_SCALE_FACTOR = 0.35f; + // Delay when drag enters until the folder opens, in miliseconds. + private static final int ON_OPEN_DELAY = 800; + public static Drawable sSharedFolderLeaveBehind = null; private ImageView mPreviewBackground; @@ -103,6 +109,9 @@ public class FolderIcon extends FrameLayout implements FolderListener { private PreviewItemDrawingParams mAnimParams = new PreviewItemDrawingParams(0, 0, 0, 0); private ArrayList mHiddenItems = new ArrayList(); + private Alarm mOpenAlarm = new Alarm(); + private ItemInfo mDragInfo; + public FolderIcon(Context context, AttributeSet attrs) { super(context, attrs); init(); @@ -331,11 +340,32 @@ public class FolderIcon extends FrameLayout implements FolderListener { mFolderRingAnimator.setCellLayout(layout); mFolderRingAnimator.animateToAcceptState(); layout.showFolderAccept(mFolderRingAnimator); + mOpenAlarm.setOnAlarmListener(mOnOpenListener); + if (SPRING_LOADING_ENABLED) { + mOpenAlarm.setAlarm(ON_OPEN_DELAY); + } + mDragInfo = (ItemInfo) dragInfo; } public void onDragOver(Object dragInfo) { } + OnAlarmListener mOnOpenListener = new OnAlarmListener() { + public void onAlarm(Alarm alarm) { + ShortcutInfo item; + if (mDragInfo instanceof AppInfo) { + // Came from all apps -- make a copy. + item = ((AppInfo) mDragInfo).makeShortcut(); + item.spanX = 1; + item.spanY = 1; + } else { + item = (ShortcutInfo) mDragInfo; + } + mFolder.beginExternalDrag(item); + mLauncher.openFolder(FolderIcon.this); + } + }; + public void performCreateAnimation(final ShortcutInfo destInfo, final View destView, final ShortcutInfo srcInfo, final DragView srcView, Rect dstRect, float scaleRelativeToDragLayer, Runnable postAnimationRunnable) { @@ -371,6 +401,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { public void onDragExit() { mFolderRingAnimator.animateToNaturalState(); + mOpenAlarm.cancelAlarm(); } private void onDrop(final ShortcutInfo item, DragView animateView, Rect finalRect, diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index c57d32e314..c87f9e2f0b 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -210,6 +210,7 @@ public class Launcher extends Activity static final int APPWIDGET_HOST_ID = 1024; public static final int EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT = 300; + public static final int EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT_FOLDER_CLOSE = 400; private static final int ON_ACTIVITY_RESULT_ANIMATION_DELAY = 500; private static final Object sLock = new Object();