ActionBarContextView.java revision 8350f7dbc3a62211b2891f35911e4073d24c4cc5
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_actionModeBackground)); 74 mCloseDrawable = a.getDrawable( 75 com.android.internal.R.styleable.Theme_actionModeCloseDrawable); 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 mSubtitleView.setVisibility(VISIBLE); 128 } 129 addView(mTitleLayout); 130 } else { 131 mTitleView.setText(mTitle); 132 mSubtitleView.setText(mSubtitle); 133 mSubtitleView.setVisibility(mSubtitle != null ? VISIBLE : GONE); 134 if (mTitleLayout.getParent() == null) { 135 addView(mTitleLayout); 136 } 137 } 138 } 139 140 public void initForMode(final ActionMode mode) { 141 if (mCloseButton == null) { 142 mCloseButton = new ImageButton(getContext()); 143 mCloseButton.setImageDrawable(mCloseDrawable); 144 mCloseButton.setBackgroundDrawable(null); 145 } 146 mCloseButton.setOnClickListener(new OnClickListener() { 147 public void onClick(View v) { 148 mode.finish(); 149 } 150 }); 151 addView(mCloseButton); 152 153 final MenuBuilder menu = (MenuBuilder) mode.getMenu(); 154 mMenuView = (ActionMenuView) menu.getMenuView(MenuBuilder.TYPE_ACTION_BUTTON, this); 155 mMenuView.setOverflowReserved(true); 156 mMenuView.updateChildren(false); 157 addView(mMenuView); 158 } 159 160 public void closeMode() { 161 removeAllViews(); 162 mCustomView = null; 163 mMenuView = null; 164 } 165 166 @Override 167 protected LayoutParams generateDefaultLayoutParams() { 168 // Used by custom views if they don't supply layout params. Everything else 169 // added to an ActionBarContextView should have them already. 170 return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 171 } 172 173 @Override 174 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 175 final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 176 if (widthMode != MeasureSpec.EXACTLY) { 177 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + 178 "with android:layout_width=\"match_parent\" (or fill_parent)"); 179 } 180 181 final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 182 if (heightMode != MeasureSpec.AT_MOST) { 183 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + 184 "with android:layout_height=\"wrap_content\""); 185 } 186 187 final int contentWidth = MeasureSpec.getSize(widthMeasureSpec); 188 final int itemMargin = mItemPadding; 189 190 int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight(); 191 final int height = mContentHeight - getPaddingTop() - getPaddingBottom(); 192 final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); 193 194 if (mCloseButton != null) { 195 availableWidth = measureChildView(mCloseButton, availableWidth, 196 childSpecHeight, itemMargin); 197 } 198 199 if (mTitleLayout != null && mCustomView == null) { 200 availableWidth = measureChildView(mTitleLayout, availableWidth, 201 childSpecHeight, itemMargin); 202 } 203 204 final int childCount = getChildCount(); 205 for (int i = 0; i < childCount; i++) { 206 final View child = getChildAt(i); 207 if (child == mCloseButton || child == mTitleLayout || child == mCustomView) { 208 continue; 209 } 210 211 availableWidth = measureChildView(child, availableWidth, childSpecHeight, itemMargin); 212 } 213 214 if (mCustomView != null) { 215 LayoutParams lp = mCustomView.getLayoutParams(); 216 final int customWidthMode = lp.width != LayoutParams.WRAP_CONTENT ? 217 MeasureSpec.EXACTLY : MeasureSpec.AT_MOST; 218 final int customWidth = lp.width >= 0 ? 219 Math.min(lp.width, availableWidth) : availableWidth; 220 final int customHeightMode = lp.height != LayoutParams.WRAP_CONTENT ? 221 MeasureSpec.EXACTLY : MeasureSpec.AT_MOST; 222 final int customHeight = lp.height >= 0 ? 223 Math.min(lp.height, height) : height; 224 mCustomView.measure(MeasureSpec.makeMeasureSpec(customWidth, customWidthMode), 225 MeasureSpec.makeMeasureSpec(customHeight, customHeightMode)); 226 } 227 228 setMeasuredDimension(contentWidth, mContentHeight); 229 } 230 231 @Override 232 protected void onLayout(boolean changed, int l, int t, int r, int b) { 233 int x = getPaddingLeft(); 234 final int y = getPaddingTop(); 235 final int contentHeight = b - t - getPaddingTop() - getPaddingBottom(); 236 final int itemMargin = mItemPadding; 237 238 if (mCloseButton != null && mCloseButton.getVisibility() != GONE) { 239 x += positionChild(mCloseButton, x, y, contentHeight); 240 } 241 242 if (mTitleLayout != null && mCustomView == null) { 243 x += positionChild(mTitleLayout, x, y, contentHeight) + itemMargin; 244 } 245 246 if (mCustomView != null) { 247 x += positionChild(mCustomView, x, y, contentHeight) + itemMargin; 248 } 249 250 x = r - l - getPaddingRight(); 251 252 if (mMenuView != null) { 253 x -= positionChildInverse(mMenuView, x + mActionSpacing, y, contentHeight) 254 - mActionSpacing; 255 } 256 } 257 258 private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) { 259 child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), 260 childSpecHeight); 261 262 availableWidth -= child.getMeasuredWidth(); 263 availableWidth -= spacing; 264 265 return availableWidth; 266 } 267 268 private int positionChild(View child, int x, int y, int contentHeight) { 269 int childWidth = child.getMeasuredWidth(); 270 int childHeight = child.getMeasuredHeight(); 271 int childTop = y + (contentHeight - childHeight) / 2; 272 273 child.layout(x, childTop, x + childWidth, childTop + childHeight); 274 275 return childWidth; 276 } 277 278 private int positionChildInverse(View child, int x, int y, int contentHeight) { 279 int childWidth = child.getMeasuredWidth(); 280 int childHeight = child.getMeasuredHeight(); 281 int childTop = y + (contentHeight - childHeight) / 2; 282 283 child.layout(x - childWidth, childTop, x, childTop + childHeight); 284 285 return childWidth; 286 } 287} 288