ActionBarContextView.java revision bc234a19f4c74116454e2c77f4739290e761995a
1/* 2 * Copyright (C) 2010 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 */ 16package com.android.internal.widget; 17 18import com.android.internal.R; 19import com.android.internal.view.menu.ActionMenuView; 20import com.android.internal.view.menu.MenuBuilder; 21 22import android.content.Context; 23import android.content.res.TypedArray; 24import android.graphics.drawable.Drawable; 25import android.util.AttributeSet; 26import android.view.ActionMode; 27import android.view.LayoutInflater; 28import android.view.View; 29import android.view.ViewGroup; 30import android.view.View.MeasureSpec; 31import android.widget.ImageButton; 32import android.widget.LinearLayout; 33import android.widget.TextView; 34 35/** 36 * @hide 37 */ 38public class ActionBarContextView extends ViewGroup { 39 private int mItemPadding; 40 private int mActionSpacing; 41 private int mContentHeight; 42 43 private CharSequence mTitle; 44 private CharSequence mSubtitle; 45 46 private ImageButton mCloseButton; 47 private View mCustomView; 48 private LinearLayout mTitleLayout; 49 private TextView mTitleView; 50 private TextView mSubtitleView; 51 private int mCloseButtonStyle; 52 private int mTitleStyleRes; 53 private int mSubtitleStyleRes; 54 private ActionMenuView mMenuView; 55 56 public ActionBarContextView(Context context) { 57 this(context, null); 58 } 59 60 public ActionBarContextView(Context context, AttributeSet attrs) { 61 this(context, attrs, com.android.internal.R.attr.actionModeStyle); 62 } 63 64 public ActionBarContextView(Context context, AttributeSet attrs, int defStyle) { 65 super(context, attrs, defStyle); 66 67 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionMode, defStyle, 0); 68 mItemPadding = a.getDimensionPixelOffset( 69 com.android.internal.R.styleable.ActionMode_itemPadding, 0); 70 setBackgroundDrawable(a.getDrawable( 71 com.android.internal.R.styleable.ActionMode_background)); 72 mCloseButtonStyle = a.getResourceId( 73 com.android.internal.R.styleable.ActionMode_closeButtonStyle, 0); 74 mTitleStyleRes = a.getResourceId( 75 com.android.internal.R.styleable.ActionMode_titleTextStyle, 0); 76 mSubtitleStyleRes = a.getResourceId( 77 com.android.internal.R.styleable.ActionMode_subtitleTextStyle, 0); 78 79 mContentHeight = a.getLayoutDimension( 80 com.android.internal.R.styleable.ActionMode_height, 0); 81 a.recycle(); 82 } 83 84 @Override 85 public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) { 86 // No starting an action mode for an existing action mode UI child! (Where would it go?) 87 return null; 88 } 89 90 public void setHeight(int height) { 91 mContentHeight = height; 92 } 93 94 public void setCustomView(View view) { 95 if (mCustomView != null) { 96 removeView(mCustomView); 97 } 98 mCustomView = view; 99 if (mTitleLayout != null) { 100 removeView(mTitleLayout); 101 mTitleLayout = null; 102 } 103 if (view != null) { 104 addView(view); 105 } 106 requestLayout(); 107 } 108 109 public void setTitle(CharSequence title) { 110 mTitle = title; 111 initTitle(); 112 } 113 114 public void setSubtitle(CharSequence subtitle) { 115 mSubtitle = subtitle; 116 initTitle(); 117 } 118 119 public CharSequence getTitle() { 120 return mTitle; 121 } 122 123 public CharSequence getSubtitle() { 124 return mSubtitle; 125 } 126 127 private void initTitle() { 128 if (mTitleLayout == null) { 129 LayoutInflater inflater = LayoutInflater.from(getContext()); 130 mTitleLayout = (LinearLayout) inflater.inflate(R.layout.action_bar_title_item, null); 131 mTitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_title); 132 mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_subtitle); 133 if (mTitle != null) { 134 mTitleView.setText(mTitle); 135 if (mTitleStyleRes != 0) { 136 mTitleView.setTextAppearance(mContext, mTitleStyleRes); 137 } 138 } 139 if (mSubtitle != null) { 140 mSubtitleView.setText(mSubtitle); 141 if (mSubtitleStyleRes != 0) { 142 mSubtitleView.setTextAppearance(mContext, mSubtitleStyleRes); 143 } 144 mSubtitleView.setVisibility(VISIBLE); 145 } 146 addView(mTitleLayout); 147 } else { 148 mTitleView.setText(mTitle); 149 mSubtitleView.setText(mSubtitle); 150 mSubtitleView.setVisibility(mSubtitle != null ? VISIBLE : GONE); 151 if (mTitleLayout.getParent() == null) { 152 addView(mTitleLayout); 153 } 154 } 155 } 156 157 public void initForMode(final ActionMode mode) { 158 if (mCloseButton == null) { 159 mCloseButton = new ImageButton(getContext(), null, mCloseButtonStyle); 160 } 161 mCloseButton.setOnClickListener(new OnClickListener() { 162 public void onClick(View v) { 163 mode.finish(); 164 } 165 }); 166 addView(mCloseButton); 167 168 final MenuBuilder menu = (MenuBuilder) mode.getMenu(); 169 mMenuView = (ActionMenuView) menu.getMenuView(MenuBuilder.TYPE_ACTION_BUTTON, this); 170 mMenuView.setOverflowReserved(true); 171 mMenuView.updateChildren(false); 172 addView(mMenuView); 173 } 174 175 public void closeMode() { 176 removeAllViews(); 177 mCustomView = null; 178 mMenuView = null; 179 } 180 181 public boolean showOverflowMenu() { 182 if (mMenuView != null) { 183 return mMenuView.showOverflowMenu(); 184 } 185 return false; 186 } 187 188 public boolean hideOverflowMenu() { 189 if (mMenuView != null) { 190 return mMenuView.hideOverflowMenu(); 191 } 192 return false; 193 } 194 195 public boolean isOverflowMenuShowing() { 196 if (mMenuView != null) { 197 return mMenuView.isOverflowMenuShowing(); 198 } 199 return false; 200 } 201 202 @Override 203 protected LayoutParams generateDefaultLayoutParams() { 204 // Used by custom views if they don't supply layout params. Everything else 205 // added to an ActionBarContextView should have them already. 206 return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 207 } 208 209 @Override 210 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 211 final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 212 if (widthMode != MeasureSpec.EXACTLY) { 213 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + 214 "with android:layout_width=\"match_parent\" (or fill_parent)"); 215 } 216 217 final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 218 if (heightMode != MeasureSpec.AT_MOST) { 219 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + 220 "with android:layout_height=\"wrap_content\""); 221 } 222 223 final int contentWidth = MeasureSpec.getSize(widthMeasureSpec); 224 final int itemMargin = mItemPadding; 225 226 int maxHeight = mContentHeight > 0 ? 227 mContentHeight : MeasureSpec.getSize(heightMeasureSpec); 228 229 final int verticalPadding = getPaddingTop() + getPaddingBottom(); 230 int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight(); 231 final int height = maxHeight - verticalPadding; 232 final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); 233 234 if (mCloseButton != null) { 235 availableWidth = measureChildView(mCloseButton, availableWidth, 236 childSpecHeight, itemMargin); 237 } 238 239 if (mTitleLayout != null && mCustomView == null) { 240 availableWidth = measureChildView(mTitleLayout, availableWidth, 241 childSpecHeight, itemMargin); 242 } 243 244 final int childCount = getChildCount(); 245 for (int i = 0; i < childCount; i++) { 246 final View child = getChildAt(i); 247 if (child == mCloseButton || child == mTitleLayout || child == mCustomView) { 248 continue; 249 } 250 251 availableWidth = measureChildView(child, availableWidth, childSpecHeight, itemMargin); 252 } 253 254 if (mCustomView != null) { 255 LayoutParams lp = mCustomView.getLayoutParams(); 256 final int customWidthMode = lp.width != LayoutParams.WRAP_CONTENT ? 257 MeasureSpec.EXACTLY : MeasureSpec.AT_MOST; 258 final int customWidth = lp.width >= 0 ? 259 Math.min(lp.width, availableWidth) : availableWidth; 260 final int customHeightMode = lp.height != LayoutParams.WRAP_CONTENT ? 261 MeasureSpec.EXACTLY : MeasureSpec.AT_MOST; 262 final int customHeight = lp.height >= 0 ? 263 Math.min(lp.height, height) : height; 264 mCustomView.measure(MeasureSpec.makeMeasureSpec(customWidth, customWidthMode), 265 MeasureSpec.makeMeasureSpec(customHeight, customHeightMode)); 266 } 267 268 if (mContentHeight <= 0) { 269 int measuredHeight = 0; 270 final int count = getChildCount(); 271 for (int i = 0; i < count; i++) { 272 View v = getChildAt(i); 273 int paddedViewHeight = v.getMeasuredHeight() + verticalPadding; 274 if (paddedViewHeight > measuredHeight) { 275 measuredHeight = paddedViewHeight; 276 } 277 } 278 setMeasuredDimension(contentWidth, measuredHeight); 279 } else { 280 setMeasuredDimension(contentWidth, maxHeight); 281 } 282 } 283 284 @Override 285 protected void onLayout(boolean changed, int l, int t, int r, int b) { 286 int x = getPaddingLeft(); 287 final int y = getPaddingTop(); 288 final int contentHeight = b - t - getPaddingTop() - getPaddingBottom(); 289 final int itemMargin = mItemPadding; 290 291 if (mCloseButton != null && mCloseButton.getVisibility() != GONE) { 292 x += positionChild(mCloseButton, x, y, contentHeight); 293 } 294 295 if (mTitleLayout != null && mCustomView == null) { 296 x += positionChild(mTitleLayout, x, y, contentHeight) + itemMargin; 297 } 298 299 if (mCustomView != null) { 300 x += positionChild(mCustomView, x, y, contentHeight) + itemMargin; 301 } 302 303 x = r - l - getPaddingRight(); 304 305 if (mMenuView != null) { 306 x -= positionChildInverse(mMenuView, x + mActionSpacing, y, contentHeight) 307 - mActionSpacing; 308 } 309 } 310 311 private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) { 312 child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), 313 childSpecHeight); 314 315 availableWidth -= child.getMeasuredWidth(); 316 availableWidth -= spacing; 317 318 return availableWidth; 319 } 320 321 private int positionChild(View child, int x, int y, int contentHeight) { 322 int childWidth = child.getMeasuredWidth(); 323 int childHeight = child.getMeasuredHeight(); 324 int childTop = y + (contentHeight - childHeight) / 2; 325 326 child.layout(x, childTop, x + childWidth, childTop + childHeight); 327 328 return childWidth; 329 } 330 331 private int positionChildInverse(View child, int x, int y, int contentHeight) { 332 int childWidth = child.getMeasuredWidth(); 333 int childHeight = child.getMeasuredHeight(); 334 int childTop = y + (contentHeight - childHeight) / 2; 335 336 child.layout(x - childWidth, childTop, x, childTop + childHeight); 337 338 return childWidth; 339 } 340} 341