diff options
Diffstat (limited to 'src/com/android/launcher3/Folder.java')
-rw-r--r-- | src/com/android/launcher3/Folder.java | 342 |
1 files changed, 283 insertions, 59 deletions
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java index a00f3c1da..71183c342 100644 --- a/src/com/android/launcher3/Folder.java +++ b/src/com/android/launcher3/Folder.java @@ -20,11 +20,13 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; +import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.res.Resources; import android.graphics.PointF; import android.graphics.Rect; -import android.graphics.drawable.Drawable; +import android.os.Bundle; import android.os.SystemClock; import android.support.v4.widget.AutoScrollHelper; import android.text.InputType; @@ -43,7 +45,9 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; +import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.RelativeLayout; import android.widget.ScrollView; import android.widget.TextView; @@ -62,6 +66,12 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList View.OnFocusChangeListener { private static final String TAG = "Launcher.Folder"; + private static final String PROTECTED_ACTION = "cyanogenmod.intent.action.PACKAGE_PROTECTED"; + private static final String PROTECTED_STATE = + "cyanogenmod.intent.action.PACKAGE_PROTECTED_STATE"; + private static final String PROTECTED_COMPONENT = + "cyanogenmod.intent.action.PACKAGE_PROTECTED_COMPONENT"; + protected DragController mDragController; protected Launcher mLauncher; protected FolderInfo mInfo; @@ -71,6 +81,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; @@ -79,17 +91,17 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList private int mState = STATE_NONE; private static final int REORDER_ANIMATION_DURATION = 230; private static final int REORDER_DELAY = 250; - private static final int ON_EXIT_CLOSE_DELAY = 800; + private static final int ON_EXIT_CLOSE_DELAY = 400; private boolean mRearrangeOnClose = false; private FolderIcon mFolderIcon; private int mMaxCountX; private int mMaxCountY; private int mMaxNumItems; private ArrayList<View> mItemsInReadingOrder = new ArrayList<View>(); - 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]; @@ -103,6 +115,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList private boolean mSuppressFolderDeletion = false; private boolean mItemAddedBackToSelfViaIcon = false; FolderEditText mFolderName; + ImageView mFolderLock; + RelativeLayout mFolderTitleSection; private float mFolderIconPivotX; private float mFolderIconPivotY; @@ -116,6 +130,11 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList private int DRAG_MODE_REORDER = 1; private int mDragMode = DRAG_MODE_NONE; + // We avoid measuring the scroll view with a 0 width or height, as this + // results in CellLayout being measured as UNSPECIFIED, which it does + // not support. + private static final int MIN_CONTENT_DIMEN = 5; + private boolean mDestroyed; private AutoScrollHelper mAutoScrollHelper; @@ -124,6 +143,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList private boolean mDeferDropAfterUninstall; private boolean mUninstallSuccessful; + private boolean mHiddenFolder = false; + /** * Used to inflate the Workspace from XML. * @@ -141,8 +162,13 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList Resources res = getResources(); mMaxCountX = (int) grid.numColumns; - mMaxCountY = (int) grid.numRows; - mMaxNumItems = mMaxCountX * mMaxCountY; + // Allow scrolling folders when DISABLE_ALL_APPS is true. + if (LauncherAppState.isDisableAllApps()) { + mMaxCountY = mMaxNumItems = Integer.MAX_VALUE; + } else { + mMaxCountY = (int) grid.numRows; + mMaxNumItems = mMaxCountX * mMaxCountY; + } mInputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); @@ -167,6 +193,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList super.onFinishInflate(); mScrollView = (ScrollView) findViewById(R.id.scroll_view); mContent = (CellLayout) findViewById(R.id.folder_content); + int measureSpec = MeasureSpec.UNSPECIFIED; LauncherAppState app = LauncherAppState.getInstance(); DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); @@ -181,7 +208,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList // We find out how tall the text view wants to be (it is set to wrap_content), so that // we can allocate the appropriate amount of space for it. - int measureSpec = MeasureSpec.UNSPECIFIED; mFolderName.measure(measureSpec, measureSpec); mFolderNameHeight = mFolderName.getMeasuredHeight(); @@ -199,6 +225,12 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mFolderName.setVisibility(View.GONE); mFolderNameHeight = getPaddingBottom(); } + + mFolderLock = (ImageView) findViewById(R.id.folder_lock); + mFolderTitleSection = (RelativeLayout) findViewById(R.id.folder_title_section); + mFolderLock.measure(measureSpec, measureSpec); + mFolderLock.setOnClickListener(this); + mFolderTitleSection.measure(measureSpec, measureSpec); } private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() { @@ -223,6 +255,60 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList if (tag instanceof ShortcutInfo) { mLauncher.onClick(v); } + + if (v.getId() == R.id.folder_lock) { + startHiddenFolderManager(); + } + } + + public void startHiddenFolderManager() { + Bundle bundle = new Bundle(); + bundle.putBoolean(HiddenFolderFragment.HIDDEN_FOLDER_STATUS, mInfo.hidden); + mLauncher.validateLockForHiddenFolders(bundle, mFolderIcon); + } + + public String[] getComponentTitles() { + int size = mItemsInReadingOrder.size(); + String[] componentsTitles = new String[size]; + for (int i = 0; i < size; i++) { + View v = mItemsInReadingOrder.get(i); + Object tag = v.getTag(); + if (tag instanceof ShortcutInfo) { + componentsTitles[i] = ((ShortcutInfo) tag).title.toString(); + } + } + return componentsTitles; + } + + public String[] getComponents() { + String components = getComponentString(); + return components.split("\\|"); + } + + public void modifyProtectedApps(boolean protect) { + String components = getComponentString(); + + Intent intent = new Intent(); + intent.setAction(PROTECTED_ACTION); + intent.putExtra(PROTECTED_STATE, protect); + intent.putExtra(PROTECTED_COMPONENT, components); + + mLauncher.sendBroadcast(intent); + } + + private String getComponentString() { + int size = mItemsInReadingOrder.size(); + String components = ""; + for (int i = 0; i < size; i++) { + View v = mItemsInReadingOrder.get(i); + Object tag = v.getTag(); + if (tag instanceof ShortcutInfo) { + ComponentName componentName = ((ShortcutInfo) tag).getIntent().getComponent(); + components += componentName.flattenToString() + "|"; + } + } + + return components; } public boolean onLongClick(View v) { @@ -236,11 +322,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList return false; } - mLauncher.dismissFolderCling(null); + mLauncher.getLauncherClings().dismissFolderCling(null); mLauncher.getWorkspace().onDragStartedWithItem(v); mLauncher.getWorkspace().beginDragShared(v, this); - mIconDrawable = ((TextView) v).getCompoundDrawables()[1]; mCurrentDragInfo = item; mEmptyCell[0] = item.cellX; @@ -262,6 +347,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList public void startEditingFolderName() { mFolderName.setHint(""); mIsEditingName = true; + + mInputMethodManager.showSoftInput(mFolderName, 0); } public void dismissEditingName() { @@ -305,10 +392,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. */ @@ -383,7 +466,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++; @@ -405,12 +488,26 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList updateTextViewFocus(); mInfo.addListener(this); + setFolderName(); + updateItemLocationsInDatabase(); + } + + public void setFolderName() { if (!sDefaultFolderName.contentEquals(mInfo.title)) { mFolderName.setText(mInfo.title); } else { mFolderName.setText(""); } updateItemLocationsInDatabase(); + + // In case any children didn't come across during loading, clean up the folder accordingly + mFolderIcon.post(new Runnable() { + public void run() { + if (getItemCount() <= 1) { + replaceFolderWithFinalItem(); + } + } + }); } /** @@ -459,11 +556,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.showFirstRunFoldersCling(); - 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(); } @@ -471,6 +572,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) { @@ -537,7 +655,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, @@ -546,7 +664,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList textView.setTag(item); textView.setTextColor(getResources().getColor(R.color.folder_items_text_color)); textView.setShadowsEnabled(false); - Utilities.applyTypeface(textView); + textView.setGlowColor(getResources().getColor(R.color.folder_items_glow_color)); textView.setOnClickListener(this); textView.setOnLongClickListener(this); @@ -558,7 +676,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; } } @@ -567,7 +685,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) { @@ -716,6 +834,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mCurrentDragView = null; mSuppressOnAdd = false; mRearrangeOnClose = true; + mIsExternalDrag = false; } public void onDragExit(DragObject d) { @@ -749,7 +868,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 { @@ -768,6 +887,12 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } } + // This is kind of hacky, but in general, dropping on the workspace handles removing + // the extra screen, but dropping elsewhere (back to self, or onto delete) doesn't. + if (target != mLauncher.getWorkspace()) { + mLauncher.getWorkspace().removeExtraEmptyScreen(true, null); + } + mDeleteFolderOnDropCompleted = false; mDragInProgress = false; mItemAddedBackToSelfViaIcon = false; @@ -793,10 +918,25 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } @Override + public float getIntrinsicIconScaleFactor() { + return 1f; + } + + @Override public boolean supportsFlingToDelete() { return true; } + @Override + public boolean supportsAppInfoDropTarget() { + return false; + } + + @Override + public boolean supportsDeleteDropTarget() { + return true; + } + public void onFlingToDelete(DragObject d, int x, int y, PointF vec) { // Do nothing } @@ -812,7 +952,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList View v = list.get(i); ItemInfo info = (ItemInfo) v.getTag(); LauncherModel.moveItemInDatabase(mLauncher, info, mInfo.id, 0, - info.cellX, info.cellY); + info.cellX, info.cellY); } } @@ -965,31 +1105,48 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList Rect workspacePadding = grid.getWorkspacePadding(grid.isLandscape ? CellLayout.LANDSCAPE : CellLayout.PORTRAIT); int maxContentAreaHeight = grid.availableHeightPx - - 4 * grid.edgeMarginPx - workspacePadding.top - workspacePadding.bottom - - getPaddingTop() - getPaddingBottom() - mFolderNameHeight; - return Math.min(maxContentAreaHeight, + int height = Math.min(maxContentAreaHeight, mContent.getDesiredHeight()); + return Math.max(height, MIN_CONTENT_DIMEN); + } + + private int getContentAreaWidth() { + return Math.max(mContent.getDesiredWidth(), MIN_CONTENT_DIMEN); } private int getFolderHeight() { - int height = getPaddingTop() + getPaddingBottom() - + getContentAreaHeight() + mFolderNameHeight; + int height = getPaddingTop() + getPaddingBottom() + mFolderNameHeight + + getContentAreaHeight(); return height; } protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth(); + int width = getPaddingLeft() + + getPaddingRight() + + Math.max(mContent.getDesiredWidth(), + mFolderTitleSection.getMeasuredWidth()); int height = getFolderHeight(); - int contentAreaWidthSpec = MeasureSpec.makeMeasureSpec(mContent.getDesiredWidth(), + int contentAreaWidthSpec = MeasureSpec.makeMeasureSpec(getContentAreaWidth(), MeasureSpec.EXACTLY); int contentAreaHeightSpec = MeasureSpec.makeMeasureSpec(getContentAreaHeight(), MeasureSpec.EXACTLY); - mContent.setFixedSize(mContent.getDesiredWidth(), mContent.getDesiredHeight()); + + if (LauncherAppState.isDisableAllApps()) { + // Don't cap the height of the content to allow scrolling. + mContent.setFixedSize(getContentAreaWidth(), mContent.getDesiredHeight()); + } else { + mContent.setFixedSize(getContentAreaWidth(), getContentAreaHeight()); + } + mScrollView.measure(contentAreaWidthSpec, contentAreaHeightSpec); - mFolderName.measure(contentAreaWidthSpec, - MeasureSpec.makeMeasureSpec(mFolderNameHeight, MeasureSpec.EXACTLY)); + mFolderName.measure(contentAreaWidthSpec, MeasureSpec.makeMeasureSpec( + mFolderNameHeight, MeasureSpec.EXACTLY)); + mFolderLock.measure(contentAreaWidthSpec, MeasureSpec.makeMeasureSpec( + mFolderNameHeight, MeasureSpec.EXACTLY)); + mFolderTitleSection.measure(contentAreaWidthSpec, MeasureSpec + .makeMeasureSpec(mFolderNameHeight, MeasureSpec.EXACTLY)); setMeasuredDimension(width, height); } @@ -1051,13 +1208,16 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } private void replaceFolderWithFinalItem() { + if (mInfo.hidden) { + return; + } // Add the last remaining child to the workspace in place of the folder Runnable onCompleteRunnable = new Runnable() { @Override public void run() { CellLayout cellLayout = mLauncher.getCellLayout(mInfo.container, mInfo.screenId); - View child = null; + View child = null; // Move the item from the folder to the workspace, in the position of the folder if (getItemCount() == 1) { ShortcutInfo finalItem = mInfo.contents.get(0); @@ -1069,7 +1229,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList if (getItemCount() <= 1) { // Remove the folder LauncherModel.deleteItemFromDatabase(mLauncher, mInfo); - cellLayout.removeView(mFolderIcon); + if (cellLayout != null) { + // b/12446428 -- sometimes the cell layout has already gone away? + cellLayout.removeView(mFolderIcon); + } if (mFolderIcon instanceof DropTarget) { mDragController.removeDropTarget((DropTarget) mFolderIcon); } @@ -1087,6 +1250,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList View finalChild = getItemAt(0); if (finalChild != null) { mFolderIcon.performDestroyAnimation(finalChild, onCompleteRunnable); + } else { + onCompleteRunnable.run(); } mDestroyed = true; } @@ -1109,34 +1274,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); + mContent.addViewToCellLayout(currentDragView, -1, (int) si.id, lp, true); + } + + 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(); } - mItemsInvalidated = true; - setupContentDimensions(getItemCount()); - mSuppressOnAdd = true; + mIsExternalDrag = false; } - mInfo.add(item); + + // 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 @@ -1218,6 +1424,20 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList return mItemsInReadingOrder; } + public ShortcutInfo getShortcutForComponent(ComponentName componentName) { + for (View v : mItemsInReadingOrder) { + Object tag = v.getTag(); + if (tag instanceof ShortcutInfo) { + ComponentName cName = ((ShortcutInfo) tag).getIntent().getComponent(); + if (cName.equals(componentName)) { + return (ShortcutInfo) tag; + } + } + } + + return null; + } + public void getLocationInDragLayer(int[] loc) { mLauncher.getDragLayer().getLocationInDragLayer(this, loc); } @@ -1232,4 +1452,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList public void getHitRectRelativeToDragLayer(Rect outRect) { getHitRect(outRect); } + + public View getViewFromPosition(int position) { + return mItemsInReadingOrder.get(position); + } } |