mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-20 19:38:21 +00:00
- Tweaking the widget page to make it a little tighter - Altering the way we generate widget previews to make them more consistent - Making the Apps page two line titles Change-Id: I7bce420466c1d41fb87b423f259472482803a406
518 lines
17 KiB
Java
518 lines
17 KiB
Java
/*
|
|
* Copyright (C) 2010 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.launcher2;
|
|
|
|
import android.content.Context;
|
|
import android.content.res.Resources;
|
|
import android.util.AttributeSet;
|
|
import android.util.Log;
|
|
import android.view.MotionEvent;
|
|
import android.view.View;
|
|
import android.view.ViewDebug;
|
|
import android.view.ViewGroup;
|
|
|
|
import com.android.launcher.R;
|
|
|
|
/**
|
|
* An abstraction of the original CellLayout which supports laying out items
|
|
* which span multiple cells into a grid-like layout. Also supports dimming
|
|
* to give a preview of its contents.
|
|
*/
|
|
public class PagedViewCellLayout extends ViewGroup implements Page {
|
|
static final String TAG = "PagedViewCellLayout";
|
|
|
|
private int mCellCountX;
|
|
private int mCellCountY;
|
|
private int mOriginalCellWidth;
|
|
private int mOriginalCellHeight;
|
|
private int mCellWidth;
|
|
private int mCellHeight;
|
|
private int mOriginalWidthGap;
|
|
private int mOriginalHeightGap;
|
|
private int mWidthGap;
|
|
private int mHeightGap;
|
|
private int mMaxGap;
|
|
protected PagedViewCellLayoutChildren mChildren;
|
|
|
|
public PagedViewCellLayout(Context context) {
|
|
this(context, null);
|
|
}
|
|
|
|
public PagedViewCellLayout(Context context, AttributeSet attrs) {
|
|
this(context, attrs, 0);
|
|
}
|
|
|
|
public PagedViewCellLayout(Context context, AttributeSet attrs, int defStyle) {
|
|
super(context, attrs, defStyle);
|
|
|
|
setAlwaysDrawnWithCacheEnabled(false);
|
|
|
|
// setup default cell parameters
|
|
Resources resources = context.getResources();
|
|
mOriginalCellWidth = mCellWidth =
|
|
resources.getDimensionPixelSize(R.dimen.apps_customize_cell_width);
|
|
mOriginalCellHeight = mCellHeight =
|
|
resources.getDimensionPixelSize(R.dimen.apps_customize_cell_height);
|
|
mCellCountX = LauncherModel.getCellCountX();
|
|
mCellCountY = LauncherModel.getCellCountY();
|
|
mOriginalHeightGap = mOriginalHeightGap = mWidthGap = mHeightGap = -1;
|
|
mMaxGap = resources.getDimensionPixelSize(R.dimen.apps_customize_max_gap);
|
|
|
|
mChildren = new PagedViewCellLayoutChildren(context);
|
|
mChildren.setCellDimensions(mCellWidth, mCellHeight);
|
|
mChildren.setGap(mWidthGap, mHeightGap);
|
|
|
|
addView(mChildren);
|
|
}
|
|
|
|
public int getCellWidth() {
|
|
return mCellWidth;
|
|
}
|
|
|
|
public int getCellHeight() {
|
|
return mCellHeight;
|
|
}
|
|
|
|
@Override
|
|
public void setAlpha(float alpha) {
|
|
mChildren.setAlpha(alpha);
|
|
}
|
|
|
|
void destroyHardwareLayers() {
|
|
// called when a page is no longer visible (triggered by loadAssociatedPages ->
|
|
// removeAllViewsOnPage)
|
|
mChildren.destroyHardwareLayer();
|
|
}
|
|
|
|
void createHardwareLayers() {
|
|
// called when a page is visible (triggered by loadAssociatedPages -> syncPageItems)
|
|
mChildren.createHardwareLayer();
|
|
}
|
|
|
|
@Override
|
|
public void cancelLongPress() {
|
|
super.cancelLongPress();
|
|
|
|
// Cancel long press for all children
|
|
final int count = getChildCount();
|
|
for (int i = 0; i < count; i++) {
|
|
final View child = getChildAt(i);
|
|
child.cancelLongPress();
|
|
}
|
|
}
|
|
|
|
public boolean addViewToCellLayout(View child, int index, int childId,
|
|
PagedViewCellLayout.LayoutParams params) {
|
|
final PagedViewCellLayout.LayoutParams lp = params;
|
|
|
|
// Generate an id for each view, this assumes we have at most 256x256 cells
|
|
// per workspace screen
|
|
if (lp.cellX >= 0 && lp.cellX <= (mCellCountX - 1) &&
|
|
lp.cellY >= 0 && (lp.cellY <= mCellCountY - 1)) {
|
|
// If the horizontal or vertical span is set to -1, it is taken to
|
|
// mean that it spans the extent of the CellLayout
|
|
if (lp.cellHSpan < 0) lp.cellHSpan = mCellCountX;
|
|
if (lp.cellVSpan < 0) lp.cellVSpan = mCellCountY;
|
|
|
|
child.setId(childId);
|
|
mChildren.addView(child, index, lp);
|
|
|
|
if (child instanceof PagedViewIcon) {
|
|
PagedViewIcon pagedViewIcon = (PagedViewIcon) child;
|
|
pagedViewIcon.disableCache();
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void removeAllViewsOnPage() {
|
|
mChildren.removeAllViews();
|
|
destroyHardwareLayers();
|
|
}
|
|
|
|
@Override
|
|
public void removeViewOnPageAt(int index) {
|
|
mChildren.removeViewAt(index);
|
|
}
|
|
|
|
@Override
|
|
public int getPageChildCount() {
|
|
return mChildren.getChildCount();
|
|
}
|
|
|
|
public PagedViewCellLayoutChildren getChildrenLayout() {
|
|
return mChildren;
|
|
}
|
|
|
|
@Override
|
|
public View getChildOnPageAt(int i) {
|
|
return mChildren.getChildAt(i);
|
|
}
|
|
|
|
@Override
|
|
public int indexOfChildOnPage(View v) {
|
|
return mChildren.indexOfChild(v);
|
|
}
|
|
|
|
public int getCellCountX() {
|
|
return mCellCountX;
|
|
}
|
|
|
|
public int getCellCountY() {
|
|
return mCellCountY;
|
|
}
|
|
|
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
|
|
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
|
|
|
|
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
|
|
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
|
|
|
|
if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
|
|
throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
|
|
}
|
|
|
|
int numWidthGaps = mCellCountX - 1;
|
|
int numHeightGaps = mCellCountY - 1;
|
|
|
|
if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) {
|
|
int hSpace = widthSpecSize - mPaddingLeft - mPaddingRight;
|
|
int vSpace = heightSpecSize - mPaddingTop - mPaddingBottom;
|
|
int hFreeSpace = hSpace - (mCellCountX * mOriginalCellWidth);
|
|
int vFreeSpace = vSpace - (mCellCountY * mOriginalCellHeight);
|
|
mWidthGap = Math.min(mMaxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0);
|
|
mHeightGap = Math.min(mMaxGap,numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0);
|
|
|
|
mChildren.setGap(mWidthGap, mHeightGap);
|
|
} else {
|
|
mWidthGap = mOriginalWidthGap;
|
|
mHeightGap = mOriginalHeightGap;
|
|
}
|
|
|
|
// Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY
|
|
int newWidth = widthSpecSize;
|
|
int newHeight = heightSpecSize;
|
|
if (widthSpecMode == MeasureSpec.AT_MOST) {
|
|
newWidth = mPaddingLeft + mPaddingRight + (mCellCountX * mCellWidth) +
|
|
((mCellCountX - 1) * mWidthGap);
|
|
newHeight = mPaddingTop + mPaddingBottom + (mCellCountY * mCellHeight) +
|
|
((mCellCountY - 1) * mHeightGap);
|
|
setMeasuredDimension(newWidth, newHeight);
|
|
}
|
|
|
|
final int count = getChildCount();
|
|
for (int i = 0; i < count; i++) {
|
|
View child = getChildAt(i);
|
|
int childWidthMeasureSpec =
|
|
MeasureSpec.makeMeasureSpec(newWidth - mPaddingLeft -
|
|
mPaddingRight, MeasureSpec.EXACTLY);
|
|
int childheightMeasureSpec =
|
|
MeasureSpec.makeMeasureSpec(newHeight - mPaddingTop -
|
|
mPaddingBottom, MeasureSpec.EXACTLY);
|
|
child.measure(childWidthMeasureSpec, childheightMeasureSpec);
|
|
}
|
|
|
|
setMeasuredDimension(newWidth, newHeight);
|
|
}
|
|
|
|
int getContentWidth() {
|
|
return getWidthBeforeFirstLayout() + mPaddingLeft + mPaddingRight;
|
|
}
|
|
|
|
int getContentHeight() {
|
|
if (mCellCountY > 0) {
|
|
return mCellCountY * mCellHeight + (mCellCountY - 1) * Math.max(0, mHeightGap);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int getWidthBeforeFirstLayout() {
|
|
if (mCellCountX > 0) {
|
|
return mCellCountX * mCellWidth + (mCellCountX - 1) * Math.max(0, mWidthGap);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
|
int count = getChildCount();
|
|
for (int i = 0; i < count; i++) {
|
|
View child = getChildAt(i);
|
|
child.layout(mPaddingLeft, mPaddingTop,
|
|
r - l - mPaddingRight, b - t - mPaddingBottom);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean onTouchEvent(MotionEvent event) {
|
|
boolean result = super.onTouchEvent(event);
|
|
int count = getPageChildCount();
|
|
if (count > 0) {
|
|
// We only intercept the touch if we are tapping in empty space after the final row
|
|
View child = getChildOnPageAt(count - 1);
|
|
int bottom = child.getBottom();
|
|
int numRows = (int) Math.ceil((float) getPageChildCount() / getCellCountX());
|
|
if (numRows < getCellCountY()) {
|
|
// Add a little bit of buffer if there is room for another row
|
|
bottom += mCellHeight / 2;
|
|
}
|
|
result = result || (event.getY() < bottom);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public void enableCenteredContent(boolean enabled) {
|
|
mChildren.enableCenteredContent(enabled);
|
|
}
|
|
|
|
@Override
|
|
protected void setChildrenDrawingCacheEnabled(boolean enabled) {
|
|
mChildren.setChildrenDrawingCacheEnabled(enabled);
|
|
}
|
|
|
|
public void setCellCount(int xCount, int yCount) {
|
|
mCellCountX = xCount;
|
|
mCellCountY = yCount;
|
|
requestLayout();
|
|
}
|
|
|
|
public void setGap(int widthGap, int heightGap) {
|
|
mWidthGap = widthGap;
|
|
mHeightGap = heightGap;
|
|
mChildren.setGap(widthGap, heightGap);
|
|
}
|
|
|
|
public int[] getCellCountForDimensions(int width, int height) {
|
|
// Always assume we're working with the smallest span to make sure we
|
|
// reserve enough space in both orientations
|
|
int smallerSize = Math.min(mCellWidth, mCellHeight);
|
|
|
|
// Always round up to next largest cell
|
|
int spanX = (width + smallerSize) / smallerSize;
|
|
int spanY = (height + smallerSize) / smallerSize;
|
|
|
|
return new int[] { spanX, spanY };
|
|
}
|
|
|
|
/**
|
|
* Start dragging the specified child
|
|
*
|
|
* @param child The child that is being dragged
|
|
*/
|
|
void onDragChild(View child) {
|
|
PagedViewCellLayout.LayoutParams lp = (PagedViewCellLayout.LayoutParams) child.getLayoutParams();
|
|
lp.isDragging = true;
|
|
}
|
|
|
|
/**
|
|
* Estimates the number of cells that the specified width would take up.
|
|
*/
|
|
public int estimateCellHSpan(int width) {
|
|
// The space for a page assuming that we want to show half of a column of the previous and
|
|
// next pages is the width - left padding (current & next page) - right padding (previous &
|
|
// current page) - half cell width (for previous and next pages)
|
|
int availWidth = (int) (width - (2 * mPaddingLeft + 2 * mPaddingRight));
|
|
|
|
// We know that we have to fit N cells with N-1 width gaps, so we just juggle to solve for N
|
|
int n = Math.max(1, (availWidth + mWidthGap) / (mCellWidth + mWidthGap));
|
|
|
|
// We don't do anything fancy to determine if we squeeze another row in.
|
|
return n;
|
|
}
|
|
|
|
/**
|
|
* Estimates the number of cells that the specified height would take up.
|
|
*/
|
|
public int estimateCellVSpan(int height) {
|
|
// The space for a page is the height - top padding (current page) - bottom padding (current
|
|
// page)
|
|
int availHeight = height - (mPaddingTop + mPaddingBottom);
|
|
|
|
// We know that we have to fit N cells with N-1 height gaps, so we juggle to solve for N
|
|
int n = Math.max(1, (availHeight + mHeightGap) / (mCellHeight + mHeightGap));
|
|
|
|
// We don't do anything fancy to determine if we squeeze another row in.
|
|
return n;
|
|
}
|
|
|
|
/** Returns an estimated center position of the cell at the specified index */
|
|
public int[] estimateCellPosition(int x, int y) {
|
|
return new int[] {
|
|
mPaddingLeft + (x * mCellWidth) + (x * mWidthGap) + (mCellWidth / 2),
|
|
mPaddingTop + (y * mCellHeight) + (y * mHeightGap) + (mCellHeight / 2)
|
|
};
|
|
}
|
|
|
|
public void calculateCellCount(int width, int height, int maxCellCountX, int maxCellCountY) {
|
|
mCellCountX = Math.min(maxCellCountX, estimateCellHSpan(width));
|
|
mCellCountY = Math.min(maxCellCountY, estimateCellVSpan(height));
|
|
requestLayout();
|
|
}
|
|
|
|
/**
|
|
* Estimates the width that the number of hSpan cells will take up.
|
|
*/
|
|
public int estimateCellWidth(int hSpan) {
|
|
// TODO: we need to take widthGap into effect
|
|
return hSpan * mCellWidth;
|
|
}
|
|
|
|
/**
|
|
* Estimates the height that the number of vSpan cells will take up.
|
|
*/
|
|
public int estimateCellHeight(int vSpan) {
|
|
// TODO: we need to take heightGap into effect
|
|
return vSpan * mCellHeight;
|
|
}
|
|
|
|
@Override
|
|
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
|
|
return new PagedViewCellLayout.LayoutParams(getContext(), attrs);
|
|
}
|
|
|
|
@Override
|
|
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
|
|
return p instanceof PagedViewCellLayout.LayoutParams;
|
|
}
|
|
|
|
@Override
|
|
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
|
|
return new PagedViewCellLayout.LayoutParams(p);
|
|
}
|
|
|
|
public static class LayoutParams extends ViewGroup.MarginLayoutParams {
|
|
/**
|
|
* Horizontal location of the item in the grid.
|
|
*/
|
|
@ViewDebug.ExportedProperty
|
|
public int cellX;
|
|
|
|
/**
|
|
* Vertical location of the item in the grid.
|
|
*/
|
|
@ViewDebug.ExportedProperty
|
|
public int cellY;
|
|
|
|
/**
|
|
* Number of cells spanned horizontally by the item.
|
|
*/
|
|
@ViewDebug.ExportedProperty
|
|
public int cellHSpan;
|
|
|
|
/**
|
|
* Number of cells spanned vertically by the item.
|
|
*/
|
|
@ViewDebug.ExportedProperty
|
|
public int cellVSpan;
|
|
|
|
/**
|
|
* Is this item currently being dragged
|
|
*/
|
|
public boolean isDragging;
|
|
|
|
// a data object that you can bind to this layout params
|
|
private Object mTag;
|
|
|
|
// X coordinate of the view in the layout.
|
|
@ViewDebug.ExportedProperty
|
|
int x;
|
|
// Y coordinate of the view in the layout.
|
|
@ViewDebug.ExportedProperty
|
|
int y;
|
|
|
|
public LayoutParams() {
|
|
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
|
|
cellHSpan = 1;
|
|
cellVSpan = 1;
|
|
}
|
|
|
|
public LayoutParams(Context c, AttributeSet attrs) {
|
|
super(c, attrs);
|
|
cellHSpan = 1;
|
|
cellVSpan = 1;
|
|
}
|
|
|
|
public LayoutParams(ViewGroup.LayoutParams source) {
|
|
super(source);
|
|
cellHSpan = 1;
|
|
cellVSpan = 1;
|
|
}
|
|
|
|
public LayoutParams(LayoutParams source) {
|
|
super(source);
|
|
this.cellX = source.cellX;
|
|
this.cellY = source.cellY;
|
|
this.cellHSpan = source.cellHSpan;
|
|
this.cellVSpan = source.cellVSpan;
|
|
}
|
|
|
|
public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
|
|
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
|
|
this.cellX = cellX;
|
|
this.cellY = cellY;
|
|
this.cellHSpan = cellHSpan;
|
|
this.cellVSpan = cellVSpan;
|
|
}
|
|
|
|
public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap,
|
|
int hStartPadding, int vStartPadding) {
|
|
|
|
final int myCellHSpan = cellHSpan;
|
|
final int myCellVSpan = cellVSpan;
|
|
final int myCellX = cellX;
|
|
final int myCellY = cellY;
|
|
|
|
width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
|
|
leftMargin - rightMargin;
|
|
height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
|
|
topMargin - bottomMargin;
|
|
|
|
if (LauncherApplication.isScreenLarge()) {
|
|
x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
|
|
y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
|
|
} else {
|
|
x = myCellX * (cellWidth + widthGap) + leftMargin;
|
|
y = myCellY * (cellHeight + heightGap) + topMargin;
|
|
}
|
|
}
|
|
|
|
public Object getTag() {
|
|
return mTag;
|
|
}
|
|
|
|
public void setTag(Object tag) {
|
|
mTag = tag;
|
|
}
|
|
|
|
public String toString() {
|
|
return "(" + this.cellX + ", " + this.cellY + ", " +
|
|
this.cellHSpan + ", " + this.cellVSpan + ")";
|
|
}
|
|
}
|
|
}
|
|
|
|
interface Page {
|
|
public int getPageChildCount();
|
|
public View getChildOnPageAt(int i);
|
|
public void removeAllViewsOnPage();
|
|
public void removeViewOnPageAt(int i);
|
|
public int indexOfChildOnPage(View v);
|
|
}
|