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