Merge "Updating folder UI" into ub-launcher3-burnaby

This commit is contained in:
Sunny Goyal
2015-04-09 23:35:01 +00:00
committed by Android (Google) Code Review
6 changed files with 162 additions and 641 deletions
+2 -2
View File
@@ -16,8 +16,8 @@
<com.android.launcher3.PageIndicatorMarker
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_gravity="center_vertical">
<ImageView
android:id="@+id/inactive"
+33 -19
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2008 The Android Open Source Project
Copyright (C) 2015 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.
@@ -34,30 +34,44 @@
android:layout_width="20dp"
android:layout_height="20dp" />
<com.android.launcher3.FolderCellLayout
<com.android.launcher3.FolderPagedView
android:id="@+id/folder_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:cacheColorHint="#ff333333"
android:hapticFeedbackEnabled="false" />
launcher:pageIndicator="@+id/folder_page_indicator" />
</FrameLayout>
<com.android.launcher3.FolderEditText
android:id="@+id/folder_name"
<LinearLayout
android:id="@+id/folder_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#00000000"
android:fontFamily="sans-serif-condensed"
android:gravity="center_horizontal"
android:hint="@string/folder_hint_text"
android:imeOptions="flagNoExtractUi"
android:paddingBottom="@dimen/folder_name_padding"
android:paddingTop="@dimen/folder_name_padding"
android:singleLine="true"
android:textColor="#ff777777"
android:textColorHighlight="#ffCCCCCC"
android:textColorHint="#ff808080"
android:textCursorDrawable="@null"
android:textSize="14sp" />
android:orientation="vertical" >
<include
android:id="@+id/folder_page_indicator"
android:layout_width="wrap_content"
android:layout_height="12dp"
android:layout_gravity="center_horizontal"
layout="@layout/page_indicator" />
<com.android.launcher3.FolderEditText
android:id="@+id/folder_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="#00000000"
android:fontFamily="sans-serif-condensed"
android:gravity="center_horizontal"
android:hint="@string/folder_hint_text"
android:imeOptions="flagNoExtractUi"
android:paddingBottom="@dimen/folder_name_padding"
android:paddingTop="@dimen/folder_name_padding"
android:singleLine="true"
android:textColor="#ff777777"
android:textColorHighlight="#ffCCCCCC"
android:textColorHint="#ff808080"
android:textCursorDrawable="@null"
android:textSize="14sp" />
</LinearLayout>
</com.android.launcher3.Folder>
-106
View File
@@ -1,106 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<com.android.launcher3.Folder xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/quantum_panel"
android:orientation="vertical" >
<FrameLayout
android:id="@+id/folder_content_wrapper"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- Actual size of the indicator doesn't matter as it is scaled to match the view size -->
<com.android.launcher3.FocusIndicatorView
android:id="@+id/focus_indicator"
android:layout_width="20dp"
android:layout_height="20dp" />
<com.android.launcher3.FolderPagedView
android:id="@+id/folder_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
launcher:pageIndicator="@+id/folder_page_indicator" />
</FrameLayout>
<LinearLayout
android:id="@+id/folder_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="12dp"
android:paddingEnd="8dp" >
<com.android.launcher3.FolderEditText
android:id="@+id/folder_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:background="#00000000"
android:fontFamily="sans-serif-condensed"
android:gravity="start"
android:hint="@string/folder_hint_text"
android:imeOptions="flagNoExtractUi"
android:paddingBottom="@dimen/folder_name_padding"
android:paddingTop="@dimen/folder_name_padding"
android:singleLine="true"
android:textColor="#ff777777"
android:textColorHighlight="#ffCCCCCC"
android:textColorHint="#ff808080"
android:textCursorDrawable="@null"
android:textSize="14sp" />
<include
android:id="@+id/folder_page_indicator"
android:layout_width="wrap_content"
android:layout_height="12dp"
android:layout_gravity="top"
android:layout_marginTop="5dp"
layout="@layout/page_indicator" />
<LinearLayout
android:id="@+id/folder_sort"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:gravity="end|center_vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:text="@string/sort_alphabetical"
android:textColor="#ff777777"
android:textSize="14sp" />
<Switch
android:id="@+id/folder_sort_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:duplicateParentState="true"
android:focusable="false" />
</LinearLayout>
</LinearLayout>
</com.android.launcher3.Folder>
+46 -134
View File
@@ -69,7 +69,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
* results in CellLayout being measured as UNSPECIFIED, which it does not support.
*/
private static final int MIN_CONTENT_DIMEN = 5;
private static final boolean ALLOW_FOLDER_SCROLL = true;
static final int STATE_NONE = -1;
static final int STATE_SMALL = 0;
@@ -101,6 +100,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
private final Alarm mReorderAlarm = new Alarm();
private final Alarm mOnExitAlarm = new Alarm();
private final Alarm mOnScrollHintAlarm = new Alarm();
@Thunk final Alarm mScrollPauseAlarm = new Alarm();
@Thunk final ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
@@ -116,7 +117,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
@Thunk FolderIcon mFolderIcon;
@Thunk FolderContent mContent;
@Thunk FolderPagedView mContent;
@Thunk View mContentWrapper;
FolderEditText mFolderName;
@@ -149,11 +150,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
// Folder scrolling
private int mScrollAreaOffset;
private Alarm mOnScrollHintAlarm;
@Thunk Alarm mScrollPauseAlarm;
// TODO: Use {@link #mContent} once {@link #ALLOW_FOLDER_SCROLL} is removed.
@Thunk FolderPagedView mPagedView;
@Thunk int mScrollHintDir = DragController.SCROLL_NONE;
@Thunk int mCurrentScrollDir = DragController.SCROLL_NONE;
@@ -186,18 +182,13 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
// name is complete, we have something to focus on, thus hiding the cursor and giving
// reliable behavior when clicking the text field (since it will always gain focus on click).
setFocusableInTouchMode(true);
if (ALLOW_FOLDER_SCROLL) {
mOnScrollHintAlarm = new Alarm();
mScrollPauseAlarm = new Alarm();
}
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mContentWrapper = findViewById(R.id.folder_content_wrapper);
mContent = (FolderContent) findViewById(R.id.folder_content);
mContent = (FolderPagedView) findViewById(R.id.folder_content);
mContent.setFolder(this);
mFolderName = (FolderEditText) findViewById(R.id.folder_name);
@@ -211,16 +202,16 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
mFolderName.setInputType(mFolderName.getInputType() |
InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
mFooter = ALLOW_FOLDER_SCROLL ? findViewById(R.id.folder_footer) : mFolderName;
mFooter = findViewById(R.id.folder_footer);
updateFooterHeight();
}
public void updateFooterHeight() {
// We find out how tall footer 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;
mFooter.measure(measureSpec, measureSpec);
mFooterHeight = mFooter.getMeasuredHeight();
if (ALLOW_FOLDER_SCROLL) {
mPagedView = (FolderPagedView) mContent;
}
}
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
@@ -398,8 +389,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
* @return A new UserFolder.
*/
static Folder fromXml(Context context) {
return (Folder) LayoutInflater.from(context).inflate(
ALLOW_FOLDER_SCROLL ? R.layout.user_folder_scroll : R.layout.user_folder, null);
return (Folder) LayoutInflater.from(context).inflate(R.layout.user_folder, null);
}
/**
@@ -424,12 +414,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
public void animateOpen() {
if (!(getParent() instanceof DragLayer)) return;
if (ALLOW_FOLDER_SCROLL) {
mPagedView.completePendingPageChanges();
if (!(mDragInProgress && mPagedView.mIsSorted)) {
// Open on the first page.
mPagedView.snapToPageImmediately(0);
}
mContent.completePendingPageChanges();
if (!(mDragInProgress && mContent.mIsSorted)) {
// Open on the first page.
mContent.snapToPageImmediately(0);
}
Animator openFolderAnim = null;
@@ -533,10 +521,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
mDragController.forceTouchMove();
}
if (ALLOW_FOLDER_SCROLL) {
FolderPagedView pages = (FolderPagedView) mContent;
pages.verifyVisibleHighResIcons(pages.getNextPage());
}
FolderPagedView pages = (FolderPagedView) mContent;
pages.verifyVisibleHighResIcons(pages.getNextPage());
}
public void beginExternalDrag(ShortcutInfo item) {
@@ -544,7 +530,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
mEmptyCellRank = mContent.allocateRankForNewItem(item);
mIsExternalDrag = true;
mDragInProgress = true;
if (ALLOW_FOLDER_SCROLL && mPagedView.mIsSorted) {
if (mContent.mIsSorted) {
mScrollPauseAlarm.setOnAlarmListener(null);
mScrollPauseAlarm.cancelAlarm();
mScrollPauseAlarm.setAlarm(SORTED_STICKY_REORDER_DELAY);
@@ -601,11 +588,9 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
public void onDragEnter(DragObject d) {
mPrevTargetRank = -1;
mOnExitAlarm.cancelAlarm();
if (ALLOW_FOLDER_SCROLL) {
// Get the area offset such that the folder only closes if half the drag icon width
// is outside the folder area
mScrollAreaOffset = d.dragView.getDragRegionWidth() / 2 - d.xOffset;
}
// Get the area offset such that the folder only closes if half the drag icon width
// is outside the folder area
mScrollAreaOffset = d.dragView.getDragRegionWidth() / 2 - d.xOffset;
}
OnAlarmListener mReorderAlarmListener = new OnAlarmListener() {
@@ -632,7 +617,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
}
@Thunk void onDragOver(DragObject d, int reorderDelay) {
if (ALLOW_FOLDER_SCROLL && mScrollPauseAlarm.alarmPending()) {
if (mScrollPauseAlarm.alarmPending()) {
return;
}
final float[] r = new float[2];
@@ -645,27 +630,23 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
mPrevTargetRank = mTargetRank;
}
if (!ALLOW_FOLDER_SCROLL) {
return;
}
float x = r[0];
int currentPage = mPagedView.getNextPage();
int currentPage = mContent.getNextPage();
float cellOverlap = mPagedView.getCurrentCellLayout().getCellWidth()
float cellOverlap = mContent.getCurrentCellLayout().getCellWidth()
* ICON_OVERSCROLL_WIDTH_FACTOR;
boolean isOutsideLeftEdge = x < cellOverlap;
boolean isOutsideRightEdge = x > (getWidth() - cellOverlap);
if (currentPage > 0 && (mPagedView.rtlLayout ? isOutsideRightEdge : isOutsideLeftEdge)) {
if (currentPage > 0 && (mContent.rtlLayout ? isOutsideRightEdge : isOutsideLeftEdge)) {
showScrollHint(DragController.SCROLL_LEFT, d);
} else if (currentPage < (mPagedView.getPageCount() - 1)
&& (mPagedView.rtlLayout ? isOutsideLeftEdge : isOutsideRightEdge)) {
} else if (currentPage < (mContent.getPageCount() - 1)
&& (mContent.rtlLayout ? isOutsideLeftEdge : isOutsideRightEdge)) {
showScrollHint(DragController.SCROLL_RIGHT, d);
} else {
mOnScrollHintAlarm.cancelAlarm();
if (mScrollHintDir != DragController.SCROLL_NONE) {
mPagedView.clearScrollHint();
mContent.clearScrollHint();
mScrollHintDir = DragController.SCROLL_NONE;
}
}
@@ -674,7 +655,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
private void showScrollHint(int direction, DragObject d) {
// Show scroll hint on the right
if (mScrollHintDir != direction) {
mPagedView.showScrollHint(direction);
mContent.showScrollHint(direction);
mScrollHintDir = direction;
}
@@ -714,13 +695,11 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
}
mReorderAlarm.cancelAlarm();
if (ALLOW_FOLDER_SCROLL) {
mOnScrollHintAlarm.cancelAlarm();
mScrollPauseAlarm.cancelAlarm();
if (mScrollHintDir != DragController.SCROLL_NONE) {
mPagedView.clearScrollHint();
mScrollHintDir = DragController.SCROLL_NONE;
}
mOnScrollHintAlarm.cancelAlarm();
mScrollPauseAlarm.cancelAlarm();
if (mScrollHintDir != DragController.SCROLL_NONE) {
mContent.clearScrollHint();
mScrollHintDir = DragController.SCROLL_NONE;
}
}
@@ -1088,21 +1067,19 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
};
}
if (ALLOW_FOLDER_SCROLL) {
// If the icon was dropped while the page was being scrolled, we need to compute
// the target location again such that the icon is placed of the final page.
if (!mPagedView.rankOnCurrentPage(mEmptyCellRank)) {
// Reorder again.
mTargetRank = getTargetRank(d, null);
// If the icon was dropped while the page was being scrolled, we need to compute
// the target location again such that the icon is placed of the final page.
if (!mContent.rankOnCurrentPage(mEmptyCellRank)) {
// Reorder again.
mTargetRank = getTargetRank(d, null);
// Rearrange items immediately.
mReorderAlarmListener.onAlarm(mReorderAlarm);
// Rearrange items immediately.
mReorderAlarmListener.onAlarm(mReorderAlarm);
mOnScrollHintAlarm.cancelAlarm();
mScrollPauseAlarm.cancelAlarm();
}
mPagedView.completePendingPageChanges();
mOnScrollHintAlarm.cancelAlarm();
mScrollPauseAlarm.cancelAlarm();
}
mContent.completePendingPageChanges();
View currentDragView;
ShortcutInfo si = mCurrentDragInfo;
@@ -1252,10 +1229,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
@Override
public void onAlarm(Alarm alarm) {
if (mCurrentScrollDir == DragController.SCROLL_LEFT) {
mPagedView.scrollLeft();
mContent.scrollLeft();
mScrollHintDir = DragController.SCROLL_NONE;
} else if (mCurrentScrollDir == DragController.SCROLL_RIGHT) {
mPagedView.scrollRight();
mContent.scrollRight();
mScrollHintDir = DragController.SCROLL_NONE;
} else {
// This should not happen
@@ -1286,69 +1263,4 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
onDragOver(mDragObject, 1);
}
}
public static interface FolderContent {
void setFolder(Folder f);
void removeItem(View v);
boolean isFull();
int getItemCount();
int getDesiredWidth();
int getDesiredHeight();
void setFixedSize(int width, int height);
/**
* Iterates over all its items in a reading order.
* @return the view for which the operator returned true.
*/
View iterateOverItems(ItemOperator op);
View getLastItem();
String getAccessibilityDescription();
/**
* Binds items to the layout.
* @return list of items that could not be bound, probably because we hit the max size limit.
*/
ArrayList<ShortcutInfo> bindItems(ArrayList<ShortcutInfo> children);
/**
* Create space for a new item, and returns the rank for that item.
* Resizes the content if necessary.
*/
int allocateRankForNewItem(ShortcutInfo info);
View createAndAddViewForRank(ShortcutInfo item, int rank);
/**
* Adds the {@param view} to the layout based on {@param rank} and updated the position
* related attributes. It assumes that {@param item} is already attached to the view.
*/
void addViewForRank(View view, ShortcutInfo item, int rank);
/**
* Reorders the items such that the {@param empty} spot moves to {@param target}
*/
void realTimeReorder(int empty, int target);
/**
* @return the rank of the cell nearest to the provided pixel position.
*/
int findNearestArea(int pixelX, int pixelY);
/**
* Updates position and rank of all the children in the view based.
* @param list the ordered list of children.
* @param itemCount if greater than the total children count, empty spaces are left
* at the end.
*/
void arrangeChildren(ArrayList<View> list, int itemCount);
/**
* Sets the focus on the first visible child.
*/
void setFocusOnFirstChild();
}
}
@@ -1,330 +0,0 @@
/**
* Copyright (C) 2015 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.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import com.android.launcher3.Workspace.ItemOperator;
import java.util.ArrayList;
public class FolderCellLayout extends CellLayout implements Folder.FolderContent {
private static final int REORDER_ANIMATION_DURATION = 230;
private static final int START_VIEW_REORDER_DELAY = 30;
private static final float VIEW_REORDER_DELAY_FACTOR = 0.9f;
private static final int[] sTempPosArray = new int[2];
private final FolderKeyEventListener mKeyListener = new FolderKeyEventListener();
private final LayoutInflater mInflater;
private final IconCache mIconCache;
private final int mMaxCountX;
private final int mMaxCountY;
private final int mMaxNumItems;
// Indicates the last number of items used to set up the grid size
private int mAllocatedContentSize;
private Folder mFolder;
private FocusIndicatorView mFocusIndicatorView;
public FolderCellLayout(Context context) {
this(context, null);
}
public FolderCellLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FolderCellLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
mMaxCountX = (int) grid.numColumns;
mMaxCountY = (int) grid.numRows;
mMaxNumItems = mMaxCountX * mMaxCountY;
mInflater = LayoutInflater.from(context);
mIconCache = app.getIconCache();
setCellDimensions(grid.folderCellWidthPx, grid.folderCellHeightPx);
getShortcutsAndWidgets().setMotionEventSplittingEnabled(false);
setInvertIfRtl(true);
}
@Override
public void setFolder(Folder folder) {
mFolder = folder;
mFocusIndicatorView = (FocusIndicatorView) folder.findViewById(R.id.focus_indicator);
}
/**
* Sets up the grid size such that {@param count} items can fit in the grid.
* The grid size is calculated such that countY <= countX and countX = ceil(sqrt(count)) while
* maintaining the restrictions of {@link #mMaxCountX} &amp; {@link #mMaxCountY}.
*/
private void setupContentDimensions(int count) {
mAllocatedContentSize = count;
int countX = getCountX();
int countY = getCountY();
boolean done = false;
while (!done) {
int oldCountX = countX;
int oldCountY = countY;
if (countX * countY < count) {
// Current grid is too small, expand it
if ((countX <= countY || countY == mMaxCountY) && countX < mMaxCountX) {
countX++;
} else if (countY < mMaxCountY) {
countY++;
}
if (countY == 0) countY++;
} else if ((countY - 1) * countX >= count && countY >= countX) {
countY = Math.max(0, countY - 1);
} else if ((countX - 1) * countY >= count) {
countX = Math.max(0, countX - 1);
}
done = countX == oldCountX && countY == oldCountY;
}
setGridSize(countX, countY);
}
@Override
public ArrayList<ShortcutInfo> bindItems(ArrayList<ShortcutInfo> items) {
ArrayList<ShortcutInfo> extra = new ArrayList<ShortcutInfo>();
setupContentDimensions(Math.min(items.size(), mMaxNumItems));
int countX = getCountX();
int rank = 0;
for (ShortcutInfo item : items) {
if (rank >= mMaxNumItems) {
extra.add(item);
continue;
}
item.rank = rank;
item.cellX = rank % countX;
item.cellY = rank / countX;
addNewView(item);
rank++;
}
return extra;
}
@Override
public int allocateRankForNewItem(ShortcutInfo info) {
int rank = getItemCount();
mFolder.rearrangeChildren(rank + 1);
return rank;
}
@Override
public View createAndAddViewForRank(ShortcutInfo item, int rank) {
updateItemXY(item, rank);
return addNewView(item);
}
@Override
public void addViewForRank(View view, ShortcutInfo item, int rank) {
updateItemXY(item, rank);
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
lp.cellX = item.cellX;
lp.cellY = item.cellY;
addViewToCellLayout(view, -1, mFolder.mLauncher.getViewIdForItem(item), lp, true);
}
@Override
public void removeItem(View v) {
removeView(v);
}
/**
* Updates the item cellX and cellY position
*/
private void updateItemXY(ShortcutInfo item, int rank) {
item.rank = rank;
int countX = getCountX();
item.cellX = rank % countX;
item.cellY = rank / countX;
}
private View addNewView(ShortcutInfo item) {
final BubbleTextView textView = (BubbleTextView) mInflater.inflate(
R.layout.folder_application, getShortcutsAndWidgets(), false);
textView.applyFromShortcutInfo(item, mIconCache, false);
textView.setOnClickListener(mFolder);
textView.setOnLongClickListener(mFolder);
textView.setOnFocusChangeListener(mFocusIndicatorView);
textView.setOnKeyListener(mKeyListener);
CellLayout.LayoutParams lp = new CellLayout.LayoutParams(
item.cellX, item.cellY, item.spanX, item.spanY);
addViewToCellLayout(textView, -1, mFolder.mLauncher.getViewIdForItem(item), lp, true);
return textView;
}
/**
* Refer {@link #findNearestArea(int, int, int, int, View, boolean, int[])}
*/
@Override
public int findNearestArea(int pixelX, int pixelY) {
findNearestArea(pixelX, pixelY, 1, 1, null, false, sTempPosArray);
if (mFolder.isLayoutRtl()) {
sTempPosArray[0] = getCountX() - sTempPosArray[0] - 1;
}
// Convert this position to rank.
return Math.min(mAllocatedContentSize - 1,
sTempPosArray[1] * getCountX() + sTempPosArray[0]);
}
@Override
public boolean isFull() {
return getItemCount() >= mMaxNumItems;
}
@Override
public int getItemCount() {
return getShortcutsAndWidgets().getChildCount();
}
@Override
public void arrangeChildren(ArrayList<View> list, int itemCount) {
setupContentDimensions(itemCount);
removeAllViews();
int newX, newY;
int rank = 0;
int countX = getCountX();
for (View v : list) {
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
newX = rank % countX;
newY = rank / countX;
ItemInfo info = (ItemInfo) v.getTag();
if (info.cellX != newX || info.cellY != newY || info.rank != rank) {
info.cellX = newX;
info.cellY = newY;
info.rank = rank;
LauncherModel.addOrMoveItemInDatabase(getContext(), info,
mFolder.mInfo.id, 0, info.cellX, info.cellY);
}
lp.cellX = info.cellX;
lp.cellY = info.cellY;
rank ++;
addViewToCellLayout(v, -1, mFolder.mLauncher.getViewIdForItem(info), lp, true);
}
}
@Override
public View iterateOverItems(ItemOperator op) {
for (int j = 0; j < getCountY(); j++) {
for (int i = 0; i < getCountX(); i++) {
View v = getChildAt(i, j);
if ((v != null) && op.evaluate((ItemInfo) v.getTag(), v, this)) {
return v;
}
}
}
return null;
}
@Override
public String getAccessibilityDescription() {
return String.format(getContext().getString(R.string.folder_opened),
getCountX(), getCountY());
}
@Override
public void setFocusOnFirstChild() {
View firstChild = getChildAt(0, 0);
if (firstChild != null) {
firstChild.requestFocus();
}
}
@Override
public View getLastItem() {
int lastRank = getShortcutsAndWidgets().getChildCount() - 1;
// count can be zero if the folder is not yet laid out.
int count = getCountX();
if (count > 0) {
return getShortcutsAndWidgets().getChildAt(lastRank % count, lastRank / count);
} else {
return getShortcutsAndWidgets().getChildAt(lastRank);
}
}
@Override
public void realTimeReorder(int empty, int target) {
boolean wrap;
int startX;
int endX;
int startY;
int delay = 0;
float delayAmount = START_VIEW_REORDER_DELAY;
int countX = getCountX();
int emptyX = empty % getCountX();
int emptyY = empty / countX;
int targetX = target % countX;
int targetY = target / countX;
if (target > empty) {
wrap = emptyX == countX - 1;
startY = wrap ? emptyY + 1 : emptyY;
for (int y = startY; y <= targetY; y++) {
startX = y == emptyY ? emptyX + 1 : 0;
endX = y < targetY ? countX - 1 : targetX;
for (int x = startX; x <= endX; x++) {
View v = getChildAt(x,y);
if (animateChildToPosition(v, emptyX, emptyY,
REORDER_ANIMATION_DURATION, delay, true, true)) {
emptyX = x;
emptyY = y;
delay += delayAmount;
delayAmount *= VIEW_REORDER_DELAY_FACTOR;
}
}
}
} else {
wrap = emptyX == 0;
startY = wrap ? emptyY - 1 : emptyY;
for (int y = startY; y >= targetY; y--) {
startX = y == emptyY ? emptyX - 1 : countX - 1;
endX = y > targetY ? 0 : targetX;
for (int x = startX; x >= endX; x--) {
View v = getChildAt(x,y);
if (animateChildToPosition(v, emptyX, emptyY,
REORDER_ANIMATION_DURATION, delay, true, true)) {
emptyX = x;
emptyY = y;
delay += delayAmount;
delayAmount *= VIEW_REORDER_DELAY_FACTOR;
}
}
}
}
}
}
+81 -50
View File
@@ -19,7 +19,6 @@ package com.android.launcher3;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.util.LayoutDirection;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -42,10 +41,15 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class FolderPagedView extends PagedView implements Folder.FolderContent {
public class FolderPagedView extends PagedView {
private static final String TAG = "FolderPagedView";
private static final boolean ALLOW_FOLDER_SCROLL = true;
// To enable this flag, user_folder.xml needs to be modified to add sort button.
private static final boolean ALLOW_ITEM_SORTING = false;
private static final int REORDER_ANIMATION_DURATION = 230;
private static final int START_VIEW_REORDER_DELAY = 30;
private static final float VIEW_REORDER_DELAY_FACTOR = 0.9f;
@@ -96,32 +100,38 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent {
setDataIsReady();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
mMaxCountX = Math.min((int) grid.numColumns, MAX_ITEMS_PER_PAGE);
mMaxCountY = Math.min((int) grid.numRows, MAX_ITEMS_PER_PAGE);
if (ALLOW_FOLDER_SCROLL) {
mMaxCountX = Math.min((int) grid.numColumns, MAX_ITEMS_PER_PAGE);
mMaxCountY = Math.min((int) grid.numRows, MAX_ITEMS_PER_PAGE);
} else {
mMaxCountX = (int) grid.numColumns;
mMaxCountY = (int) grid.numRows;
}
mMaxItemsPerPage = mMaxCountX * mMaxCountY;
mInflater = LayoutInflater.from(context);
mIconCache = app.getIconCache();
rtlLayout = getResources().getConfiguration().getLayoutDirection() == LayoutDirection.RTL;
rtlLayout = getResources().getConfiguration().getLayoutDirection() == LAYOUT_DIRECTION_RTL;
}
@Override
public void setFolder(Folder folder) {
mFolder = folder;
mFocusIndicatorView = (FocusIndicatorView) folder.findViewById(R.id.focus_indicator);
mKeyListener = new PagedFolderKeyEventListener(folder);
mSortButton = folder.findViewById(R.id.folder_sort);
mSortButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onSortClicked();
}
});
mPageIndicator = folder.findViewById(R.id.folder_page_indicator);
mSortSwitch = (Switch) folder.findViewById(R.id.folder_sort_switch);
if (ALLOW_ITEM_SORTING) {
// Initialize {@link #mSortSwitch} and {@link #mSortButton}.
mSortButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onSortClicked();
}
});
}
}
private void onSortClicked() {
@@ -138,9 +148,11 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent {
private void setIsSorted(boolean isSorted, boolean saveChanges) {
mIsSorted = isSorted;
mSortSwitch.setChecked(isSorted);
mFolder.mInfo.setOption(FolderInfo.FLAG_ITEMS_SORTED, isSorted,
saveChanges ? mFolder.mLauncher : null);
if (ALLOW_ITEM_SORTING) {
mSortSwitch.setChecked(isSorted);
mFolder.mInfo.setOption(FolderInfo.FLAG_ITEMS_SORTED, isSorted,
saveChanges ? mFolder.mLauncher : null);
}
}
/**
@@ -282,26 +294,34 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent {
}
}
@Override
/**
* Binds items to the layout.
* @return list of items that could not be bound, probably because we hit the max size limit.
*/
public ArrayList<ShortcutInfo> bindItems(ArrayList<ShortcutInfo> items) {
mIsSorted = mFolder.mInfo.hasOption(FolderInfo.FLAG_ITEMS_SORTED);
mIsSorted = ALLOW_ITEM_SORTING && mFolder.mInfo.hasOption(FolderInfo.FLAG_ITEMS_SORTED);
ArrayList<View> icons = new ArrayList<View>();
ArrayList<ShortcutInfo> extra = new ArrayList<ShortcutInfo>();
for (ShortcutInfo item : items) {
icons.add(createNewView(item));
if (!ALLOW_FOLDER_SCROLL && icons.size() >= mMaxItemsPerPage) {
extra.add(item);
} else {
icons.add(createNewView(item));
}
}
arrangeChildren(icons, icons.size(), false);
return new ArrayList<ShortcutInfo>();
return extra;
}
/**
* Create space for a new item at the end, and returns the rank for that item.
* Also sets the current page to the last page.
*/
@Override
public int allocateRankForNewItem(ShortcutInfo info) {
int rank = getItemCount();
ArrayList<View> views = new ArrayList<View>(mFolder.getItemsInReadingOrder());
if (mIsSorted) {
if (ALLOW_ITEM_SORTING && mIsSorted) {
View tmp = new View(getContext());
tmp.setTag(info);
int index = Collections.binarySearch(views, tmp, new ViewComparator());
@@ -321,14 +341,16 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent {
return rank;
}
@Override
public View createAndAddViewForRank(ShortcutInfo item, int rank) {
View icon = createNewView(item);
addViewForRank(icon, item, rank);
return icon;
}
@Override
/**
* Adds the {@param view} to the layout based on {@param rank} and updated the position
* related attributes. It assumes that {@param item} is already attached to the view.
*/
public void addViewForRank(View view, ShortcutInfo item, int rank) {
int pagePos = rank % mMaxItemsPerPage;
int pageNo = rank / mMaxItemsPerPage;
@@ -388,14 +410,12 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent {
return page;
}
@Override
public void setFixedSize(int width, int height) {
for (int i = getChildCount() - 1; i >= 0; i --) {
((CellLayout) getChildAt(i)).setFixedSize(width, height);
}
}
@Override
public void removeItem(View v) {
for (int i = getChildCount() - 1; i >= 0; i --) {
getPageAt(i).removeView(v);
@@ -412,7 +432,6 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent {
* at the end, otherwise it is ignored.
*
*/
@Override
public void arrangeChildren(ArrayList<View> list, int itemCount) {
arrangeChildren(list, itemCount, true);
}
@@ -488,19 +507,26 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent {
setCurrentPage(0);
}
setIsSorted(isSorted, saveChanges);
setEnableOverscroll(getPageCount() > 1);
// Update footer
if (getPageCount() > 1) {
mPageIndicator.setVisibility(View.VISIBLE);
mSortButton.setVisibility(View.VISIBLE);
mFolder.mFolderName.setGravity(rtlLayout ? Gravity.RIGHT : Gravity.LEFT);
setEnableOverscroll(true);
if (ALLOW_ITEM_SORTING) {
setIsSorted(isSorted, saveChanges);
if (getPageCount() > 1) {
mPageIndicator.setVisibility(View.VISIBLE);
mSortButton.setVisibility(View.VISIBLE);
mFolder.mFolderName.setGravity(rtlLayout ? Gravity.RIGHT : Gravity.LEFT);
} else {
mPageIndicator.setVisibility(View.GONE);
mSortButton.setVisibility(View.GONE);
mFolder.mFolderName.setGravity(Gravity.CENTER_HORIZONTAL);
}
} else {
mPageIndicator.setVisibility(View.GONE);
mSortButton.setVisibility(View.GONE);
mFolder.mFolderName.setGravity(Gravity.CENTER_HORIZONTAL);
setEnableOverscroll(false);
int indicatorVisibility = mPageIndicator.getVisibility();
mPageIndicator.setVisibility(getPageCount() > 1 ? View.VISIBLE : View.GONE);
if (indicatorVisibility != mPageIndicator.getVisibility()) {
mFolder.updateFooterHeight();
}
}
}
@@ -521,7 +547,6 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent {
return getPageCount() > 0 ? getPageAt(0).getDesiredHeight() : 0;
}
@Override
public int getItemCount() {
int lastPageIndex = getChildCount() - 1;
if (lastPageIndex < 0) {
@@ -532,7 +557,9 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent {
+ lastPageIndex * mMaxItemsPerPage;
}
@Override
/**
* @return the rank of the cell nearest to the provided pixel position.
*/
public int findNearestArea(int pixelX, int pixelY) {
int pageIndex = getNextPage();
CellLayout page = getPageAt(pageIndex);
@@ -550,12 +577,10 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent {
R.drawable.ic_pageindicator_default_folder);
}
@Override
public boolean isFull() {
return false;
return !ALLOW_FOLDER_SCROLL && getItemCount() >= mMaxItemsPerPage;
}
@Override
public View getLastItem() {
if (getChildCount() < 1) {
return null;
@@ -569,7 +594,10 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent {
}
}
@Override
/**
* Iterates over all its items in a reading order.
* @return the view for which the operator returned true.
*/
public View iterateOverItems(ItemOperator op) {
for (int k = 0 ; k < getChildCount(); k++) {
CellLayout page = getPageAt(k);
@@ -585,13 +613,14 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent {
return null;
}
@Override
public String getAccessibilityDescription() {
return String.format(getContext().getString(R.string.folder_opened),
mGridCountX, mGridCountY);
}
@Override
/**
* Sets the focus on the first visible child.
*/
public void setFocusOnFirstChild() {
View firstChild = getCurrentCellLayout().getChildAt(0, 0);
if (firstChild != null) {
@@ -605,7 +634,7 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent {
if (mFolder != null) {
mFolder.updateTextViewFocus();
}
if (mSortOperationPending && getNextPage() == 0) {
if (ALLOW_ITEM_SORTING && mSortOperationPending && getNextPage() == 0) {
post(new Runnable() {
@Override
@@ -680,7 +709,9 @@ public class FolderPagedView extends PagedView implements Folder.FolderContent {
}
}
@Override
/**
* Reorders the items such that the {@param empty} spot moves to {@param target}
*/
public void realTimeReorder(int empty, int target) {
completePendingPageChanges();
int delay = 0;