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 ApplicationsStackLayout(Context context)86 public ApplicationsStackLayout(Context context) { 87 super(context); 88 initLayout(); 89 } 90 ApplicationsStackLayout(Context context, AttributeSet attrs)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 initLayout()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 */ getOrientation()126 public int getOrientation() { 127 return mOrientation; 128 } 129 130 @Override onDraw(Canvas canvas)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 onMeasure(int widthMeasureSpec, int heightMeasureSpec)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 onLayout(boolean changed, int l, int t, int r, int b)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 layoutVertical()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 layoutHorizontal()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 stackApplications(List<ApplicationInfo> applications, int childLeft, int childTop)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 removeAllApplications()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 createApplicationIcon(LayoutInflater inflater, ViewGroup group, ApplicationInfo info)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 */ setFavorites(List<ApplicationInfo> applications)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 */ setRecents(List<ApplicationInfo> applications)332 public void setRecents(List<ApplicationInfo> applications) { 333 mRecents = applications; 334 requestLayout(); 335 } 336 onClick(View v)337 public void onClick(View v) { 338 getContext().startActivity((Intent) v.getTag()); 339 } 340 } 341