ActionBarContextView.java revision 6e34636749217654f43221885afb7a29bb5ca96a
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.widget.ImageButton; 31import android.widget.LinearLayout; 32import android.widget.TextView; 33 34/** 35 * @hide 36 */ 37public class ActionBarContextView extends ViewGroup { 38 // TODO: This must be defined in the default theme 39 private static final int CONTENT_HEIGHT_DIP = 50; 40 41 private int mItemPadding; 42 private int mItemMargin; 43 private int mActionSpacing; 44 private int mContentHeight; 45 46 private CharSequence mTitle; 47 private CharSequence mSubtitle; 48 49 private ImageButton mCloseButton; 50 private View mCustomView; 51 private LinearLayout mTitleLayout; 52 private TextView mTitleView; 53 private TextView mSubtitleView; 54 private Drawable mCloseDrawable; 55 private ActionMenuView mMenuView; 56 57 public ActionBarContextView(Context context) { 58 this(context, null, 0); 59 } 60 61 public ActionBarContextView(Context context, AttributeSet attrs) { 62 this(context, attrs, 0); 63 } 64 65 public ActionBarContextView(Context context, AttributeSet attrs, int defStyle) { 66 super(context, attrs, defStyle); 67 68 TypedArray a = context.obtainStyledAttributes(attrs, 69 com.android.internal.R.styleable.Theme); 70 mItemPadding = a.getDimensionPixelOffset( 71 com.android.internal.R.styleable.Theme_actionButtonPadding, 0); 72 setBackgroundDrawable(a.getDrawable( 73 com.android.internal.R.styleable.Theme_actionBarContextBackground)); 74 mCloseDrawable = a.getDrawable( 75 com.android.internal.R.styleable.Theme_actionBarCloseContextDrawable); 76 mItemMargin = mItemPadding / 2; 77 78 mContentHeight = 79 (int) (CONTENT_HEIGHT_DIP * getResources().getDisplayMetrics().density + 0.5f); 80 a.recycle(); 81 } 82 83 public void setCustomView(View view) { 84 if (mCustomView != null) { 85 removeView(mCustomView); 86 } 87 mCustomView = view; 88 if (mTitleLayout != null) { 89 removeView(mTitleLayout); 90 mTitleLayout = null; 91 } 92 if (view != null) { 93 addView(view); 94 } 95 requestLayout(); 96 } 97 98 public void setTitle(CharSequence title) { 99 mTitle = title; 100 initTitle(); 101 } 102 103 public void setSubtitle(CharSequence subtitle) { 104 mSubtitle = subtitle; 105 initTitle(); 106 } 107 108 public CharSequence getTitle() { 109 return mTitle; 110 } 111 112 public CharSequence getSubtitle() { 113 return mSubtitle; 114 } 115 116 private void initTitle() { 117 if (mTitleLayout == null) { 118 LayoutInflater inflater = LayoutInflater.from(getContext()); 119 mTitleLayout = (LinearLayout) inflater.inflate(R.layout.action_bar_title_item, null); 120 mTitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_title); 121 mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_subtitle); 122 if (mTitle != null) { 123 mTitleView.setText(mTitle); 124 } 125 if (mSubtitle != null) { 126 mSubtitleView.setText(mSubtitle); 127 } 128 addView(mTitleLayout); 129 } else { 130 mTitleView.setText(mTitle); 131 mSubtitleView.setText(mSubtitle); 132 if (mTitleLayout.getParent() == null) { 133 addView(mTitleLayout); 134 } 135 } 136 } 137 138 public void initForMode(final ActionMode mode) { 139 if (mCloseButton == null) { 140 mCloseButton = new ImageButton(getContext()); 141 mCloseButton.setImageDrawable(mCloseDrawable); 142 mCloseButton.setBackgroundDrawable(null); 143 } 144 mCloseButton.setOnClickListener(new OnClickListener() { 145 public void onClick(View v) { 146 mode.finish(); 147 } 148 }); 149 addView(mCloseButton); 150 151 final MenuBuilder menu = (MenuBuilder) mode.getMenu(); 152 mMenuView = (ActionMenuView) menu.getMenuView(MenuBuilder.TYPE_ACTION_BUTTON, this); 153 mMenuView.setOverflowReserved(true); 154 mMenuView.updateChildren(false); 155 addView(mMenuView); 156 } 157 158 public void closeMode() { 159 removeAllViews(); 160 mCustomView = null; 161 mMenuView = null; 162 } 163 164 @Override 165 protected LayoutParams generateDefaultLayoutParams() { 166 // Used by custom views if they don't supply layout params. Everything else 167 // added to an ActionBarContextView should have them already. 168 return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 169 } 170 171 @Override 172 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 173 final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 174 if (widthMode != MeasureSpec.EXACTLY) { 175 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + 176 "with android:layout_width=\"match_parent\" (or fill_parent)"); 177 } 178 179 final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 180 if (heightMode != MeasureSpec.AT_MOST) { 181 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + 182 "with android:layout_height=\"wrap_content\""); 183 } 184 185 final int contentWidth = MeasureSpec.getSize(widthMeasureSpec); 186 final int itemMargin = mItemPadding; 187 188 int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight(); 189 final int height = mContentHeight - getPaddingTop() - getPaddingBottom(); 190 final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); 191 192 if (mCloseButton != null) { 193 availableWidth = measureChildView(mCloseButton, availableWidth, 194 childSpecHeight, itemMargin); 195 } 196 197 if (mTitleLayout != null && mCustomView == null) { 198 availableWidth = measureChildView(mTitleLayout, availableWidth, 199 childSpecHeight, itemMargin); 200 } 201 202 final int childCount = getChildCount(); 203 for (int i = 0; i < childCount; i++) { 204 final View child = getChildAt(i); 205 if (child == mCloseButton || child == mTitleLayout || child == mCustomView) { 206 continue; 207 } 208 209 availableWidth = measureChildView(child, availableWidth, childSpecHeight, itemMargin); 210 } 211 212 if (mCustomView != null) { 213 LayoutParams lp = mCustomView.getLayoutParams(); 214 final int customWidthMode = lp.width != LayoutParams.WRAP_CONTENT ? 215 MeasureSpec.EXACTLY : MeasureSpec.AT_MOST; 216 final int customWidth = lp.width >= 0 ? 217 Math.min(lp.width, availableWidth) : availableWidth; 218 final int customHeightMode = lp.height != LayoutParams.WRAP_CONTENT ? 219 MeasureSpec.EXACTLY : MeasureSpec.AT_MOST; 220 final int customHeight = lp.height >= 0 ? 221 Math.min(lp.height, height) : height; 222 mCustomView.measure(MeasureSpec.makeMeasureSpec(customWidth, customWidthMode), 223 MeasureSpec.makeMeasureSpec(customHeight, customHeightMode)); 224 } 225 226 setMeasuredDimension(contentWidth, mContentHeight); 227 } 228 229 @Override 230 protected void onLayout(boolean changed, int l, int t, int r, int b) { 231 int x = getPaddingLeft(); 232 final int y = getPaddingTop(); 233 final int contentHeight = b - t - getPaddingTop() - getPaddingBottom(); 234 final int itemMargin = mItemPadding; 235 236 if (mCloseButton != null && mCloseButton.getVisibility() != GONE) { 237 x += positionChild(mCloseButton, x, y, contentHeight); 238 } 239 240 if (mTitleLayout != null && mCustomView == null) { 241 x += positionChild(mTitleLayout, x, y, contentHeight) + itemMargin; 242 } 243 244 if (mCustomView != null) { 245 x += positionChild(mCustomView, x, y, contentHeight) + itemMargin; 246 } 247 248 x = r - l - getPaddingRight(); 249 250 if (mMenuView != null) { 251 x -= positionChildInverse(mMenuView, x + mActionSpacing, y, contentHeight) 252 - mActionSpacing; 253 } 254 } 255 256 private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) { 257 child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), 258 childSpecHeight); 259 260 availableWidth -= child.getMeasuredWidth(); 261 availableWidth -= spacing; 262 263 return availableWidth; 264 } 265 266 private int positionChild(View child, int x, int y, int contentHeight) { 267 int childWidth = child.getMeasuredWidth(); 268 int childHeight = child.getMeasuredHeight(); 269 int childTop = y + (contentHeight - childHeight) / 2; 270 271 child.layout(x, childTop, x + childWidth, childTop + childHeight); 272 273 return childWidth; 274 } 275 276 private int positionChildInverse(View child, int x, int y, int contentHeight) { 277 int childWidth = child.getMeasuredWidth(); 278 int childHeight = child.getMeasuredHeight(); 279 int childTop = y + (contentHeight - childHeight) / 2; 280 281 child.layout(x - childWidth, childTop, x, childTop + childHeight); 282 283 return childWidth; 284 } 285} 286