[go: nahoru, domu]

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 */
16
17package android.support.v7.widget;
18
19import android.content.Context;
20import android.os.Build;
21import android.support.v7.appcompat.R;
22import android.support.v7.view.ActionMode;
23import android.support.v7.view.menu.MenuBuilder;
24import android.text.TextUtils;
25import android.util.AttributeSet;
26import android.view.LayoutInflater;
27import android.view.View;
28import android.view.ViewGroup;
29import android.view.accessibility.AccessibilityEvent;
30import android.widget.LinearLayout;
31import android.widget.TextView;
32
33/**
34 * @hide
35 */
36public class ActionBarContextView extends AbsActionBarView {
37    private static final String TAG = "ActionBarContextView";
38
39    private CharSequence mTitle;
40    private CharSequence mSubtitle;
41
42    private View mClose;
43    private View mCustomView;
44    private LinearLayout mTitleLayout;
45    private TextView mTitleView;
46    private TextView mSubtitleView;
47    private int mTitleStyleRes;
48    private int mSubtitleStyleRes;
49    private boolean mTitleOptional;
50    private int mCloseItemLayout;
51
52    public ActionBarContextView(Context context) {
53        this(context, null);
54    }
55
56    public ActionBarContextView(Context context, AttributeSet attrs) {
57        this(context, attrs, R.attr.actionModeStyle);
58    }
59
60    public ActionBarContextView(Context context, AttributeSet attrs, int defStyle) {
61        super(context, attrs, defStyle);
62
63        final TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
64                R.styleable.ActionMode, defStyle, 0);
65        setBackgroundDrawable(a.getDrawable(
66                R.styleable.ActionMode_background));
67        mTitleStyleRes = a.getResourceId(
68                R.styleable.ActionMode_titleTextStyle, 0);
69        mSubtitleStyleRes = a.getResourceId(
70                R.styleable.ActionMode_subtitleTextStyle, 0);
71
72        mContentHeight = a.getLayoutDimension(
73                R.styleable.ActionMode_height, 0);
74
75        mCloseItemLayout = a.getResourceId(
76                R.styleable.ActionMode_closeItemLayout,
77                R.layout.abc_action_mode_close_item_material);
78
79        a.recycle();
80    }
81
82    @Override
83    public void onDetachedFromWindow() {
84        super.onDetachedFromWindow();
85        if (mActionMenuPresenter != null) {
86            mActionMenuPresenter.hideOverflowMenu();
87            mActionMenuPresenter.hideSubMenus();
88        }
89    }
90
91    public void setContentHeight(int height) {
92        mContentHeight = height;
93    }
94
95    public void setCustomView(View view) {
96        if (mCustomView != null) {
97            removeView(mCustomView);
98        }
99        mCustomView = view;
100        if (view != null && mTitleLayout != null) {
101            removeView(mTitleLayout);
102            mTitleLayout = null;
103        }
104        if (view != null) {
105            addView(view);
106        }
107        requestLayout();
108    }
109
110    public void setTitle(CharSequence title) {
111        mTitle = title;
112        initTitle();
113    }
114
115    public void setSubtitle(CharSequence subtitle) {
116        mSubtitle = subtitle;
117        initTitle();
118    }
119
120    public CharSequence getTitle() {
121        return mTitle;
122    }
123
124    public CharSequence getSubtitle() {
125        return mSubtitle;
126    }
127
128    private void initTitle() {
129        if (mTitleLayout == null) {
130            LayoutInflater inflater = LayoutInflater.from(getContext());
131            inflater.inflate(R.layout.abc_action_bar_title_item, this);
132            mTitleLayout = (LinearLayout) getChildAt(getChildCount() - 1);
133            mTitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_title);
134            mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_subtitle);
135            if (mTitleStyleRes != 0) {
136                mTitleView.setTextAppearance(getContext(), mTitleStyleRes);
137            }
138            if (mSubtitleStyleRes != 0) {
139                mSubtitleView.setTextAppearance(getContext(), mSubtitleStyleRes);
140            }
141        }
142
143        mTitleView.setText(mTitle);
144        mSubtitleView.setText(mSubtitle);
145
146        final boolean hasTitle = !TextUtils.isEmpty(mTitle);
147        final boolean hasSubtitle = !TextUtils.isEmpty(mSubtitle);
148        mSubtitleView.setVisibility(hasSubtitle ? VISIBLE : GONE);
149        mTitleLayout.setVisibility(hasTitle || hasSubtitle ? VISIBLE : GONE);
150        if (mTitleLayout.getParent() == null) {
151            addView(mTitleLayout);
152        }
153    }
154
155    public void initForMode(final ActionMode mode) {
156        if (mClose == null) {
157            LayoutInflater inflater = LayoutInflater.from(getContext());
158            mClose = inflater.inflate(mCloseItemLayout, this, false);
159            addView(mClose);
160        } else if (mClose.getParent() == null) {
161            addView(mClose);
162        }
163
164        View closeButton = mClose.findViewById(R.id.action_mode_close_button);
165        closeButton.setOnClickListener(new OnClickListener() {
166            public void onClick(View v) {
167                mode.finish();
168            }
169        });
170
171        final MenuBuilder menu = (MenuBuilder) mode.getMenu();
172        if (mActionMenuPresenter != null) {
173            mActionMenuPresenter.dismissPopupMenus();
174        }
175        mActionMenuPresenter = new ActionMenuPresenter(getContext());
176        mActionMenuPresenter.setReserveOverflow(true);
177
178        final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
179                LayoutParams.MATCH_PARENT);
180        menu.addMenuPresenter(mActionMenuPresenter, mPopupContext);
181        mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
182        mMenuView.setBackgroundDrawable(null);
183        addView(mMenuView, layoutParams);
184    }
185
186    public void closeMode() {
187        if (mClose == null) {
188            killMode();
189            return;
190        }
191    }
192
193    public void killMode() {
194        removeAllViews();
195        mCustomView = null;
196        mMenuView = null;
197    }
198
199    @Override
200    public boolean showOverflowMenu() {
201        if (mActionMenuPresenter != null) {
202            return mActionMenuPresenter.showOverflowMenu();
203        }
204        return false;
205    }
206
207    @Override
208    public boolean hideOverflowMenu() {
209        if (mActionMenuPresenter != null) {
210            return mActionMenuPresenter.hideOverflowMenu();
211        }
212        return false;
213    }
214
215    @Override
216    public boolean isOverflowMenuShowing() {
217        if (mActionMenuPresenter != null) {
218            return mActionMenuPresenter.isOverflowMenuShowing();
219        }
220        return false;
221    }
222
223    @Override
224    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
225        // Used by custom views if they don't supply layout params. Everything else
226        // added to an ActionBarContextView should have them already.
227        return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
228    }
229
230    @Override
231    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
232        return new MarginLayoutParams(getContext(), attrs);
233    }
234
235    @Override
236    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
237        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
238        if (widthMode != MeasureSpec.EXACTLY) {
239            throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
240                    "with android:layout_width=\"match_parent\" (or fill_parent)");
241        }
242
243        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
244        if (heightMode == MeasureSpec.UNSPECIFIED) {
245            throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
246                    "with android:layout_height=\"wrap_content\"");
247        }
248
249        final int contentWidth = MeasureSpec.getSize(widthMeasureSpec);
250
251        int maxHeight = mContentHeight > 0 ?
252                mContentHeight : MeasureSpec.getSize(heightMeasureSpec);
253
254        final int verticalPadding = getPaddingTop() + getPaddingBottom();
255        int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight();
256        final int height = maxHeight - verticalPadding;
257        final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
258
259        if (mClose != null) {
260            availableWidth = measureChildView(mClose, availableWidth, childSpecHeight, 0);
261            MarginLayoutParams lp = (MarginLayoutParams) mClose.getLayoutParams();
262            availableWidth -= lp.leftMargin + lp.rightMargin;
263        }
264
265        if (mMenuView != null && mMenuView.getParent() == this) {
266            availableWidth = measureChildView(mMenuView, availableWidth,
267                    childSpecHeight, 0);
268        }
269
270        if (mTitleLayout != null && mCustomView == null) {
271            if (mTitleOptional) {
272                final int titleWidthSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
273                mTitleLayout.measure(titleWidthSpec, childSpecHeight);
274                final int titleWidth = mTitleLayout.getMeasuredWidth();
275                final boolean titleFits = titleWidth <= availableWidth;
276                if (titleFits) {
277                    availableWidth -= titleWidth;
278                }
279                mTitleLayout.setVisibility(titleFits ? VISIBLE : GONE);
280            } else {
281                availableWidth = measureChildView(mTitleLayout, availableWidth, childSpecHeight, 0);
282            }
283        }
284
285        if (mCustomView != null) {
286            ViewGroup.LayoutParams lp = mCustomView.getLayoutParams();
287            final int customWidthMode = lp.width != LayoutParams.WRAP_CONTENT ?
288                    MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
289            final int customWidth = lp.width >= 0 ?
290                    Math.min(lp.width, availableWidth) : availableWidth;
291            final int customHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
292                    MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
293            final int customHeight = lp.height >= 0 ?
294                    Math.min(lp.height, height) : height;
295            mCustomView.measure(MeasureSpec.makeMeasureSpec(customWidth, customWidthMode),
296                    MeasureSpec.makeMeasureSpec(customHeight, customHeightMode));
297        }
298
299        if (mContentHeight <= 0) {
300            int measuredHeight = 0;
301            final int count = getChildCount();
302            for (int i = 0; i < count; i++) {
303                View v = getChildAt(i);
304                int paddedViewHeight = v.getMeasuredHeight() + verticalPadding;
305                if (paddedViewHeight > measuredHeight) {
306                    measuredHeight = paddedViewHeight;
307                }
308            }
309            setMeasuredDimension(contentWidth, measuredHeight);
310        } else {
311            setMeasuredDimension(contentWidth, maxHeight);
312        }
313    }
314
315    @Override
316    protected void onLayout(boolean changed, int l, int t, int r, int b) {
317        final boolean isLayoutRtl = ViewUtils.isLayoutRtl(this);
318        int x = isLayoutRtl ? r - l - getPaddingRight() : getPaddingLeft();
319        final int y = getPaddingTop();
320        final int contentHeight = b - t - getPaddingTop() - getPaddingBottom();
321
322        if (mClose != null && mClose.getVisibility() != GONE) {
323            MarginLayoutParams lp = (MarginLayoutParams) mClose.getLayoutParams();
324            final int startMargin = (isLayoutRtl ? lp.rightMargin : lp.leftMargin);
325            final int endMargin = (isLayoutRtl ? lp.leftMargin : lp.rightMargin);
326            x = next(x, startMargin, isLayoutRtl);
327            x += positionChild(mClose, x, y, contentHeight, isLayoutRtl);
328            x = next(x, endMargin, isLayoutRtl);
329        }
330
331        if (mTitleLayout != null && mCustomView == null && mTitleLayout.getVisibility() != GONE) {
332            x += positionChild(mTitleLayout, x, y, contentHeight, isLayoutRtl);
333        }
334
335        if (mCustomView != null) {
336            x += positionChild(mCustomView, x, y, contentHeight, isLayoutRtl);
337        }
338
339        x = isLayoutRtl ? getPaddingLeft() : r - l - getPaddingRight();
340
341        if (mMenuView != null) {
342            x += positionChild(mMenuView, x, y, contentHeight, !isLayoutRtl);
343        }
344    }
345
346    @Override
347    public boolean shouldDelayChildPressedState() {
348        return false;
349    }
350
351    @Override
352    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
353        if (Build.VERSION.SDK_INT >= 14) {
354            if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
355                // Action mode started
356                event.setSource(this);
357                event.setClassName(getClass().getName());
358                event.setPackageName(getContext().getPackageName());
359                event.setContentDescription(mTitle);
360            } else {
361                super.onInitializeAccessibilityEvent(event);
362            }
363        }
364    }
365
366    public void setTitleOptional(boolean titleOptional) {
367        if (titleOptional != mTitleOptional) {
368            requestLayout();
369        }
370        mTitleOptional = titleOptional;
371    }
372
373    public boolean isTitleOptional() {
374        return mTitleOptional;
375    }
376}
377