OSDN Git Service

add a11y announcement when multi toggle button changes
[android-x86/packages-apps-Camera2.git] / src / com / android / camera / MultiToggleImageButton.java
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;
18
19 import android.content.Context;
20 import android.content.res.TypedArray;
21 import android.graphics.drawable.Drawable;
22 import android.util.AttributeSet;
23 import android.widget.ImageButton;
24 import android.view.View;
25 import android.view.accessibility.AccessibilityEvent;
26
27 import com.android.camera2.R;
28
29 /*
30  * A toggle button that supports two or more states with images rendererd on top
31  * for each state.
32  * The button is initialized in an XML layout file with an array reference of
33  * image ids (e.g. imageIds="@array/camera_flashmode_icons").
34  * Each image in the referenced array represents a single integer state.
35  * Every time the user touches the button it gets set to next state in line,
36  * with the corresponding image drawn onto the face of the button.
37  * State wraps back to 0 on user touch when button is already at n-1 state.
38  */
39 public class MultiToggleImageButton extends ImageButton {
40     /*
41      * Listener inteface for button state changes.
42      */
43     public interface OnStateChangeListener {
44         /*
45          * @param view the MultiToggleImageButton that received the touch event
46          * @param state the new state the button is in
47          */
48         public abstract void stateChanged(View view, int state);
49     }
50
51     private OnStateChangeListener mOnStateChangeListener;
52     private int mState;
53     private int[] mImageIds;
54     private int[] mDescIds;
55     private int mLevel;
56
57     public MultiToggleImageButton(Context context) {
58         super(context);
59         init();
60     }
61
62     public MultiToggleImageButton(Context context, AttributeSet attrs) {
63         super(context, attrs);
64         init();
65         parseAttributes(context, attrs);
66         setState(0);
67     }
68
69     public MultiToggleImageButton(Context context, AttributeSet attrs, int defStyle) {
70         super(context, attrs, defStyle);
71         init();
72         parseAttributes(context, attrs);
73         setState(0);
74     }
75
76     /*
77      * Set the state change listener.
78      *
79      * @param onStateChangeListener the listener to set
80      */
81     public void setOnStateChangeListener(OnStateChangeListener onStateChangeListener) {
82         mOnStateChangeListener = onStateChangeListener;
83     }
84
85     /*
86      * Get the current button state.
87      *
88      */
89     public int getState() {
90         return mState;
91     }
92
93     /*
94      * Set the current button state, thus causing the state change listener to
95      * get called.
96      *
97      * @param state the desired state
98      */
99     public void setState(int state) {
100         setState(state, true);
101     }
102
103     /*
104      * Set the current button state.
105      *
106      * @param state the desired state
107      * @param callListener should the state change listener be called?
108      */
109     public void setState(int state, boolean callListener) {
110         mState = state;
111         setImageResource(mImageIds[mState]);
112         String oldContentDescription = String.valueOf(getContentDescription());
113         String newContentDescription = getResources().getString(mDescIds[mState]);
114         if (oldContentDescription != null && !oldContentDescription.isEmpty()
115                 && !oldContentDescription.equals(newContentDescription)) {
116             setContentDescription(newContentDescription);
117             String announceChange = getResources().getString(
118                     R.string.button_change_announcement, newContentDescription);
119             announceForAccessibility(announceChange);
120         }
121         super.setImageLevel(mLevel);
122         if (callListener && mOnStateChangeListener != null) {
123             mOnStateChangeListener.stateChanged(this, getState());
124         }
125     }
126
127     private void nextState() {
128         int state = mState + 1;
129         if (state >= mImageIds.length) {
130             state = 0;
131         }
132         setState(state);
133     }
134
135     protected void init() {
136         this.setOnClickListener(new View.OnClickListener() {
137             @Override
138             public void onClick(View v) {
139                 nextState();
140             }
141         });
142     }
143
144     private void parseAttributes(Context context, AttributeSet attrs) {
145         TypedArray a = context.getTheme().obtainStyledAttributes(
146             attrs,
147             R.styleable.MultiToggleImageButton,
148             0, 0);
149         int imageIds = a.getResourceId(R.styleable.MultiToggleImageButton_imageIds, 0);
150         overrideImageIds(imageIds);
151
152         int descIds = a.getResourceId(R.styleable.MultiToggleImageButton_contentDescriptionIds, 0);
153         overrideContentDescriptions(descIds);
154
155         a.recycle();
156     }
157
158     /**
159      * Override the image ids of this button.
160      */
161     public void overrideImageIds(int resId) {
162         TypedArray ids = null;
163         try {
164             ids = getResources().obtainTypedArray(resId);
165             mImageIds = new int[ids.length()];
166             for (int i = 0; i < ids.length(); i++) {
167                 mImageIds[i] = ids.getResourceId(i, 0);
168             }
169         } finally {
170             if (ids != null) {
171                 ids.recycle();
172             }
173         }
174     }
175
176     /**
177      * Override the content descriptions of this button.
178      */
179     public void overrideContentDescriptions(int resId) {
180         TypedArray ids = null;
181         try {
182             ids = getResources().obtainTypedArray(resId);
183             mDescIds = new int[ids.length()];
184             for (int i = 0; i < ids.length(); i++) {
185                 mDescIds[i] = ids.getResourceId(i, 0);
186             }
187         } finally {
188             if (ids != null) {
189                 ids.recycle();
190             }
191         }
192     }
193
194     @Override
195     public void setImageLevel(int level) {
196         super.setImageLevel(level);
197         mLevel = level;
198     }
199 }