ActionBarContextView.java revision dcdefbbff2bfecbfeb7b6459de130f376595c590
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 =
80                (int) (CONTENT_HEIGHT_DIP * getResources().getDisplayMetrics().density + 0.5f);
81        a.recycle();
82    }
83
84    public void setCustomView(View view) {
85        if (mCustomView != null) {
86            removeView(mCustomView);
87        }
88        mCustomView = view;
89        if (mTitleLayout != null) {
90            removeView(mTitleLayout);
91            mTitleLayout = null;
92        }
93        if (view != null) {
94            addView(view);
95        }
96        requestLayout();
97    }
98
99    public void setTitle(CharSequence title) {
100        mTitle = title;
101        initTitle();
102    }
103
104    public void setSubtitle(CharSequence subtitle) {
105        mSubtitle = subtitle;
106        initTitle();
107    }
108
109    public CharSequence getTitle() {
110        return mTitle;
111    }
112
113    public CharSequence getSubtitle() {
114        return mSubtitle;
115    }
116
117    private void initTitle() {
118        if (mTitleLayout == null) {
119            LayoutInflater inflater = LayoutInflater.from(getContext());
120            mTitleLayout = (LinearLayout) inflater.inflate(R.layout.action_bar_title_item, null);
121            mTitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_title);
122            mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_subtitle);
123            if (mTitle != null) {
124                mTitleView.setText(mTitle);
125            }
126            if (mSubtitle != null) {
127                mSubtitleView.setText(mSubtitle);
128            }
129            addView(mTitleLayout);
130        } else {
131            mTitleView.setText(mTitle);
132            mSubtitleView.setText(mSubtitle);
133            if (mTitleLayout.getParent() == null) {
134                addView(mTitleLayout);
135            }
136        }
137    }
138
139    public void initForMode(final ActionBar.ContextMode mode) {
140        final ActionBarImpl.ContextMode implMode = (ActionBarImpl.ContextMode) mode;
141
142        if (mCloseButton == null) {
143            mCloseButton = new ImageButton(getContext());
144            mCloseButton.setImageDrawable(mCloseDrawable);
145            mCloseButton.setBackgroundDrawable(null);
146            mCloseButton.setOnClickListener(new OnClickListener() {
147                public void onClick(View v) {
148                    mode.finish();
149                }
150            });
151        }
152        addView(mCloseButton);
153
154        final Context context = getContext();
155        final Menu menu = mode.getMenu();
156        final int itemCount = menu.size();
157        for (int i = 0; i < itemCount; i++) {
158            final MenuItem item = menu.getItem(i);
159            final ImageButton button = new ImageButton(context, null,
160                    com.android.internal.R.attr.actionButtonStyle);
161            button.setClickable(true);
162            button.setFocusable(true);
163            button.setImageDrawable(item.getIcon());
164            button.setId(item.getItemId());
165            button.setVisibility(item.isVisible() ? VISIBLE : GONE);
166            button.setEnabled(item.isEnabled());
167
168            button.setOnClickListener(new OnClickListener() {
169                public void onClick(View v) {
170                    implMode.dispatchOnContextItemClicked(item);
171                }
172            });
173
174            addView(button);
175        }
176        requestLayout();
177    }
178
179    public void closeMode() {
180        removeAllViews();
181        mCustomView = null;
182    }
183
184    @Override
185    protected LayoutParams generateDefaultLayoutParams() {
186        // Used by custom views if they don't supply layout params. Everything else
187        // added to an ActionBarContextView should have them already.
188        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
189    }
190
191    @Override
192    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
193        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
194        if (widthMode != MeasureSpec.EXACTLY) {
195            throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
196                    "with android:layout_width=\"match_parent\" (or fill_parent)");
197        }
198
199        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
200        if (heightMode != MeasureSpec.AT_MOST) {
201            throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
202                    "with android:layout_height=\"wrap_content\"");
203        }
204
205        final int contentWidth = MeasureSpec.getSize(widthMeasureSpec);
206        final int itemMargin = mItemPadding;
207
208        int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight();
209        final int height = mContentHeight - getPaddingTop() - getPaddingBottom();
210        final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
211
212        if (mCloseButton != null) {
213            availableWidth = measureChildView(mCloseButton, availableWidth,
214                    childSpecHeight, itemMargin);
215        }
216
217        if (mTitleLayout != null && mCustomView == null) {
218            availableWidth = measureChildView(mTitleLayout, availableWidth,
219                    childSpecHeight, itemMargin);
220        }
221
222        final int childCount = getChildCount();
223        for (int i = 0; i < childCount; i++) {
224            final View child = getChildAt(i);
225            if (child == mCloseButton || child == mTitleLayout || child == mCustomView) {
226                continue;
227            }
228
229            availableWidth = measureChildView(child, availableWidth, childSpecHeight, itemMargin);
230        }
231
232        if (mCustomView != null) {
233            LayoutParams lp = mCustomView.getLayoutParams();
234            final int customWidthMode = lp.width != LayoutParams.WRAP_CONTENT ?
235                    MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
236            final int customWidth = lp.width >= 0 ?
237                    Math.min(lp.width, availableWidth) : availableWidth;
238            final int customHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
239                    MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
240            final int customHeight = lp.height >= 0 ?
241                    Math.min(lp.height, height) : height;
242            mCustomView.measure(MeasureSpec.makeMeasureSpec(customWidth, customWidthMode),
243                    MeasureSpec.makeMeasureSpec(customHeight, customHeightMode));
244        }
245
246        setMeasuredDimension(contentWidth, mContentHeight);
247    }
248
249    @Override
250    protected void onLayout(boolean changed, int l, int t, int r, int b) {
251        int x = getPaddingLeft();
252        final int y = getPaddingTop();
253        final int contentHeight = b - t - getPaddingTop() - getPaddingBottom();
254        final int itemMargin = mItemPadding;
255
256        if (mCloseButton != null && mCloseButton.getVisibility() != GONE) {
257            x += positionChild(mCloseButton, x, y, contentHeight);
258        }
259
260        if (mTitleLayout != null && mCustomView == null) {
261            x += positionChild(mTitleLayout, x, y, contentHeight) + itemMargin;
262        }
263
264        if (mCustomView != null) {
265            x += positionChild(mCustomView, x, y, contentHeight) + itemMargin;
266        }
267
268        x = r - l - getPaddingRight();
269
270        final int childCount = getChildCount();
271        for (int i = 0; i < childCount; i++) {
272            final View child = getChildAt(i);
273            if (child == mCloseButton || child == mTitleLayout || child == mCustomView) {
274                continue;
275            }
276
277            x -= positionChildInverse(child, x, y, contentHeight) + itemMargin;
278        }
279    }
280
281    private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) {
282        child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
283                childSpecHeight);
284
285        availableWidth -= child.getMeasuredWidth();
286        availableWidth -= spacing;
287
288        return availableWidth;
289    }
290
291    private int positionChild(View child, int x, int y, int contentHeight) {
292        int childWidth = child.getMeasuredWidth();
293        int childHeight = child.getMeasuredHeight();
294        int childTop = y + (contentHeight - childHeight) / 2;
295
296        child.layout(x, childTop, x + childWidth, childTop + childHeight);
297
298        return childWidth;
299    }
300
301    private int positionChildInverse(View child, int x, int y, int contentHeight) {
302        int childWidth = child.getMeasuredWidth();
303        int childHeight = child.getMeasuredHeight();
304        int childTop = y + (contentHeight - childHeight) / 2;
305
306        child.layout(x - childWidth, childTop, x, childTop + childHeight);
307
308        return childWidth;
309    }
310}
311