blob: e4eb6a1b4d9fb59a269d1b2e87dc646cd4ee66b5 [file] [log] [blame]
/*
* Copyright (C) 2007 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.example.android.home;
import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.LayoutInflater;
import android.widget.TextView;
import java.util.List;
/**
* The ApplicationsStackLayout is a specialized layout used for the purpose of the home screen
* only. This layout stacks various icons in three distinct areas: the recents, the favorites
* (or faves) and the button.
*
* This layout supports two different orientations: vertical and horizontal. When horizontal,
* the areas are laid out this way:
*
* [RECENTS][FAVES][BUTTON]
*
* When vertical, the layout is the following:
*
* [RECENTS]
* [FAVES]
* [BUTTON]
*
* The layout operates from the "bottom up" (or from right to left.) This means that the button
* area will first be laid out, then the faves area, then the recents. When there are too many
* favorites, the recents area is not displayed.
*
* The following attributes can be set in XML:
*
* orientation: horizontal or vertical
* marginLeft: the left margin of each element in the stack
* marginTop: the top margin of each element in the stack
* marginRight: the right margin of each element in the stack
* marginBottom: the bottom margin of each element in the stack
*/
public class ApplicationsStackLayout extends ViewGroup implements View.OnClickListener {
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
private View mButton;
private LayoutInflater mInflater;
private int mFavoritesEnd;
private int mFavoritesStart;
private List<ApplicationInfo> mFavorites;
private List<ApplicationInfo> mRecents;
private int mOrientation = VERTICAL;
private int mMarginLeft;
private int mMarginTop;
private int mMarginRight;
private int mMarginBottom;
private Rect mDrawRect = new Rect();
private Drawable mBackground;
private int mIconSize;
public ApplicationsStackLayout(Context context) {
super(context);
initLayout();
}
public ApplicationsStackLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a =
context.obtainStyledAttributes(attrs, R.styleable.ApplicationsStackLayout);
mOrientation = a.getInt(R.styleable.ApplicationsStackLayout_stackOrientation, VERTICAL);
mMarginLeft = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginLeft, 0);
mMarginTop = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginTop, 0);
mMarginRight = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginRight, 0);
mMarginBottom = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginBottom, 0);
a.recycle();
mIconSize = 42; //(int) getResources().getDimension(android.R.dimen.app_icon_size);
initLayout();
}
private void initLayout() {
mInflater = LayoutInflater.from(getContext());
mButton = mInflater.inflate(R.layout.all_applications_button, this, false);
addView(mButton);
mBackground = getBackground();
setBackgroundDrawable(null);
setWillNotDraw(false);
}
/**
* Return the current orientation, either VERTICAL (default) or HORIZONTAL.
*
* @return the stack orientation
*/
public int getOrientation() {
return mOrientation;
}
@Override
protected void onDraw(Canvas canvas) {
final Drawable background = mBackground;
final int right = getWidth();
final int bottom = getHeight();
// Draw behind recents
if (mOrientation == VERTICAL) {
mDrawRect.set(0, 0, right, mFavoritesStart);
} else {
mDrawRect.set(0, 0, mFavoritesStart, bottom);
}
background.setBounds(mDrawRect);
background.draw(canvas);
// Draw behind favorites
if (mFavoritesStart > -1) {
if (mOrientation == VERTICAL) {
mDrawRect.set(0, mFavoritesStart, right, mFavoritesEnd);
} else {
mDrawRect.set(mFavoritesStart, 0, mFavoritesEnd, bottom);
}
background.setBounds(mDrawRect);
background.draw(canvas);
}
super.onDraw(canvas);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) {
throw new IllegalStateException("ApplicationsStackLayout can only be used with "
+ "measure spec mode=EXACTLY");
}
setMeasuredDimension(widthSize, heightSize);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
removeAllApplications();
LayoutParams layoutParams = mButton.getLayoutParams();
final int widthSpec = MeasureSpec.makeMeasureSpec(layoutParams.width, MeasureSpec.EXACTLY);
final int heightSpec = MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
mButton.measure(widthSpec, heightSpec);
if (mOrientation == VERTICAL) {
layoutVertical();
} else {
layoutHorizontal();
}
}
private void layoutVertical() {
int childLeft = 0;
int childTop = getHeight();
int childWidth = mButton.getMeasuredWidth();
int childHeight = mButton.getMeasuredHeight();
childTop -= childHeight + mMarginBottom;
mButton.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
childTop -= mMarginTop;
mFavoritesEnd = childTop - mMarginBottom;
int oldChildTop = childTop;
childTop = stackApplications(mFavorites, childLeft, childTop);
if (childTop != oldChildTop) {
mFavoritesStart = childTop + mMarginTop;
} else {
mFavoritesStart = -1;
}
stackApplications(mRecents, childLeft, childTop);
}
private void layoutHorizontal() {
int childLeft = getWidth();
int childTop = 0;
int childWidth = mButton.getMeasuredWidth();
int childHeight = mButton.getMeasuredHeight();
childLeft -= childWidth;
mButton.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
childLeft -= mMarginLeft;
mFavoritesEnd = childLeft - mMarginRight;
int oldChildLeft = childLeft;
childLeft = stackApplications(mFavorites, childLeft, childTop);
if (childLeft != oldChildLeft) {
mFavoritesStart = childLeft + mMarginLeft;
} else {
mFavoritesStart = -1;
}
stackApplications(mRecents, childLeft, childTop);
}
private int stackApplications(List<ApplicationInfo> applications, int childLeft, int childTop) {
LayoutParams layoutParams;
int widthSpec;
int heightSpec;
int childWidth;
int childHeight;
final boolean isVertical = mOrientation == VERTICAL;
final int count = applications.size();
for (int i = count - 1; i >= 0; i--) {
final ApplicationInfo info = applications.get(i);
final View view = createApplicationIcon(mInflater, this, info);
layoutParams = view.getLayoutParams();
widthSpec = MeasureSpec.makeMeasureSpec(layoutParams.width, MeasureSpec.EXACTLY);
heightSpec = MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
view.measure(widthSpec, heightSpec);
childWidth = view.getMeasuredWidth();
childHeight = view.getMeasuredHeight();
if (isVertical) {
childTop -= childHeight + mMarginBottom;
if (childTop < 0) {
childTop += childHeight + mMarginBottom;
break;
}
} else {
childLeft -= childWidth + mMarginRight;
if (childLeft < 0) {
childLeft += childWidth + mMarginRight;
break;
}
}
addViewInLayout(view, -1, layoutParams);
view.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
if (isVertical) {
childTop -= mMarginTop;
} else {
childLeft -= mMarginLeft;
}
}
return isVertical ? childTop : childLeft;
}
private void removeAllApplications() {
final int count = getChildCount();
for (int i = count - 1; i >= 0; i--) {
final View view = getChildAt(i);
if (view != mButton) {
removeViewAt(i);
}
}
}
private View createApplicationIcon(LayoutInflater inflater,
ViewGroup group, ApplicationInfo info) {
TextView textView = (TextView) inflater.inflate(R.layout.favorite, group, false);
info.icon.setBounds(0, 0, mIconSize, mIconSize);
textView.setCompoundDrawables(null, info.icon, null, null);
textView.setText(info.title);
textView.setTag(info.intent);
textView.setOnClickListener(this);
return textView;
}
/**
* Sets the list of favorites.
*
* @param applications the applications to put in the favorites area
*/
public void setFavorites(List<ApplicationInfo> applications) {
mFavorites = applications;
requestLayout();
}
/**
* Sets the list of recents.
*
* @param applications the applications to put in the recents area
*/
public void setRecents(List<ApplicationInfo> applications) {
mRecents = applications;
requestLayout();
}
public void onClick(View v) {
getContext().startActivity((Intent) v.getTag());
}
}