Home | History | Annotate | Download | only in home
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.example.android.home;
     18 
     19 import android.content.Context;
     20 import android.content.Intent;
     21 import android.content.res.TypedArray;
     22 import android.graphics.Canvas;
     23 import android.graphics.Rect;
     24 import android.graphics.drawable.Drawable;
     25 import android.util.AttributeSet;
     26 import android.view.View;
     27 import android.view.ViewGroup;
     28 import android.view.LayoutInflater;
     29 import android.widget.TextView;
     30 
     31 import java.util.List;
     32 
     33 /**
     34  * The ApplicationsStackLayout is a specialized layout used for the purpose of the home screen
     35  * only. This layout stacks various icons in three distinct areas: the recents, the favorites
     36  * (or faves) and the button.
     37  *
     38  * This layout supports two different orientations: vertical and horizontal. When horizontal,
     39  * the areas are laid out this way:
     40  *
     41  * [RECENTS][FAVES][BUTTON]
     42  *
     43  * When vertical, the layout is the following:
     44  *
     45  * [RECENTS]
     46  * [FAVES]
     47  * [BUTTON]
     48  *
     49  * The layout operates from the "bottom up" (or from right to left.) This means that the button
     50  * area will first be laid out, then the faves area, then the recents. When there are too many
     51  * favorites, the recents area is not displayed.
     52  *
     53  * The following attributes can be set in XML:
     54  *
     55  * orientation: horizontal or vertical
     56  * marginLeft: the left margin of each element in the stack
     57  * marginTop: the top margin of each element in the stack
     58  * marginRight: the right margin of each element in the stack
     59  * marginBottom: the bottom margin of each element in the stack
     60  */
     61 public class ApplicationsStackLayout extends ViewGroup implements View.OnClickListener {
     62     public static final int HORIZONTAL = 0;
     63     public static final int VERTICAL = 1;
     64 
     65     private View mButton;
     66     private LayoutInflater mInflater;
     67 
     68     private int mFavoritesEnd;
     69     private int mFavoritesStart;
     70 
     71     private List<ApplicationInfo> mFavorites;
     72     private List<ApplicationInfo> mRecents;
     73 
     74     private int mOrientation = VERTICAL;
     75 
     76     private int mMarginLeft;
     77     private int mMarginTop;
     78     private int mMarginRight;
     79     private int mMarginBottom;
     80 
     81     private Rect mDrawRect = new Rect();
     82 
     83     private Drawable mBackground;
     84     private int mIconSize;
     85 
     86     public ApplicationsStackLayout(Context context) {
     87         super(context);
     88         initLayout();
     89     }
     90 
     91     public ApplicationsStackLayout(Context context, AttributeSet attrs) {
     92         super(context, attrs);
     93 
     94         TypedArray a =
     95                 context.obtainStyledAttributes(attrs, R.styleable.ApplicationsStackLayout);
     96 
     97         mOrientation = a.getInt(R.styleable.ApplicationsStackLayout_stackOrientation, VERTICAL);
     98 
     99         mMarginLeft = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginLeft, 0);
    100         mMarginTop = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginTop, 0);
    101         mMarginRight = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginRight, 0);
    102         mMarginBottom = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginBottom, 0);
    103 
    104         a.recycle();
    105 
    106         mIconSize = 42; //(int) getResources().getDimension(android.R.dimen.app_icon_size);
    107 
    108         initLayout();
    109     }
    110 
    111     private void initLayout() {
    112         mInflater = LayoutInflater.from(getContext());
    113         mButton = mInflater.inflate(R.layout.all_applications_button, this, false);
    114         addView(mButton);
    115 
    116         mBackground = getBackground();
    117         setBackgroundDrawable(null);
    118         setWillNotDraw(false);
    119     }
    120 
    121     /**
    122      * Return the current orientation, either VERTICAL (default) or HORIZONTAL.
    123      *
    124      * @return the stack orientation
    125      */
    126     public int getOrientation() {
    127         return mOrientation;
    128     }
    129 
    130     @Override
    131     protected void onDraw(Canvas canvas) {
    132         final Drawable background = mBackground;
    133 
    134         final int right = getWidth();
    135         final int bottom = getHeight();
    136 
    137         // Draw behind recents
    138         if (mOrientation == VERTICAL) {
    139             mDrawRect.set(0, 0, right, mFavoritesStart);
    140         } else {
    141             mDrawRect.set(0, 0, mFavoritesStart, bottom);
    142         }
    143         background.setBounds(mDrawRect);
    144         background.draw(canvas);
    145 
    146         // Draw behind favorites
    147         if (mFavoritesStart > -1) {
    148             if (mOrientation == VERTICAL) {
    149                 mDrawRect.set(0, mFavoritesStart, right, mFavoritesEnd);
    150             } else {
    151                 mDrawRect.set(mFavoritesStart, 0, mFavoritesEnd, bottom);
    152             }
    153             background.setBounds(mDrawRect);
    154             background.draw(canvas);
    155         }
    156 
    157         super.onDraw(canvas);
    158     }
    159 
    160     @Override
    161     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    162         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    163 
    164         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    165         final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    166 
    167         final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    168         final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    169 
    170         if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) {
    171             throw new IllegalStateException("ApplicationsStackLayout can only be used with "
    172                     + "measure spec mode=EXACTLY");
    173         }
    174 
    175         setMeasuredDimension(widthSize, heightSize);
    176     }
    177 
    178     @Override
    179     protected void onLayout(boolean changed, int l, int t, int r, int b) {
    180         removeAllApplications();
    181 
    182         LayoutParams layoutParams = mButton.getLayoutParams();
    183         final int widthSpec = MeasureSpec.makeMeasureSpec(layoutParams.width, MeasureSpec.EXACTLY);
    184         final int heightSpec = MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
    185         mButton.measure(widthSpec, heightSpec);
    186 
    187         if (mOrientation == VERTICAL) {
    188             layoutVertical();
    189         } else {
    190             layoutHorizontal();
    191         }
    192     }
    193 
    194     private void layoutVertical() {
    195         int childLeft = 0;
    196         int childTop = getHeight();
    197 
    198         int childWidth = mButton.getMeasuredWidth();
    199         int childHeight = mButton.getMeasuredHeight();
    200 
    201         childTop -= childHeight + mMarginBottom;
    202         mButton.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
    203         childTop -= mMarginTop;
    204         mFavoritesEnd = childTop - mMarginBottom;
    205 
    206         int oldChildTop = childTop;
    207         childTop = stackApplications(mFavorites, childLeft, childTop);
    208         if (childTop != oldChildTop) {
    209             mFavoritesStart = childTop + mMarginTop;
    210         } else {
    211             mFavoritesStart = -1;
    212         }
    213 
    214         stackApplications(mRecents, childLeft, childTop);
    215     }
    216 
    217     private void layoutHorizontal() {
    218         int childLeft = getWidth();
    219         int childTop = 0;
    220 
    221         int childWidth = mButton.getMeasuredWidth();
    222         int childHeight = mButton.getMeasuredHeight();
    223 
    224         childLeft -= childWidth;
    225         mButton.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
    226         childLeft -= mMarginLeft;
    227         mFavoritesEnd = childLeft - mMarginRight;
    228 
    229         int oldChildLeft = childLeft;
    230         childLeft = stackApplications(mFavorites, childLeft, childTop);
    231         if (childLeft != oldChildLeft) {
    232             mFavoritesStart = childLeft + mMarginLeft;
    233         } else {
    234             mFavoritesStart = -1;
    235         }
    236 
    237         stackApplications(mRecents, childLeft, childTop);
    238     }
    239 
    240     private int stackApplications(List<ApplicationInfo> applications, int childLeft, int childTop) {
    241         LayoutParams layoutParams;
    242         int widthSpec;
    243         int heightSpec;
    244         int childWidth;
    245         int childHeight;
    246 
    247         final boolean isVertical = mOrientation == VERTICAL;
    248 
    249         final int count = applications.size();
    250         for (int i = count - 1; i >= 0; i--) {
    251             final ApplicationInfo info = applications.get(i);
    252             final View view = createApplicationIcon(mInflater, this, info);
    253 
    254             layoutParams = view.getLayoutParams();
    255             widthSpec = MeasureSpec.makeMeasureSpec(layoutParams.width, MeasureSpec.EXACTLY);
    256             heightSpec = MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
    257             view.measure(widthSpec, heightSpec);
    258 
    259             childWidth = view.getMeasuredWidth();
    260             childHeight = view.getMeasuredHeight();
    261 
    262             if (isVertical) {
    263                 childTop -= childHeight + mMarginBottom;
    264 
    265                 if (childTop < 0) {
    266                     childTop += childHeight + mMarginBottom;
    267                     break;
    268                 }
    269             } else {
    270                 childLeft -= childWidth + mMarginRight;
    271 
    272                 if (childLeft < 0) {
    273                     childLeft += childWidth + mMarginRight;
    274                     break;
    275                 }
    276             }
    277 
    278             addViewInLayout(view, -1, layoutParams);
    279 
    280             view.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
    281 
    282             if (isVertical) {
    283                 childTop -= mMarginTop;
    284             } else {
    285                 childLeft -= mMarginLeft;
    286             }
    287         }
    288 
    289         return isVertical ? childTop : childLeft;
    290     }
    291 
    292     private void removeAllApplications() {
    293         final int count = getChildCount();
    294         for (int i = count - 1; i >= 0; i--) {
    295             final View view = getChildAt(i);
    296             if (view != mButton) {
    297                 removeViewAt(i);
    298             }
    299         }
    300     }
    301 
    302     private View createApplicationIcon(LayoutInflater inflater,
    303             ViewGroup group, ApplicationInfo info) {
    304 
    305         TextView textView = (TextView) inflater.inflate(R.layout.favorite, group, false);
    306 
    307         info.icon.setBounds(0, 0, mIconSize, mIconSize);
    308         textView.setCompoundDrawables(null, info.icon, null, null);
    309         textView.setText(info.title);
    310 
    311         textView.setTag(info.intent);
    312         textView.setOnClickListener(this);
    313 
    314         return textView;
    315     }
    316 
    317     /**
    318      * Sets the list of favorites.
    319      *
    320      * @param applications the applications to put in the favorites area
    321      */
    322     public void setFavorites(List<ApplicationInfo> applications) {
    323         mFavorites = applications;
    324         requestLayout();
    325     }
    326 
    327     /**
    328      * Sets the list of recents.
    329      *
    330      * @param applications the applications to put in the recents area
    331      */
    332     public void setRecents(List<ApplicationInfo> applications) {
    333         mRecents = applications;
    334         requestLayout();
    335     }
    336 
    337     public void onClick(View v) {
    338         getContext().startActivity((Intent) v.getTag());
    339     }
    340 }
    341