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