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