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