Merge commit '42b2e5ca519766e37ce6941ba4faecc9691cc403' into upstream
[debian/openrocket] / android-libraries / ActionBarSherlock / src / com / actionbarsherlock / internal / widget / ActionBarContextView.java
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/ActionBarContextView.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/ActionBarContextView.java
new file mode 100644 (file)
index 0000000..9ec250f
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.actionbarsherlock.internal.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.actionbarsherlock.R;
+import com.actionbarsherlock.internal.nineoldandroids.animation.Animator;
+import com.actionbarsherlock.internal.nineoldandroids.animation.Animator.AnimatorListener;
+import com.actionbarsherlock.internal.nineoldandroids.animation.AnimatorSet;
+import com.actionbarsherlock.internal.nineoldandroids.animation.ObjectAnimator;
+import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy;
+import com.actionbarsherlock.internal.nineoldandroids.widget.NineLinearLayout;
+import com.actionbarsherlock.internal.view.menu.ActionMenuPresenter;
+import com.actionbarsherlock.internal.view.menu.ActionMenuView;
+import com.actionbarsherlock.internal.view.menu.MenuBuilder;
+import com.actionbarsherlock.view.ActionMode;
+
+/**
+ * @hide
+ */
+public class ActionBarContextView extends AbsActionBarView implements AnimatorListener {
+    //UNUSED private static final String TAG = "ActionBarContextView";
+
+    private CharSequence mTitle;
+    private CharSequence mSubtitle;
+
+    private NineLinearLayout mClose;
+    private View mCustomView;
+    private LinearLayout mTitleLayout;
+    private TextView mTitleView;
+    private TextView mSubtitleView;
+    private int mTitleStyleRes;
+    private int mSubtitleStyleRes;
+    private Drawable mSplitBackground;
+
+    private Animator mCurrentAnimation;
+    private boolean mAnimateInOnLayout;
+    private int mAnimationMode;
+
+    private static final int ANIMATE_IDLE = 0;
+    private static final int ANIMATE_IN = 1;
+    private static final int ANIMATE_OUT = 2;
+
+    public ActionBarContextView(Context context) {
+        this(context, null);
+    }
+
+    public ActionBarContextView(Context context, AttributeSet attrs) {
+        this(context, attrs, R.attr.actionModeStyle);
+    }
+
+    public ActionBarContextView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SherlockActionMode, defStyle, 0);
+        setBackgroundDrawable(a.getDrawable(
+                R.styleable.SherlockActionMode_background));
+        mTitleStyleRes = a.getResourceId(
+                R.styleable.SherlockActionMode_titleTextStyle, 0);
+        mSubtitleStyleRes = a.getResourceId(
+                R.styleable.SherlockActionMode_subtitleTextStyle, 0);
+
+        mContentHeight = a.getLayoutDimension(
+                R.styleable.SherlockActionMode_height, 0);
+
+        mSplitBackground = a.getDrawable(
+                R.styleable.SherlockActionMode_backgroundSplit);
+
+        a.recycle();
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        if (mActionMenuPresenter != null) {
+            mActionMenuPresenter.hideOverflowMenu();
+            mActionMenuPresenter.hideSubMenus();
+        }
+    }
+
+    @Override
+    public void setSplitActionBar(boolean split) {
+        if (mSplitActionBar != split) {
+            if (mActionMenuPresenter != null) {
+                // Mode is already active; move everything over and adjust the menu itself.
+                final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
+                        LayoutParams.MATCH_PARENT);
+                if (!split) {
+                    mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
+                    mMenuView.setBackgroundDrawable(null);
+                    final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
+                    if (oldParent != null) oldParent.removeView(mMenuView);
+                    addView(mMenuView, layoutParams);
+                } else {
+                    // Allow full screen width in split mode.
+                    mActionMenuPresenter.setWidthLimit(
+                            getContext().getResources().getDisplayMetrics().widthPixels, true);
+                    // No limit to the item count; use whatever will fit.
+                    mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
+                    // Span the whole width
+                    layoutParams.width = LayoutParams.MATCH_PARENT;
+                    layoutParams.height = mContentHeight;
+                    mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
+                    mMenuView.setBackgroundDrawable(mSplitBackground);
+                    final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
+                    if (oldParent != null) oldParent.removeView(mMenuView);
+                    mSplitView.addView(mMenuView, layoutParams);
+                }
+            }
+            super.setSplitActionBar(split);
+        }
+    }
+
+    public void setContentHeight(int height) {
+        mContentHeight = height;
+    }
+
+    public void setCustomView(View view) {
+        if (mCustomView != null) {
+            removeView(mCustomView);
+        }
+        mCustomView = view;
+        if (mTitleLayout != null) {
+            removeView(mTitleLayout);
+            mTitleLayout = null;
+        }
+        if (view != null) {
+            addView(view);
+        }
+        requestLayout();
+    }
+
+    public void setTitle(CharSequence title) {
+        mTitle = title;
+        initTitle();
+    }
+
+    public void setSubtitle(CharSequence subtitle) {
+        mSubtitle = subtitle;
+        initTitle();
+    }
+
+    public CharSequence getTitle() {
+        return mTitle;
+    }
+
+    public CharSequence getSubtitle() {
+        return mSubtitle;
+    }
+
+    private void initTitle() {
+        if (mTitleLayout == null) {
+            LayoutInflater inflater = LayoutInflater.from(getContext());
+            inflater.inflate(R.layout.abs__action_bar_title_item, this);
+            mTitleLayout = (LinearLayout) getChildAt(getChildCount() - 1);
+            mTitleView = (TextView) mTitleLayout.findViewById(R.id.abs__action_bar_title);
+            mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.abs__action_bar_subtitle);
+            if (mTitleStyleRes != 0) {
+                mTitleView.setTextAppearance(mContext, mTitleStyleRes);
+            }
+            if (mSubtitleStyleRes != 0) {
+                mSubtitleView.setTextAppearance(mContext, mSubtitleStyleRes);
+            }
+        }
+
+        mTitleView.setText(mTitle);
+        mSubtitleView.setText(mSubtitle);
+
+        final boolean hasTitle = !TextUtils.isEmpty(mTitle);
+        final boolean hasSubtitle = !TextUtils.isEmpty(mSubtitle);
+        mSubtitleView.setVisibility(hasSubtitle ? VISIBLE : GONE);
+        mTitleLayout.setVisibility(hasTitle || hasSubtitle ? VISIBLE : GONE);
+        if (mTitleLayout.getParent() == null) {
+            addView(mTitleLayout);
+        }
+    }
+
+    public void initForMode(final ActionMode mode) {
+        if (mClose == null) {
+            LayoutInflater inflater = LayoutInflater.from(mContext);
+            mClose = (NineLinearLayout)inflater.inflate(R.layout.abs__action_mode_close_item, this, false);
+            addView(mClose);
+        } else if (mClose.getParent() == null) {
+            addView(mClose);
+        }
+
+        View closeButton = mClose.findViewById(R.id.abs__action_mode_close_button);
+        closeButton.setOnClickListener(new OnClickListener() {
+            public void onClick(View v) {
+                mode.finish();
+            }
+        });
+
+        final MenuBuilder menu = (MenuBuilder) mode.getMenu();
+        if (mActionMenuPresenter != null) {
+            mActionMenuPresenter.dismissPopupMenus();
+        }
+        mActionMenuPresenter = new ActionMenuPresenter(mContext);
+        mActionMenuPresenter.setReserveOverflow(true);
+
+        final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
+                LayoutParams.MATCH_PARENT);
+        if (!mSplitActionBar) {
+            menu.addMenuPresenter(mActionMenuPresenter);
+            mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
+            mMenuView.setBackgroundDrawable(null);
+            addView(mMenuView, layoutParams);
+        } else {
+            // Allow full screen width in split mode.
+            mActionMenuPresenter.setWidthLimit(
+                    getContext().getResources().getDisplayMetrics().widthPixels, true);
+            // No limit to the item count; use whatever will fit.
+            mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
+            // Span the whole width
+            layoutParams.width = LayoutParams.MATCH_PARENT;
+            layoutParams.height = mContentHeight;
+            menu.addMenuPresenter(mActionMenuPresenter);
+            mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
+            mMenuView.setBackgroundDrawable(mSplitBackground);
+            mSplitView.addView(mMenuView, layoutParams);
+        }
+
+        mAnimateInOnLayout = true;
+    }
+
+    public void closeMode() {
+        if (mAnimationMode == ANIMATE_OUT) {
+            // Called again during close; just finish what we were doing.
+            return;
+        }
+        if (mClose == null) {
+            killMode();
+            return;
+        }
+
+        finishAnimation();
+        mAnimationMode = ANIMATE_OUT;
+        mCurrentAnimation = makeOutAnimation();
+        mCurrentAnimation.start();
+    }
+
+    private void finishAnimation() {
+        final Animator a = mCurrentAnimation;
+        if (a != null) {
+            mCurrentAnimation = null;
+            a.end();
+        }
+    }
+
+    public void killMode() {
+        finishAnimation();
+        removeAllViews();
+        if (mSplitView != null) {
+            mSplitView.removeView(mMenuView);
+        }
+        mCustomView = null;
+        mMenuView = null;
+        mAnimateInOnLayout = false;
+    }
+
+    @Override
+    public boolean showOverflowMenu() {
+        if (mActionMenuPresenter != null) {
+            return mActionMenuPresenter.showOverflowMenu();
+        }
+        return false;
+    }
+
+    @Override
+    public boolean hideOverflowMenu() {
+        if (mActionMenuPresenter != null) {
+            return mActionMenuPresenter.hideOverflowMenu();
+        }
+        return false;
+    }
+
+    @Override
+    public boolean isOverflowMenuShowing() {
+        if (mActionMenuPresenter != null) {
+            return mActionMenuPresenter.isOverflowMenuShowing();
+        }
+        return false;
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+        // Used by custom views if they don't supply layout params. Everything else
+        // added to an ActionBarContextView should have them already.
+        return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new MarginLayoutParams(getContext(), attrs);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        if (widthMode != MeasureSpec.EXACTLY) {
+            throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
+                    "with android:layout_width=\"match_parent\" (or fill_parent)");
+        }
+
+        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        if (heightMode == MeasureSpec.UNSPECIFIED) {
+            throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
+                    "with android:layout_height=\"wrap_content\"");
+        }
+
+        final int contentWidth = MeasureSpec.getSize(widthMeasureSpec);
+
+        int maxHeight = mContentHeight > 0 ?
+                mContentHeight : MeasureSpec.getSize(heightMeasureSpec);
+
+        final int verticalPadding = getPaddingTop() + getPaddingBottom();
+        int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight();
+        final int height = maxHeight - verticalPadding;
+        final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
+
+        if (mClose != null) {
+            availableWidth = measureChildView(mClose, availableWidth, childSpecHeight, 0);
+            MarginLayoutParams lp = (MarginLayoutParams) mClose.getLayoutParams();
+            availableWidth -= lp.leftMargin + lp.rightMargin;
+        }
+
+        if (mMenuView != null && mMenuView.getParent() == this) {
+            availableWidth = measureChildView(mMenuView, availableWidth,
+                    childSpecHeight, 0);
+        }
+
+        if (mTitleLayout != null && mCustomView == null) {
+            availableWidth = measureChildView(mTitleLayout, availableWidth, childSpecHeight, 0);
+        }
+
+        if (mCustomView != null) {
+            ViewGroup.LayoutParams lp = mCustomView.getLayoutParams();
+            final int customWidthMode = lp.width != LayoutParams.WRAP_CONTENT ?
+                    MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
+            final int customWidth = lp.width >= 0 ?
+                    Math.min(lp.width, availableWidth) : availableWidth;
+            final int customHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
+                    MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
+            final int customHeight = lp.height >= 0 ?
+                    Math.min(lp.height, height) : height;
+            mCustomView.measure(MeasureSpec.makeMeasureSpec(customWidth, customWidthMode),
+                    MeasureSpec.makeMeasureSpec(customHeight, customHeightMode));
+        }
+
+        if (mContentHeight <= 0) {
+            int measuredHeight = 0;
+            final int count = getChildCount();
+            for (int i = 0; i < count; i++) {
+                View v = getChildAt(i);
+                int paddedViewHeight = v.getMeasuredHeight() + verticalPadding;
+                if (paddedViewHeight > measuredHeight) {
+                    measuredHeight = paddedViewHeight;
+                }
+            }
+            setMeasuredDimension(contentWidth, measuredHeight);
+        } else {
+            setMeasuredDimension(contentWidth, maxHeight);
+        }
+    }
+
+    private Animator makeInAnimation() {
+        mClose.setTranslationX(-mClose.getWidth() -
+                ((MarginLayoutParams) mClose.getLayoutParams()).leftMargin);
+        ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX", 0);
+        buttonAnimator.setDuration(200);
+        buttonAnimator.addListener(this);
+        buttonAnimator.setInterpolator(new DecelerateInterpolator());
+
+        AnimatorSet set = new AnimatorSet();
+        AnimatorSet.Builder b = set.play(buttonAnimator);
+
+        if (mMenuView != null) {
+            final int count = mMenuView.getChildCount();
+            if (count > 0) {
+                for (int i = count - 1, j = 0; i >= 0; i--, j++) {
+                    AnimatorProxy child = AnimatorProxy.wrap(mMenuView.getChildAt(i));
+                    child.setScaleY(0);
+                    ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0, 1);
+                    a.setDuration(100);
+                    a.setStartDelay(j * 70);
+                    b.with(a);
+                }
+            }
+        }
+
+        return set;
+    }
+
+    private Animator makeOutAnimation() {
+        ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX",
+                -mClose.getWidth() - ((MarginLayoutParams) mClose.getLayoutParams()).leftMargin);
+        buttonAnimator.setDuration(200);
+        buttonAnimator.addListener(this);
+        buttonAnimator.setInterpolator(new DecelerateInterpolator());
+
+        AnimatorSet set = new AnimatorSet();
+        AnimatorSet.Builder b = set.play(buttonAnimator);
+
+        if (mMenuView != null) {
+            final int count = mMenuView.getChildCount();
+            if (count > 0) {
+                for (int i = 0; i < 0; i++) {
+                    AnimatorProxy child = AnimatorProxy.wrap(mMenuView.getChildAt(i));
+                    child.setScaleY(0);
+                    ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0);
+                    a.setDuration(100);
+                    a.setStartDelay(i * 70);
+                    b.with(a);
+                }
+            }
+        }
+
+        return set;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        int x = getPaddingLeft();
+        final int y = getPaddingTop();
+        final int contentHeight = b - t - getPaddingTop() - getPaddingBottom();
+
+        if (mClose != null && mClose.getVisibility() != GONE) {
+            MarginLayoutParams lp = (MarginLayoutParams) mClose.getLayoutParams();
+            x += lp.leftMargin;
+            x += positionChild(mClose, x, y, contentHeight);
+            x += lp.rightMargin;
+
+            if (mAnimateInOnLayout) {
+                mAnimationMode = ANIMATE_IN;
+                mCurrentAnimation = makeInAnimation();
+                mCurrentAnimation.start();
+                mAnimateInOnLayout = false;
+            }
+        }
+
+        if (mTitleLayout != null && mCustomView == null) {
+            x += positionChild(mTitleLayout, x, y, contentHeight);
+        }
+
+        if (mCustomView != null) {
+            x += positionChild(mCustomView, x, y, contentHeight);
+        }
+
+        x = r - l - getPaddingRight();
+
+        if (mMenuView != null) {
+            x -= positionChildInverse(mMenuView, x, y, contentHeight);
+        }
+    }
+
+    @Override
+    public void onAnimationStart(Animator animation) {
+    }
+
+    @Override
+    public void onAnimationEnd(Animator animation) {
+        if (mAnimationMode == ANIMATE_OUT) {
+            killMode();
+        }
+        mAnimationMode = ANIMATE_IDLE;
+    }
+
+    @Override
+    public void onAnimationCancel(Animator animation) {
+    }
+
+    @Override
+    public void onAnimationRepeat(Animator animation) {
+    }
+
+    @Override
+    public boolean shouldDelayChildPressedState() {
+        return false;
+    }
+
+    @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
+            // Action mode started
+            //TODO event.setSource(this);
+            event.setClassName(getClass().getName());
+            event.setPackageName(getContext().getPackageName());
+            event.setContentDescription(mTitle);
+        } else {
+            //TODO super.onInitializeAccessibilityEvent(event);
+        }
+    }
+}