ActionBarContextView.java revision 29ed7575c2129974a57ad77b3531bc5995940c6c
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.app.ActionBarImpl;
20
21import android.app.ActionBar;
22import android.content.Context;
23import android.content.res.TypedArray;
24import android.graphics.drawable.Drawable;
25import android.util.AttributeSet;
26import android.view.LayoutInflater;
27import android.view.Menu;
28import android.view.MenuItem;
29import android.view.View;
30import android.view.ViewGroup;
31import android.view.View.MeasureSpec;
32import android.view.ViewGroup.LayoutParams;
33import android.widget.ImageButton;
34import android.widget.LinearLayout;
35import android.widget.TextView;
36
37/**
38 * @hide
39 */
40public class ActionBarContextView extends ViewGroup {
41    // TODO: This must be defined in the default theme
42    private static final int CONTENT_HEIGHT_DIP = 50;
43
44    private int mItemPadding;
45    private int mItemMargin;
46    private int mContentHeight;
47
48    private CharSequence mTitle;
49    private CharSequence mSubtitle;
50
51    private ImageButton mCloseButton;
52    private View mCustomView;
53    private LinearLayout mTitleLayout;
54    private TextView mTitleView;
55    private TextView mSubtitleView;
56    private Drawable mCloseDrawable;
57
58    public ActionBarContextView(Context context) {
59        this(context, null, 0);
60    }
61
62    public ActionBarContextView(Context context, AttributeSet attrs) {
63        this(context, attrs, 0);
64    }
65
66    public ActionBarContextView(Context context, AttributeSet attrs, int defStyle) {
67        super(context, attrs, defStyle);
68
69        TypedArray a = context.obtainStyledAttributes(attrs,
70                com.android.internal.R.styleable.Theme);
71        mItemPadding = a.getDimensionPixelOffset(
72                com.android.internal.R.styleable.Theme_actionButtonPadding, 0);
73        setBackgroundDrawable(a.getDrawable(
74                com.android.internal.R.styleable.Theme_actionBarContextBackground));
75        mCloseDrawable = a.getDrawable(
76                com.android.internal.R.styleable.Theme_actionBarCloseContextDrawable);
77        mItemMargin = mItemPadding / 2;
78
79        mContentHeight = CONTENT_HEIGHT_DIP;
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 ActionBar.ContextMode mode) {
139        final ActionBarImpl.ContextMode implMode = (ActionBarImpl.ContextMode) mode;
140
141        if (mCloseButton == null) {
142            mCloseButton = new ImageButton(getContext());
143            mCloseButton.setImageDrawable(mCloseDrawable);
144            mCloseButton.setBackgroundDrawable(null);
145            mCloseButton.setOnClickListener(new OnClickListener() {
146                public void onClick(View v) {
147                    mode.finish();
148                }
149            });
150        }
151        addView(mCloseButton);
152
153        final Context context = getContext();
154        final Menu menu = mode.getMenu();
155        final int itemCount = menu.size();
156        for (int i = 0; i < itemCount; i++) {
157            final MenuItem item = menu.getItem(i);
158            final ImageButton button = new ImageButton(context, null,
159                    com.android.internal.R.attr.actionButtonStyle);
160            button.setClickable(true);
161            button.setFocusable(true);
162            button.setImageDrawable(item.getIcon());
163            button.setId(item.getItemId());
164            button.setVisibility(item.isVisible() ? VISIBLE : GONE);
165            button.setEnabled(item.isEnabled());
166
167            button.setOnClickListener(new OnClickListener() {
168                public void onClick(View v) {
169                    implMode.dispatchOnContextItemClicked(item);
170                }
171            });
172
173            addView(button);
174        }
175        requestLayout();
176    }
177
178    public void closeMode() {
179        removeAllViews();
180        mCustomView = null;
181    }
182
183    @Override
184    protected LayoutParams generateDefaultLayoutParams() {
185        // Used by custom views if they don't supply layout params. Everything else
186        // added to an ActionBarContextView should have them already.
187        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
188    }
189
190    @Override
191    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
192        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
193        if (widthMode != MeasureSpec.EXACTLY) {
194            throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
195                    "with android:layout_width=\"match_parent\" (or fill_parent)");
196        }
197
198        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
199        if (heightMode != MeasureSpec.AT_MOST) {
200            throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
201                    "with android:layout_height=\"wrap_content\"");
202        }
203
204        final int contentWidth = MeasureSpec.getSize(widthMeasureSpec);
205        final int itemMargin = mItemPadding;
206
207        int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight();
208        final int height = mContentHeight - getPaddingTop() - getPaddingBottom();
209        final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
210
211        if (mCloseButton != null) {
212            availableWidth = measureChildView(mCloseButton, availableWidth,
213                    childSpecHeight, itemMargin);
214        }
215
216        if (mTitleLayout != null && mCustomView == null) {
217            availableWidth = measureChildView(mTitleLayout, availableWidth,
218                    childSpecHeight, itemMargin);
219        }
220
221        final int childCount = getChildCount();
222        for (int i = 0; i < childCount; i++) {
223            final View child = getChildAt(i);
224            if (child == mCloseButton || child == mTitleLayout || child == mCustomView) {
225                continue;
226            }
227
228            availableWidth = measureChildView(child, availableWidth, childSpecHeight, itemMargin);
229        }
230
231        if (mCustomView != null) {
232            LayoutParams lp = mCustomView.getLayoutParams();
233            final int customWidthMode = lp.width != LayoutParams.WRAP_CONTENT ?
234                    MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
235            final int customWidth = lp.width >= 0 ?
236                    Math.min(lp.width, availableWidth) : availableWidth;
237            final int customHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
238                    MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
239            final int customHeight = lp.height >= 0 ?
240                    Math.min(lp.height, height) : height;
241            mCustomView.measure(MeasureSpec.makeMeasureSpec(customWidth, customWidthMode),
242                    MeasureSpec.makeMeasureSpec(customHeight, customHeightMode));
243        }
244
245        setMeasuredDimension(contentWidth, mContentHeight);
246    }
247
248    @Override
249    protected void onLayout(boolean changed, int l, int t, int r, int b) {
250        int x = getPaddingLeft();
251        final int y = getPaddingTop();
252        final int contentHeight = b - t - getPaddingTop() - getPaddingBottom();
253        final int itemMargin = mItemPadding;
254
255        if (mCloseButton != null && mCloseButton.getVisibility() != GONE) {
256            x += positionChild(mCloseButton, x, y, contentHeight);
257        }
258
259        if (mTitleLayout != null && mCustomView == null) {
260            x += positionChild(mTitleLayout, x, y, contentHeight) + itemMargin;
261        }
262
263        if (mCustomView != null) {
264            x += positionChild(mCustomView, x, y, contentHeight) + itemMargin;
265        }
266
267        x = r - l - getPaddingRight();
268
269        final int childCount = getChildCount();
270        for (int i = 0; i < childCount; i++) {
271            final View child = getChildAt(i);
272            if (child == mCloseButton || child == mTitleLayout || child == mCustomView) {
273                continue;
274            }
275
276            x -= positionChildInverse(child, x, y, contentHeight) + itemMargin;
277        }
278    }
279
280    private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) {
281        child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
282                childSpecHeight);
283
284        availableWidth -= child.getMeasuredWidth();
285        availableWidth -= spacing;
286
287        return availableWidth;
288    }
289
290    private int positionChild(View child, int x, int y, int contentHeight) {
291        int childWidth = child.getMeasuredWidth();
292        int childHeight = child.getMeasuredHeight();
293        int childTop = y + (contentHeight - childHeight) / 2;
294
295        child.layout(x, childTop, x + childWidth, childTop + childHeight);
296
297        return childWidth;
298    }
299
300    private int positionChildInverse(View child, int x, int y, int contentHeight) {
301        int childWidth = child.getMeasuredWidth();
302        int childHeight = child.getMeasuredHeight();
303        int childTop = y + (contentHeight - childHeight) / 2;
304
305        child.layout(x - childWidth, childTop, x, childTop + childHeight);
306
307        return childWidth;
308    }
309}
310