diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 63e3c66ad1..d9404a7bc5 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -61,7 +61,7 @@ - + - + android:theme="@style/Theme"> diff --git a/res/drawable-hdpi/portal_container_holo.9.png b/res/drawable-hdpi/portal_container_holo.9.png index af2fa98d74..a2fbcb6df3 100644 Binary files a/res/drawable-hdpi/portal_container_holo.9.png and b/res/drawable-hdpi/portal_container_holo.9.png differ diff --git a/res/drawable-hdpi/portal_ring_inner_holo.png b/res/drawable-hdpi/portal_ring_inner_holo.png index 8a9e85b7f5..e671d1b624 100644 Binary files a/res/drawable-hdpi/portal_ring_inner_holo.png and b/res/drawable-hdpi/portal_ring_inner_holo.png differ diff --git a/res/drawable-hdpi/portal_ring_outer_holo.png b/res/drawable-hdpi/portal_ring_outer_holo.png index 5b46419469..7aad6076e2 100644 Binary files a/res/drawable-hdpi/portal_ring_outer_holo.png and b/res/drawable-hdpi/portal_ring_outer_holo.png differ diff --git a/res/drawable-mdpi/portal_container_holo.9.png b/res/drawable-mdpi/portal_container_holo.9.png index 42aca5f511..d2f9b58b1e 100644 Binary files a/res/drawable-mdpi/portal_container_holo.9.png and b/res/drawable-mdpi/portal_container_holo.9.png differ diff --git a/res/drawable-mdpi/portal_ring_inner_holo.png b/res/drawable-mdpi/portal_ring_inner_holo.png index 4a6469488d..dc0c04170b 100644 Binary files a/res/drawable-mdpi/portal_ring_inner_holo.png and b/res/drawable-mdpi/portal_ring_inner_holo.png differ diff --git a/res/drawable-mdpi/portal_ring_outer_holo.png b/res/drawable-mdpi/portal_ring_outer_holo.png index 90cf77fa85..5a7e7402b9 100644 Binary files a/res/drawable-mdpi/portal_ring_outer_holo.png and b/res/drawable-mdpi/portal_ring_outer_holo.png differ diff --git a/res/layout-land/folder_icon.xml b/res/layout-land/folder_icon.xml index c76a75666a..60569c5539 100644 --- a/res/layout-land/folder_icon.xml +++ b/res/layout-land/folder_icon.xml @@ -4,9 +4,9 @@ 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. @@ -14,5 +14,19 @@ limitations under the License. --> - + + + + diff --git a/res/layout-port/folder_icon.xml b/res/layout-port/folder_icon.xml index 49049cfafa..3f776dec0e 100644 --- a/res/layout-port/folder_icon.xml +++ b/res/layout-port/folder_icon.xml @@ -4,9 +4,9 @@ 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. @@ -14,5 +14,19 @@ limitations under the License. --> - + + + + diff --git a/res/layout/user_folder.xml b/res/layout/user_folder.xml index 5ef959d718..7e25f356e6 100644 --- a/res/layout/user_folder.xml +++ b/res/layout/user_folder.xml @@ -17,16 +17,20 @@ - + + + \ No newline at end of file diff --git a/res/values-large/dimens.xml b/res/values-large/dimens.xml index 924832a558..eb48859a60 100644 --- a/res/values-large/dimens.xml +++ b/res/values-large/dimens.xml @@ -106,9 +106,16 @@ 6 + 12dp 12dp 4dp 20dp + + + + 80dp + + 4dp diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 15dbc3ab6f..141df0615a 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -83,9 +83,18 @@ -1dp -1dp + 0dp 0dp 0dp 0dp + + + + 56dp + + 4dp + 18dp + 10dp diff --git a/res/values/strings.xml b/res/values/strings.xml index 0ad1a46f24..70f212c2e0 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -254,9 +254,12 @@ http://www.google.com/m?client=ms-{CID}&source=android-home-hotseat - + This is a system application and cannot be uninstalled. Rocket Launcher + + + Unnamed Folder diff --git a/src/com/android/launcher2/BubbleTextView.java b/src/com/android/launcher2/BubbleTextView.java index 703b3a8cb9..8c0c27ca21 100644 --- a/src/com/android/launcher2/BubbleTextView.java +++ b/src/com/android/launcher2/BubbleTextView.java @@ -262,10 +262,12 @@ public class BubbleTextView extends TextView implements VisibilityChangedBroadca } void setCellLayoutPressedOrFocusedIcon() { - CellLayoutChildren parent = (CellLayoutChildren) getParent(); - if (parent != null) { - CellLayout layout = (CellLayout) parent.getParent(); - layout.setPressedOrFocusedIcon((mPressedOrFocusedBackground != null) ? this : null); + if (getParent() instanceof CellLayoutChildren) { + CellLayoutChildren parent = (CellLayoutChildren) getParent(); + if (parent != null) { + CellLayout layout = (CellLayout) parent.getParent(); + layout.setPressedOrFocusedIcon((mPressedOrFocusedBackground != null) ? this : null); + } } } diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java index a9ba88d940..c1aa2d5897 100644 --- a/src/com/android/launcher2/CellLayout.java +++ b/src/com/android/launcher2/CellLayout.java @@ -298,6 +298,7 @@ public class CellLayout extends ViewGroup { mCountX = x; mCountY = y; mOccupied = new boolean[mCountX][mCountY]; + requestLayout(); } private void invalidateBubbleTextView(BubbleTextView icon) { @@ -971,7 +972,8 @@ public class CellLayout extends ViewGroup { return mChildren.getChildAt(x, y); } - public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration) { + public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration, + int delay) { CellLayoutChildren clc = getChildrenLayout(); if (clc.indexOfChild(child) != -1 && !mOccupied[cellX][cellY]) { final LayoutParams lp = (LayoutParams) child.getLayoutParams(); @@ -996,6 +998,10 @@ public class CellLayout extends ViewGroup { int newX = lp.x; int newY = lp.y; + lp.x = oldX; + lp.y = oldY; + child.requestLayout(); + PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", oldX, newX); PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", oldY, newY); ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, x, y); @@ -1023,6 +1029,7 @@ public class CellLayout extends ViewGroup { cancelled = true; } }); + oa.setStartDelay(delay); oa.start(); return true; } diff --git a/src/com/android/launcher2/CellLayoutChildren.java b/src/com/android/launcher2/CellLayoutChildren.java index 6e78885ded..1caecc0018 100644 --- a/src/com/android/launcher2/CellLayoutChildren.java +++ b/src/com/android/launcher2/CellLayoutChildren.java @@ -83,6 +83,7 @@ public class CellLayoutChildren extends ViewGroup { lp.setup(mCellWidth, mCellHeight, mWidthGap, mHeightGap); } + public void measureChild(View child) { final int cellWidth = mCellWidth; final int cellHeight = mCellHeight; @@ -92,7 +93,6 @@ public class CellLayoutChildren extends ViewGroup { int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY); int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); - child.measure(childWidthMeasureSpec, childheightMeasureSpec); } diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java index af47bea783..c4d75d6ebc 100644 --- a/src/com/android/launcher2/DragLayer.java +++ b/src/com/android/launcher2/DragLayer.java @@ -25,6 +25,7 @@ import android.util.AttributeSet; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; +import android.view.ViewParent; import android.widget.FrameLayout; import android.widget.ImageView; @@ -62,13 +63,13 @@ public class DragLayer extends FrameLayout { mLauncher = launcher; mDragController = controller; } - + @Override public boolean dispatchKeyEvent(KeyEvent event) { return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event); } - private boolean handleTouchDown(MotionEvent ev) { + private boolean handleTouchDown(MotionEvent ev, boolean intercept) { Rect hitRect = new Rect(); int x = (int) ev.getX(); int y = (int) ev.getY(); @@ -85,17 +86,21 @@ public class DragLayer extends FrameLayout { } } } - if (mCurrentFolder != null) { - mCurrentFolder.getHitRect(hitRect); - int[] screenPos = new int[2]; - View parent = (View) mCurrentFolder.getParent(); - if (parent != null) { - parent.getLocationOnScreen(screenPos); - hitRect.offset(screenPos[0], screenPos[1]); + + if (mCurrentFolder != null && intercept) { + if (mCurrentFolder.isEditingName()) { + getDescendantRectRelativeToSelf(mCurrentFolder.getEditTextRegion(), hitRect); if (!hitRect.contains(x, y)) { - mLauncher.closeFolder(); + mCurrentFolder.dismissEditingName(); + return true; } } + + getDescendantRectRelativeToSelf(mCurrentFolder, hitRect); + if (!hitRect.contains(x, y)) { + mLauncher.closeFolder(); + return true; + } } return false; } @@ -103,7 +108,7 @@ public class DragLayer extends FrameLayout { @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { - if (handleTouchDown(ev)) { + if (handleTouchDown(ev, true)) { return true; } } @@ -121,7 +126,7 @@ public class DragLayer extends FrameLayout { if (ev.getAction() == MotionEvent.ACTION_DOWN) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { - if (handleTouchDown(ev)) { + if (handleTouchDown(ev, false)) { return true; } } @@ -143,6 +148,18 @@ public class DragLayer extends FrameLayout { return mDragController.onTouchEvent(ev); } + private void getDescendantRectRelativeToSelf(View descendant, Rect r) { + descendant.getHitRect(r); + + ViewParent viewParent = descendant.getParent(); + while (viewParent instanceof View && viewParent != this) { + final View view = (View)viewParent; + r.offset(view.getLeft() + (int) (view.getTranslationX() + 0.5f) - view.getScrollX(), + view.getTop() + (int) (view.getTranslationY() + 0.5f) - view.getScrollY()); + viewParent = view.getParent(); + } + } + @Override public boolean dispatchUnhandledMove(View focused, int direction) { return mDragController.dispatchUnhandledMove(focused, direction); diff --git a/src/com/android/launcher2/FastBitmapDrawable.java b/src/com/android/launcher2/FastBitmapDrawable.java index 3e75fb6d04..9fa62da4a7 100644 --- a/src/com/android/launcher2/FastBitmapDrawable.java +++ b/src/com/android/launcher2/FastBitmapDrawable.java @@ -64,6 +64,10 @@ class FastBitmapDrawable extends Drawable { mPaint.setAlpha(alpha); } + public void setFilterBitmap(boolean filterBitmap) { + mPaint.setFilterBitmap(filterBitmap); + } + public int getAlpha() { return mAlpha; } diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java index d81183c6b0..960fa551c4 100644 --- a/src/com/android/launcher2/Folder.java +++ b/src/com/android/launcher2/Folder.java @@ -23,16 +23,22 @@ import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.content.Context; -import android.graphics.Color; +import android.content.res.Resources; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.AttributeSet; +import android.view.ActionMode; +import android.view.KeyEvent; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.LinearLayout; import android.widget.TextView; @@ -48,7 +54,8 @@ import java.util.ArrayList; * Represents a set of icons chosen by the user or generated by the system. */ public class Folder extends LinearLayout implements DragSource, OnItemLongClickListener, - OnItemClickListener, OnClickListener, View.OnLongClickListener, DropTarget, FolderListener { + OnItemClickListener, OnClickListener, View.OnLongClickListener, DropTarget, FolderListener, + TextView.OnEditorActionListener { protected DragController mDragController; @@ -90,6 +97,11 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL private int[] mEmptyCell = new int[2]; private Alarm mReorderAlarm = new Alarm(); private Alarm mOnExitAlarm = new Alarm(); + private TextView mFolderName; + private int mFolderNameHeight; + + private boolean mIsEditingName = false; + private InputMethodManager mInputMethodManager; /** * Used to inflate the Workspace from XML. @@ -102,10 +114,14 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL setAlwaysDrawnWithCacheEnabled(false); mInflater = LayoutInflater.from(context); mIconCache = ((LauncherApplication)context.getApplicationContext()).getIconCache(); - mExpandDuration = getResources().getInteger(R.integer.config_folderAnimDuration); - mMaxCountX = LauncherModel.getCellCountX() - 1; mMaxCountY = LauncherModel.getCellCountY() - 1; + + mInputMethodManager = (InputMethodManager) + mContext.getSystemService(Context.INPUT_METHOD_SERVICE); + + Resources res = getResources(); + mExpandDuration = res.getInteger(R.integer.config_folderAnimDuration); } @Override @@ -114,8 +130,37 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL mContent = (CellLayout) findViewById(R.id.folder_content); mContent.setGridSize(0, 0); mContent.enableHardwareLayers(); + mFolderName = (TextView) findViewById(R.id.folder_name); + + // 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(); + + // We disable action mode for now since it messes up the view on phones + mFolderName.setCustomSelectionActionModeCallback(mActionModeCallback); + mFolderName.setCursorVisible(false); + mFolderName.setOnEditorActionListener(this); } + private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() { + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + return false; + } + + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + return false; + } + + public void onDestroyActionMode(ActionMode mode) { + } + + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return false; + } + }; + public void onItemClick(AdapterView parent, View v, int position, long id) { ShortcutInfo app = (ShortcutInfo) parent.getItemAtPosition(position); int[] pos = new int[2]; @@ -138,6 +183,17 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL } } + private Rect mHitRect = new Rect(); + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + mFolderName.getHitRect(mHitRect); + if (mHitRect.contains((int) ev.getX(), (int) ev.getY()) && !mIsEditingName) { + startEditingFolderName(); + } + } + return false; + } + public boolean onLongClick(View v) { Object tag = v.getTag(); if (tag instanceof ShortcutInfo) { @@ -158,13 +214,44 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL mCurrentDragView = v; mContent.removeView(mCurrentDragView); mInfo.remove(item); - } else { - mLauncher.closeFolder(this); - mLauncher.showRenameDialog(mInfo); } return true; } + public boolean isEditingName() { + return mIsEditingName; + } + + public void startEditingFolderName() { + mFolderName.setCursorVisible(true); + mIsEditingName = true; + } + + public void dismissEditingName() { + mInputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); + doneEditingFolderName(true); + } + + public void doneEditingFolderName(boolean commit) { + mInfo.setTitle(mFolderName.getText()); + LauncherModel.updateItemInDatabase(mLauncher, mInfo); + mFolderName.setCursorVisible(false); + mFolderName.clearFocus(); + mIsEditingName = false; + } + + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (actionId == EditorInfo.IME_ACTION_DONE) { + dismissEditingName(); + return true; + } + return false; + } + + public View getEditTextRegion() { + return mFolderName; + } + public Drawable getDragDrawable() { return mIconDrawable; } @@ -216,12 +303,13 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL // forcing a layout // TODO: find out if this is still necessary mContent.requestLayout(); - requestFocus(); } void onClose() { - final Workspace workspace = mLauncher.getWorkspace(); - workspace.getChildAt(workspace.getCurrentPage()).requestFocus(); + CellLayoutChildren clc = (CellLayoutChildren) getParent(); + final CellLayout cellLayout = (CellLayout) clc.getParent(); + cellLayout.removeViewWithoutMarkingCells(Folder.this); + clearFocus(); } void bind(FolderInfo info) { @@ -234,6 +322,7 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL } mItemsInvalidated = true; mInfo.addListener(this); + mFolderName.setText(mInfo.title); } /** @@ -322,10 +411,7 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL public void animateClosed() { if (!(getParent() instanceof CellLayoutChildren)) return; - CellLayoutChildren clc = (CellLayoutChildren) getParent(); - final CellLayout cellLayout = (CellLayout) clc.getParent(); ObjectAnimator oa; - if (mMode == PARTIAL_GROW) { PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0); PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 0.9f); @@ -356,8 +442,8 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL oa.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { + onClose(); onCloseComplete(); - cellLayout.removeViewWithoutMarkingCells(Folder.this); mState = STATE_SMALL; } @Override @@ -438,6 +524,8 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL int startX; int endX; int startY; + int delay = 0; + float delayAmount = 30; if (readingOrderGreaterThan(target, empty)) { wrap = empty[0] >= mContent.getCountX() - 1; startY = wrap ? empty[1] + 1 : empty[1]; @@ -447,9 +535,11 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL for (int x = startX; x <= endX; x++) { View v = mContent.getChildAt(x,y); if (mContent.animateChildToPosition(v, empty[0], empty[1], - REORDER_ANIMATION_DURATION)) { + REORDER_ANIMATION_DURATION, delay)) { empty[0] = x; empty[1] = y; + delay += delayAmount; + delayAmount *= 0.9; } } } @@ -462,9 +552,11 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL for (int x = startX; x >= endX; x--) { View v = mContent.getChildAt(x,y); if (mContent.animateChildToPosition(v, empty[0], empty[1], - REORDER_ANIMATION_DURATION)) { + REORDER_ANIMATION_DURATION, delay)) { empty[0] = x; empty[1] = y; + delay += delayAmount; + delayAmount *= 0.9; } } } @@ -591,7 +683,9 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams(); int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth(); - int height = getPaddingTop() + getPaddingBottom() + mContent.getDesiredHeight(); + // Technically there is no padding at the bottom, but we add space equal to the padding + // and have to account for that here. + int height = getPaddingTop() + mContent.getDesiredHeight() + mFolderNameHeight; int centerX = iconLp.x + iconLp.width / 2; int centerY = iconLp.y + iconLp.height / 2; @@ -732,6 +826,8 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL public void onItemsChanged() { } + public void onTitleChanged(CharSequence title) { + } public ArrayList getItemsInReadingOrder() { return getItemsInReadingOrder(true); diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java index 18b242bfa1..db3dfe8f2d 100644 --- a/src/com/android/launcher2/FolderIcon.java +++ b/src/com/android/launcher2/FolderIcon.java @@ -30,7 +30,8 @@ import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.TextView; import com.android.launcher.R; @@ -42,39 +43,32 @@ import java.util.ArrayList; /** * An icon that can appear on in the workspace representing an {@link UserFolder}. */ -public class FolderIcon extends FrameLayout implements FolderListener { +public class FolderIcon extends LinearLayout implements FolderListener { private Launcher mLauncher; Folder mFolder; FolderInfo mInfo; // The number of icons to display in the - private static final int NUM_ITEMS_IN_PREVIEW = 4; + private static final int NUM_ITEMS_IN_PREVIEW = 3; private static final int CONSUMPTION_ANIMATION_DURATION = 100; // The degree to which the inner ring grows when accepting drop private static final float INNER_RING_GROWTH_FACTOR = 0.1f; - // The degree to which the inner ring is scaled in its natural state - private static final float INNER_RING_BASELINE_SCALE = 1.0f; - - // The degree to which the outer ring grows when accepting drop - private static final float OUTER_RING_BASELINE_SCALE = 0.7f; - // The degree to which the outer ring is scaled in its natural state - private static final float OUTER_RING_GROWTH_FACTOR = 0.3f; + private static final float OUTER_RING_GROWTH_FACTOR = 0.4f; // The amount of vertical spread between items in the stack [0...1] - private static final float PERSPECTIVE_SHIFT_FACTOR = 0.3f; + private static final float PERSPECTIVE_SHIFT_FACTOR = 0.24f; // 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.3f; - - // The percentage of the FolderIcons view that will be dedicated to the items preview - private static final float SPACE_PERCENTAGE_FOR_ICONS = 0.8f; + private static final float PERSPECTIVE_SCALE_FACTOR = 0.35f; private int mOriginalWidth = -1; private int mOriginalHeight = -1; + private ImageView mPreviewBackground; + private BubbleTextView mFolderName; FolderRingAnimator mFolderRingAnimator = null; @@ -98,9 +92,10 @@ public class FolderIcon extends FrameLayout implements FolderListener { FolderIcon icon = (FolderIcon) LayoutInflater.from(launcher).inflate(resId, group, false); - final Resources resources = launcher.getResources(); - Drawable d = iconCache.getFullResIcon(resources, R.drawable.portal_ring_inner_holo); - icon.setBackgroundDrawable(d); + icon.mFolderName = (BubbleTextView) icon.findViewById(R.id.folder_name); + icon.mFolderName.setText(folderInfo.title); + icon.mPreviewBackground = (ImageView) icon.findViewById(R.id.preview_background); + icon.setTag(folderInfo); icon.setOnClickListener(launcher); icon.mInfo = folderInfo; @@ -121,31 +116,36 @@ public class FolderIcon extends FrameLayout implements FolderListener { public static class FolderRingAnimator { public int mFolderLocX; public int mFolderLocY; - public float mOuterRingScale; - public float mInnerRingScale; + public float mOuterRingSize; + public float mInnerRingSize; public FolderIcon mFolderIcon = null; private Launcher mLauncher; public Drawable mOuterRingDrawable = null; public Drawable mInnerRingDrawable = null; public static Drawable sSharedOuterRingDrawable = null; public static Drawable sSharedInnerRingDrawable = null; + public static int sPreviewSize = -1; + public static int sPreviewPadding = -1; + private ValueAnimator mAcceptAnimator; private ValueAnimator mNeutralAnimator; public FolderRingAnimator(Launcher launcher, FolderIcon folderIcon) { mLauncher = launcher; mFolderIcon = folderIcon; - mOuterRingDrawable = - launcher.getResources().getDrawable(R.drawable.portal_ring_outer_holo); - mInnerRingDrawable = - launcher.getResources().getDrawable(R.drawable.portal_ring_inner_holo); + Resources res = launcher.getResources(); + mOuterRingDrawable = res.getDrawable(R.drawable.portal_ring_outer_holo); + mInnerRingDrawable = res.getDrawable(R.drawable.portal_ring_inner_holo); + + if (sPreviewSize < 0 || sPreviewPadding < 0) { + sPreviewSize = res.getDimensionPixelSize(R.dimen.folder_preview_size); + sPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding); + } if (sSharedOuterRingDrawable == null) { - sSharedOuterRingDrawable = - launcher.getResources().getDrawable(R.drawable.portal_ring_outer_holo); + sSharedOuterRingDrawable = res.getDrawable(R.drawable.portal_ring_outer_holo); } if (sSharedInnerRingDrawable == null) { - sSharedInnerRingDrawable = - launcher.getResources().getDrawable(R.drawable.portal_ring_inner_holo); + sSharedInnerRingDrawable = res.getDrawable(R.drawable.portal_ring_inner_holo); } } @@ -164,8 +164,8 @@ public class FolderIcon extends FrameLayout implements FolderListener { mAcceptAnimator.addUpdateListener(new AnimatorUpdateListener() { public void onAnimationUpdate(ValueAnimator animation) { final float percent = (Float) animation.getAnimatedValue(); - mOuterRingScale = OUTER_RING_BASELINE_SCALE + percent * OUTER_RING_GROWTH_FACTOR; - mInnerRingScale = INNER_RING_BASELINE_SCALE + percent * INNER_RING_GROWTH_FACTOR; + mOuterRingSize = (1 + percent * OUTER_RING_GROWTH_FACTOR) * sPreviewSize; + mInnerRingSize = (1 + percent * INNER_RING_GROWTH_FACTOR) * sPreviewSize; mLauncher.getWorkspace().invalidate(); if (mFolderIcon != null) { mFolderIcon.invalidate(); @@ -176,7 +176,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { @Override public void onAnimationStart(Animator animation) { if (mFolderIcon != null) { - mFolderIcon.setBackgroundDrawable(null); + mFolderIcon.mPreviewBackground.setVisibility(INVISIBLE); } } }); @@ -192,10 +192,8 @@ public class FolderIcon extends FrameLayout implements FolderListener { mNeutralAnimator.addUpdateListener(new AnimatorUpdateListener() { public void onAnimationUpdate(ValueAnimator animation) { final float percent = (Float) animation.getAnimatedValue(); - mOuterRingScale = OUTER_RING_BASELINE_SCALE + OUTER_RING_GROWTH_FACTOR - - percent * OUTER_RING_GROWTH_FACTOR; - mInnerRingScale = INNER_RING_BASELINE_SCALE + INNER_RING_GROWTH_FACTOR - - percent * INNER_RING_GROWTH_FACTOR; + mOuterRingSize = (1 + (1 - percent) * OUTER_RING_GROWTH_FACTOR) * sPreviewSize; + mInnerRingSize = (1 + (1 - percent) * INNER_RING_GROWTH_FACTOR) * sPreviewSize; mLauncher.getWorkspace().invalidate(); if (mFolderIcon != null) { mFolderIcon.invalidate(); @@ -206,7 +204,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { @Override public void onAnimationEnd(Animator animation) { if (mFolderIcon != null) { - mFolderIcon.setBackgroundDrawable(mInnerRingDrawable); + mFolderIcon.mPreviewBackground.setVisibility(VISIBLE); } mLauncher.getWorkspace().hideFolderAccept(FolderRingAnimator.this); } @@ -220,12 +218,12 @@ public class FolderIcon extends FrameLayout implements FolderListener { loc[1] = mFolderLocY; } - public float getOuterRingScale() { - return mOuterRingScale; + public float getOuterRingSize() { + return mOuterRingSize; } - public float getInnerRingScale() { - return mInnerRingScale; + public float getInnerRingSize() { + return mInnerRingSize; } } @@ -258,7 +256,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { mLauncher.getWorkspace().getLocationInWindow(wsLocation); int x = tvLocation[0] - wsLocation[0] + getMeasuredWidth() / 2; - int y = tvLocation[1] - wsLocation[1] + getMeasuredHeight() / 2; + int y = tvLocation[1] - wsLocation[1] + FolderRingAnimator.sPreviewSize / 2; mFolderRingAnimator.setLocation(x, y); } @@ -296,31 +294,38 @@ public class FolderIcon extends FrameLayout implements FolderListener { @Override protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (mFolder == null) return; if (mFolder.getItemCount() == 0) return; canvas.save(); TextView v = (TextView) mFolder.getItemAt(0); Drawable d = v.getCompoundDrawables()[1]; + int intrinsicIconSize = d.getIntrinsicHeight(); if (mOriginalWidth < 0 || mOriginalHeight < 0) { mOriginalWidth = getMeasuredWidth(); mOriginalHeight = getMeasuredHeight(); } + final int previewSize = FolderRingAnimator.sPreviewSize; + final int previewPadding = FolderRingAnimator.sPreviewPadding; - int unscaledHeight = (int) (d.getIntrinsicHeight() * (1 + PERSPECTIVE_SHIFT_FACTOR)); - float baselineIconScale = SPACE_PERCENTAGE_FOR_ICONS / (unscaledHeight / (mOriginalHeight * 1.0f)); + int halfAvailableSpace = (previewSize - 2 * previewPadding) / 2; + // cos(45) = 0.707 + ~= 0.1) + int availableSpace = (int) (halfAvailableSpace * (1 + 0.8f)); - int baselineHeight = (int) (d.getIntrinsicHeight() * baselineIconScale); - int totalStackHeight = (int) (baselineHeight * (1 + PERSPECTIVE_SHIFT_FACTOR)); - int baselineWidth = (int) (d.getIntrinsicWidth() * baselineIconScale); - float maxPerpectiveShift = baselineHeight * PERSPECTIVE_SHIFT_FACTOR; + int unscaledHeight = (int) (intrinsicIconSize * (1 + PERSPECTIVE_SHIFT_FACTOR)); + float baselineIconScale = (1.0f * availableSpace / unscaledHeight); + + int baselineSize = (int) (intrinsicIconSize * baselineIconScale); + float maxPerspectiveShift = baselineSize * PERSPECTIVE_SHIFT_FACTOR; ArrayList items = mFolder.getItemsInReadingOrder(false); int firstItemIndex = Math.max(0, items.size() - NUM_ITEMS_IN_PREVIEW); - int xShift = (int) (mOriginalWidth - baselineWidth) / 2; - int yShift = (int) (mOriginalHeight - totalStackHeight) / 2; + int xShift = (mOriginalWidth - 2 * halfAvailableSpace) / 2; + int yShift = previewPadding; canvas.translate(xShift, yShift); for (int i = firstItemIndex; i < items.size(); i++) { int index = i - firstItemIndex; @@ -328,10 +333,17 @@ public class FolderIcon extends FrameLayout implements FolderListener { float r = (index * 1.0f) / (NUM_ITEMS_IN_PREVIEW - 1); float scale = (1 - PERSPECTIVE_SCALE_FACTOR * (1 - r)); - r = (float) Math.pow(r, 2); - float transY = r * maxPerpectiveShift; - float transX = (1 - scale) * baselineWidth / 2.0f; + //r = (float) Math.pow(r, 2); + + float offset = (1 - r) * maxPerspectiveShift; + float scaledSize = scale * baselineSize; + float scaleOffsetCorrection = (1 - scale) * baselineSize; + + // We want to imagine our coordinates from the bottom left, growing up and to the + // right. This is natural for the x-axis, but for the y-axis, we have to invert things. + float transY = 2 * halfAvailableSpace - (offset + scaledSize + scaleOffsetCorrection); + float transX = offset + scaleOffsetCorrection; v = (TextView) items.get(i); d = v.getCompoundDrawables()[1]; @@ -342,10 +354,12 @@ public class FolderIcon extends FrameLayout implements FolderListener { int overlayAlpha = (int) (80 * (1 - r)); if (d != null) { - d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight()); + d.setBounds(0, 0, intrinsicIconSize, intrinsicIconSize); + d.setFilterBitmap(true); d.setColorFilter(Color.argb(overlayAlpha, 0, 0, 0), PorterDuff.Mode.SRC_ATOP); d.draw(canvas); d.clearColorFilter(); + d.setFilterBitmap(false); } canvas.restore(); } @@ -366,4 +380,10 @@ public class FolderIcon extends FrameLayout implements FolderListener { invalidate(); requestLayout(); } + + public void onTitleChanged(CharSequence title) { + mFolderName.setText(title); + mFolderName.invalidate(); + mFolderName.requestLayout(); + } } diff --git a/src/com/android/launcher2/FolderInfo.java b/src/com/android/launcher2/FolderInfo.java index 805a51f399..b5b5b29c19 100644 --- a/src/com/android/launcher2/FolderInfo.java +++ b/src/com/android/launcher2/FolderInfo.java @@ -70,6 +70,13 @@ class FolderInfo extends ItemInfo { } } + public void setTitle(CharSequence title) { + this.title = title; + for (int i = 0; i < listeners.size(); i++) { + listeners.get(i).onTitleChanged(title); + } + } + @Override void onAddToDatabase(ContentValues values) { super.onAddToDatabase(values); @@ -95,6 +102,7 @@ class FolderInfo extends ItemInfo { interface FolderListener { public void onAdd(ShortcutInfo item); public void onRemove(ShortcutInfo item); + public void onTitleChanged(CharSequence title); public void onItemsChanged(); } } diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java index bda55919d2..323c52700d 100644 --- a/src/com/android/launcher2/Launcher.java +++ b/src/com/android/launcher2/Launcher.java @@ -1728,7 +1728,12 @@ public final class Launcher extends Activity if (mState == State.APPS_CUSTOMIZE) { showWorkspace(true); } else if (mWorkspace.getOpenFolder() != null) { - closeFolder(); + Folder openFolder = mWorkspace.getOpenFolder(); + if (openFolder.isEditingName()) { + openFolder.dismissEditingName(); + } else { + closeFolder(); + } } else if (isPreviewVisible()) { dismissPreview(mPreviousView); dismissPreview(mNextView); @@ -1760,7 +1765,6 @@ public final class Launcher extends Activity } folder.animateClosed(); - folder.onClose(); } /** diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java index 1fa23cf4c6..ca0847ef9f 100644 --- a/src/com/android/launcher2/PagedView.java +++ b/src/com/android/launcher2/PagedView.java @@ -692,7 +692,7 @@ public abstract class PagedView extends ViewGroup { } View v = getPageAt(focusablePage); if (v != null) { - v.requestFocus(direction, previouslyFocusedRect); + return v.requestFocus(direction, previouslyFocusedRect); } return false; } diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java index 1048fd5705..b07e22b39b 100644 --- a/src/com/android/launcher2/Workspace.java +++ b/src/com/android/launcher2/Workspace.java @@ -1199,11 +1199,12 @@ public class Workspace extends SmoothPagedView View currentPage = getChildAt(getCurrentPage()); Matrix m = currentPage.getMatrix(); - // Draw outer ring FolderRingAnimator fra = mFolderOuterRings.get(i); + + // Draw outer ring Drawable d = FolderRingAnimator.sSharedOuterRingDrawable; - int width = (int) (d.getIntrinsicWidth() * fra.getOuterRingScale()); - int height = (int) (d.getIntrinsicHeight() * fra.getOuterRingScale()); + int width = (int) fra.getOuterRingSize(); + int height = width; fra.getLocation(mTempLocation); // First we map the folder's location from window coordinates to its containing @@ -1226,34 +1227,28 @@ public class Workspace extends SmoothPagedView canvas.restore(); // Draw inner ring - if (fra.mFolderIcon != null) { - int folderWidth = fra.mFolderIcon != null ? - fra.mFolderIcon.getMeasuredWidth() : mCellWidth; - int folderHeight = fra.mFolderIcon != null ? - fra.mFolderIcon.getMeasuredWidth() : mCellHeight; - d = FolderRingAnimator.sSharedInnerRingDrawable; - width = (int) (folderWidth * fra.getInnerRingScale()); - height = (int) (folderHeight * fra.getInnerRingScale()); + d = FolderRingAnimator.sSharedInnerRingDrawable; + width = (int) fra.getInnerRingSize(); + height = width; - // First we map the folder's location from window coordinates to its containing - // CellLayout's coordinates. Then we transform the coordinates according to the - // CellLayout's transform. Finally, we map this back into the coordinates of the - // the window (ie. Workspace). - x = mTempLocation[0] + mScrollX - width / 2 - currentPage.getLeft(); - y = mTempLocation[1] + mScrollY - height / 2 - currentPage.getTop(); - mTempFloatTuple[0] = x; - mTempFloatTuple[1] = y; - m.mapPoints(mTempFloatTuple); - x = (int) (mTempFloatTuple[0]) + currentPage.getLeft(); - y = (int) (mTempFloatTuple[1]) + currentPage.getTop(); + // First we map the folder's location from window coordinates to its containing + // CellLayout's coordinates. Then we transform the coordinates according to the + // CellLayout's transform. Finally, we map this back into the coordinates of the + // the window (ie. Workspace). + x = mTempLocation[0] + mScrollX - width / 2 - currentPage.getLeft(); + y = mTempLocation[1] + mScrollY - height / 2 - currentPage.getTop(); + mTempFloatTuple[0] = x; + mTempFloatTuple[1] = y; + m.mapPoints(mTempFloatTuple); + x = (int) (mTempFloatTuple[0]) + currentPage.getLeft(); + y = (int) (mTempFloatTuple[1]) + currentPage.getTop(); - canvas.save(); - canvas.translate(x, y); - d.setBounds(0, 0, (int) (width * currentPage.getScaleX()), - (int) (height * currentPage.getScaleY())); - d.draw(canvas); - canvas.restore(); - } + canvas.save(); + canvas.translate(x, y); + d.setBounds(0, 0, (int) (width * currentPage.getScaleX()), + (int) (height * currentPage.getScaleY())); + d.draw(canvas); + canvas.restore(); } super.onDraw(canvas); } @@ -3025,8 +3020,9 @@ public class Workspace extends SmoothPagedView mCellWidth = mDragTargetLayout.getCellWidth(); mCellHeight = mDragTargetLayout.getCellHeight(); } + int x = tvLocation[0] - wsLocation[0] + v.getMeasuredWidth() / 2; - int y = tvLocation[1] - wsLocation[1] + v.getMeasuredHeight() / 2; + int y = tvLocation[1] - wsLocation[1] + FolderRingAnimator.sPreviewSize / 2; if (mDragFolderRingAnimator == null) { mDragFolderRingAnimator = new FolderRingAnimator(mLauncher, null);