1/*
2 * Copyright (C) 2013 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 com.android.camera.ui;
18
19import android.content.Context;
20import android.graphics.Canvas;
21import android.graphics.Typeface;
22import android.graphics.drawable.Drawable;
23import android.util.AttributeSet;
24import android.view.MotionEvent;
25import android.widget.FrameLayout;
26import android.widget.TextView;
27
28import com.android.camera.util.ApiHelper;
29import com.android.camera2.R;
30
31/**
32 * This is a package private class, as it is not intended to be visible or used
33 * outside of this package.
34 *
35 * ModeSelectorItem is a FrameLayout that contains an ImageView to display the
36 * icon for the corresponding mode, a TextView that explains what the mode is,
37 * and a GradientDrawable at the end of the TextView.
38 *
39 * The purpose of this class is to encapsulate different drawing logic into
40 * its own class. There are two drawing mode, <code>FLY_IN</code>
41 * and <code>FLY_OUT</code>. They define how we draw the view when
42 * we display the view partially.
43 */
44class ModeSelectorItem extends FrameLayout {
45    private TextView mText;
46    private ModeIconView mIcon;
47    private int mVisibleWidth = 0;
48    private final int mMinVisibleWidth;
49    private VisibleWidthChangedListener mListener = null;
50
51    private int mWidth;
52    private int mModeId;
53
54    /**
55     * A listener that gets notified when the visible width of the current item
56     * is changed.
57     */
58    public interface VisibleWidthChangedListener {
59        public void onVisibleWidthChanged(int width);
60    }
61
62    public ModeSelectorItem(Context context, AttributeSet attrs) {
63        super(context, attrs);
64        setWillNotDraw(false);
65        setClickable(true);
66        mMinVisibleWidth = getResources()
67                .getDimensionPixelSize(R.dimen.mode_selector_icon_block_width);
68    }
69
70    @Override
71    public void onFinishInflate() {
72        mIcon = (ModeIconView) findViewById(R.id.selector_icon);
73        mText = (TextView) findViewById(R.id.selector_text);
74        Typeface typeface;
75        if (ApiHelper.HAS_ROBOTO_MEDIUM_FONT) {
76            typeface = Typeface.create("sans-serif-medium", Typeface.NORMAL);
77        } else {
78            // Load roboto_light typeface from assets.
79            typeface = Typeface.createFromAsset(getResources().getAssets(),
80                    "Roboto-Medium.ttf");
81        }
82        mText.setTypeface(typeface);
83    }
84
85    public void setDefaultBackgroundColor(int color) {
86        setBackgroundColor(color);
87    }
88
89    /**
90     * Sets a listener that receives a callback when the visible width of this
91     * selector item changes.
92     */
93    public void setVisibleWidthChangedListener(VisibleWidthChangedListener listener) {
94        mListener = listener;
95    }
96
97    @Override
98    public void setSelected(boolean selected) {
99        mIcon.setSelected(selected);
100    }
101
102    @Override
103    public boolean dispatchTouchEvent(MotionEvent ev) {
104        // Do not dispatch any touch event, so that all the events that are received
105        // in onTouchEvent() are only through forwarding.
106         return false;
107    }
108
109    @Override
110    public boolean onTouchEvent(MotionEvent ev) {
111        super.onTouchEvent(ev);
112        return false;
113    }
114
115    /**
116     * When swiping in, we truncate the end of the item if the visible width
117     * is not enough to show the whole item. When swiping out, we truncate the
118     * front of the text (i.e. offset the text).
119     *
120     * @param swipeIn whether swiping direction is swiping in (i.e. from left
121     *                to right)
122     */
123    public void onSwipeModeChanged(boolean swipeIn) {
124        mText.setTranslationX(0);
125    }
126
127    public void setText(CharSequence text) {
128        mText.setText(text);
129    }
130
131    @Override
132    public void onLayout(boolean changed, int left, int top, int right, int bottom) {
133        super.onLayout(changed, left, top, right, bottom);
134        mWidth = right - left;
135        if (changed && mVisibleWidth > 0) {
136            // Reset mode list to full screen
137            setVisibleWidth(mWidth);
138        }
139    }
140
141    /**
142     * Sets image resource as the icon for the mode. By default, all drawables instances
143     * loaded from the same resource share a common state; if you modify the state
144     * of one instance, all the other instances will receive the same modification.
145     * In order to modify properties of this icon drawable without affecting other
146     * drawables, here we use a mutable drawable which is guaranteed to not share
147     * states with other drawables.
148     *
149     * @param resource resource id of the asset to be used as icon
150     */
151    public void setImageResource(int resource) {
152        Drawable drawableIcon = getResources().getDrawable(resource);
153        if (drawableIcon != null) {
154            drawableIcon = drawableIcon.mutate();
155        }
156        mIcon.setIconDrawable(drawableIcon);
157    }
158
159    /**
160     * Sets the visible width preferred for the item. The item can then decide how
161     * to draw itself based on the visible width and whether it's being swiped in
162     * or out. This function will be called on every frame during animation. It should
163     * only do minimal work required to get the animation working.
164     *
165     * @param newWidth new visible width
166     */
167    public void setVisibleWidth(int newWidth) {
168        int fullyShownIconWidth = getMaxVisibleWidth();
169        newWidth = Math.max(newWidth, 0);
170        // Visible width should not be greater than view width
171        newWidth = Math.min(newWidth, fullyShownIconWidth);
172
173        if (mVisibleWidth != newWidth) {
174            mVisibleWidth = newWidth;
175            if (mListener != null) {
176                mListener.onVisibleWidthChanged(newWidth);
177            }
178        }
179        invalidate();
180    }
181
182    /**
183     * Getter for visible width. This function will get called during animation as
184     * well.
185     *
186     * @return The visible width of this item
187     */
188    public int getVisibleWidth() {
189        return mVisibleWidth;
190    }
191
192    /**
193     * Draw the view based on the drawing mode. Clip the canvas if necessary.
194     *
195     * @param canvas The Canvas to which the View is rendered.
196     */
197    @Override
198    public void draw(Canvas canvas) {
199        float transX = 0f;
200        // If the given width is less than the icon width, we need to translate icon
201        if (mVisibleWidth < mMinVisibleWidth + mIcon.getLeft()) {
202            transX = mMinVisibleWidth + mIcon.getLeft() - mVisibleWidth;
203        }
204        canvas.save();
205        canvas.translate(-transX, 0);
206        super.draw(canvas);
207        canvas.restore();
208    }
209
210    /**
211     * Sets the color that will be used in the drawable for highlight state.
212     *
213     * @param highlightColor color for the highlight state
214     */
215    public void setHighlightColor(int highlightColor) {
216        mIcon.setHighlightColor(highlightColor);
217    }
218
219    /**
220     * @return highlightColor color for the highlight state
221     */
222    public int getHighlightColor() {
223        return mIcon.getHighlightColor();
224    }
225
226    /**
227     * Gets the maximum visible width of the mode icon. The mode item will be
228     * full shown when the mode icon has max visible width.
229     */
230    public int getMaxVisibleWidth() {
231        return mIcon.getLeft() + mMinVisibleWidth;
232    }
233
234    /**
235     * Gets the position of the icon center relative to the window.
236     *
237     * @param loc integer array of size 2, to hold the position x and y
238     */
239    public void getIconCenterLocationInWindow(int[] loc) {
240        mIcon.getLocationInWindow(loc);
241        loc[0] += mMinVisibleWidth / 2;
242        loc[1] += mMinVisibleWidth / 2;
243    }
244
245    /**
246     * Sets the mode id of the current item.
247     *
248     * @param modeId id of the mode represented by current item.
249     */
250    public void setModeId(int modeId) {
251        mModeId = modeId;
252    }
253
254    /**
255     * Gets the mode id of the current item.
256     */
257    public int getModeId() {
258        return mModeId;
259    }
260
261    /**
262     * @return The {@link ModeIconView} attached to this item.
263     */
264    public ModeIconView getIcon() {
265        return mIcon;
266    }
267
268    /**
269     * Sets the alpha on the mode text.
270     */
271    public void setTextAlpha(float alpha) {
272        mText.setAlpha(alpha);
273    }
274}
275