MultiToggleImageButton.java revision f80ac9ee5c66671c3a77ac6628fefc86cd39d57e
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; 18 19import android.content.Context; 20import android.content.res.TypedArray; 21import android.graphics.drawable.Drawable; 22import android.util.AttributeSet; 23import android.widget.ImageButton; 24import android.view.View; 25import android.view.accessibility.AccessibilityEvent; 26 27import 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 */ 39public 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 if (mImageIds != null) { 112 setImageResource(mImageIds[mState]); 113 } 114 if (mDescIds != null) { 115 String oldContentDescription = String.valueOf(getContentDescription()); 116 String newContentDescription = getResources().getString(mDescIds[mState]); 117 if (oldContentDescription != null && !oldContentDescription.isEmpty() 118 && !oldContentDescription.equals(newContentDescription)) { 119 setContentDescription(newContentDescription); 120 String announceChange = getResources().getString( 121 R.string.button_change_announcement, newContentDescription); 122 announceForAccessibility(announceChange); 123 } 124 } 125 super.setImageLevel(mLevel); 126 if (callListener && mOnStateChangeListener != null) { 127 mOnStateChangeListener.stateChanged(this, getState()); 128 } 129 } 130 131 private void nextState() { 132 int state = mState + 1; 133 if (state >= mImageIds.length) { 134 state = 0; 135 } 136 setState(state); 137 } 138 139 protected void init() { 140 this.setOnClickListener(new View.OnClickListener() { 141 @Override 142 public void onClick(View v) { 143 nextState(); 144 } 145 }); 146 } 147 148 private void parseAttributes(Context context, AttributeSet attrs) { 149 TypedArray a = context.getTheme().obtainStyledAttributes( 150 attrs, 151 R.styleable.MultiToggleImageButton, 152 0, 0); 153 int imageIds = a.getResourceId(R.styleable.MultiToggleImageButton_imageIds, 0); 154 if (imageIds > 0) { 155 overrideImageIds(imageIds); 156 } 157 int descIds = a.getResourceId(R.styleable.MultiToggleImageButton_contentDescriptionIds, 0); 158 if (descIds > 0) { 159 overrideContentDescriptions(descIds); 160 } 161 a.recycle(); 162 } 163 164 /** 165 * Override the image ids of this button. 166 */ 167 public void overrideImageIds(int resId) { 168 TypedArray ids = null; 169 try { 170 ids = getResources().obtainTypedArray(resId); 171 mImageIds = new int[ids.length()]; 172 for (int i = 0; i < ids.length(); i++) { 173 mImageIds[i] = ids.getResourceId(i, 0); 174 } 175 } finally { 176 if (ids != null) { 177 ids.recycle(); 178 } 179 } 180 } 181 182 /** 183 * Override the content descriptions of this button. 184 */ 185 public void overrideContentDescriptions(int resId) { 186 TypedArray ids = null; 187 try { 188 ids = getResources().obtainTypedArray(resId); 189 mDescIds = new int[ids.length()]; 190 for (int i = 0; i < ids.length(); i++) { 191 mDescIds[i] = ids.getResourceId(i, 0); 192 } 193 } finally { 194 if (ids != null) { 195 ids.recycle(); 196 } 197 } 198 } 199 200 @Override 201 public void setImageLevel(int level) { 202 super.setImageLevel(level); 203 mLevel = level; 204 } 205}