| /* |
| * 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()); |
| } |
| } |