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 
17 package com.android.camera.ui;
18 
19 import android.content.Context;
20 import android.graphics.Canvas;
21 import android.graphics.Typeface;
22 import android.graphics.drawable.Drawable;
23 import android.util.AttributeSet;
24 import android.view.MotionEvent;
25 import android.widget.FrameLayout;
26 import android.widget.TextView;
27 
28 import com.android.camera.util.ApiHelper;
29 import 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  */
44 class 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 {
onVisibleWidthChanged(int width)59         public void onVisibleWidthChanged(int width);
60     }
61 
ModeSelectorItem(Context context, AttributeSet attrs)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
onFinishInflate()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 
setDefaultBackgroundColor(int color)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      */
setVisibleWidthChangedListener(VisibleWidthChangedListener listener)93     public void setVisibleWidthChangedListener(VisibleWidthChangedListener listener) {
94         mListener = listener;
95     }
96 
97     @Override
setSelected(boolean selected)98     public void setSelected(boolean selected) {
99         mIcon.setSelected(selected);
100     }
101 
102     @Override
dispatchTouchEvent(MotionEvent ev)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
onTouchEvent(MotionEvent ev)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      */
onSwipeModeChanged(boolean swipeIn)123     public void onSwipeModeChanged(boolean swipeIn) {
124         mText.setTranslationX(0);
125     }
126 
setText(CharSequence text)127     public void setText(CharSequence text) {
128         mText.setText(text);
129     }
130 
131     @Override
onLayout(boolean changed, int left, int top, int right, int bottom)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      */
setImageResource(int resource)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      */
setVisibleWidth(int newWidth)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      */
getVisibleWidth()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
draw(Canvas canvas)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      */
setHighlightColor(int highlightColor)215     public void setHighlightColor(int highlightColor) {
216         mIcon.setHighlightColor(highlightColor);
217     }
218 
219     /**
220      * @return highlightColor color for the highlight state
221      */
getHighlightColor()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      */
getMaxVisibleWidth()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      */
getIconCenterLocationInWindow(int[] loc)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      */
setModeId(int modeId)250     public void setModeId(int modeId) {
251         mModeId = modeId;
252     }
253 
254     /**
255      * Gets the mode id of the current item.
256      */
getModeId()257     public int getModeId() {
258         return mModeId;
259     }
260 
261     /**
262      * @return The {@link ModeIconView} attached to this item.
263      */
getIcon()264     public ModeIconView getIcon() {
265         return mIcon;
266     }
267 
268     /**
269      * Sets the alpha on the mode text.
270      */
setTextAlpha(float alpha)271     public void setTextAlpha(float alpha) {
272         mText.setAlpha(alpha);
273     }
274 }
275