1 /* 2 * Copyright (C) 2012 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.animation.Animator; 20 import android.animation.Animator.AnimatorListener; 21 import android.animation.AnimatorListenerAdapter; 22 import android.content.Context; 23 import android.content.res.Configuration; 24 import android.graphics.Canvas; 25 import android.graphics.drawable.Drawable; 26 import android.util.AttributeSet; 27 import android.view.LayoutInflater; 28 import android.view.MotionEvent; 29 import android.view.View; 30 import android.view.View.OnClickListener; 31 import android.view.View.OnTouchListener; 32 import android.view.ViewGroup; 33 import android.widget.LinearLayout; 34 35 import com.android.camera.R; 36 import com.android.gallery3d.common.ApiHelper; 37 38 public class CameraSwitcher extends RotateImageView 39 implements OnClickListener, OnTouchListener { 40 41 private static final String TAG = "CAM_Switcher"; 42 private static final int SWITCHER_POPUP_ANIM_DURATION = 200; 43 44 public interface CameraSwitchListener { onCameraSelected(int i)45 public void onCameraSelected(int i); onShowSwitcherPopup()46 public void onShowSwitcherPopup(); 47 } 48 49 private CameraSwitchListener mListener; 50 private int mCurrentIndex; 51 private int[] mModuleIds; 52 private int[] mDrawIds; 53 private int mItemSize; 54 private View mPopup; 55 private View mParent; 56 private boolean mShowingPopup; 57 private boolean mNeedsAnimationSetup; 58 private Drawable mIndicator; 59 60 private float mTranslationX = 0; 61 private float mTranslationY = 0; 62 63 private AnimatorListener mHideAnimationListener; 64 private AnimatorListener mShowAnimationListener; 65 CameraSwitcher(Context context)66 public CameraSwitcher(Context context) { 67 super(context); 68 init(context); 69 } 70 CameraSwitcher(Context context, AttributeSet attrs)71 public CameraSwitcher(Context context, AttributeSet attrs) { 72 super(context, attrs); 73 init(context); 74 } 75 init(Context context)76 private void init(Context context) { 77 mItemSize = context.getResources().getDimensionPixelSize(R.dimen.switcher_size); 78 setOnClickListener(this); 79 mIndicator = context.getResources().getDrawable(R.drawable.ic_switcher_menu_indicator); 80 } 81 setIds(int[] moduleids, int[] drawids)82 public void setIds(int[] moduleids, int[] drawids) { 83 mDrawIds = drawids; 84 mModuleIds = moduleids; 85 } 86 setCurrentIndex(int i)87 public void setCurrentIndex(int i) { 88 mCurrentIndex = i; 89 setImageResource(mDrawIds[i]); 90 } 91 setSwitchListener(CameraSwitchListener l)92 public void setSwitchListener(CameraSwitchListener l) { 93 mListener = l; 94 } 95 96 @Override onClick(View v)97 public void onClick(View v) { 98 showSwitcher(); 99 mListener.onShowSwitcherPopup(); 100 } 101 onCameraSelected(int ix)102 private void onCameraSelected(int ix) { 103 hidePopup(); 104 if ((ix != mCurrentIndex) && (mListener != null)) { 105 setCurrentIndex(ix); 106 mListener.onCameraSelected(mModuleIds[ix]); 107 } 108 } 109 110 @Override onDraw(Canvas canvas)111 protected void onDraw(Canvas canvas) { 112 super.onDraw(canvas); 113 mIndicator.setBounds(getDrawable().getBounds()); 114 mIndicator.draw(canvas); 115 } 116 initPopup()117 private void initPopup() { 118 mParent = LayoutInflater.from(getContext()).inflate(R.layout.switcher_popup, 119 (ViewGroup) getParent()); 120 LinearLayout content = (LinearLayout) mParent.findViewById(R.id.content); 121 mPopup = content; 122 mPopup.setVisibility(View.INVISIBLE); 123 mNeedsAnimationSetup = true; 124 for (int i = mDrawIds.length - 1; i >= 0; i--) { 125 RotateImageView item = new RotateImageView(getContext()); 126 item.setImageResource(mDrawIds[i]); 127 item.setBackgroundResource(R.drawable.bg_pressed); 128 final int index = i; 129 item.setOnClickListener(new OnClickListener() { 130 @Override 131 public void onClick(View v) { 132 onCameraSelected(index); 133 } 134 }); 135 switch (mDrawIds[i]) { 136 case R.drawable.ic_switch_camera: 137 item.setContentDescription(getContext().getResources().getString( 138 R.string.accessibility_switch_to_camera)); 139 break; 140 case R.drawable.ic_switch_video: 141 item.setContentDescription(getContext().getResources().getString( 142 R.string.accessibility_switch_to_video)); 143 break; 144 case R.drawable.ic_switch_pan: 145 item.setContentDescription(getContext().getResources().getString( 146 R.string.accessibility_switch_to_panorama)); 147 break; 148 case R.drawable.ic_switch_photosphere: 149 item.setContentDescription(getContext().getResources().getString( 150 R.string.accessibility_switch_to_new_panorama)); 151 break; 152 default: 153 break; 154 } 155 content.addView(item, new LinearLayout.LayoutParams(mItemSize, mItemSize)); 156 } 157 } 158 showsPopup()159 public boolean showsPopup() { 160 return mShowingPopup; 161 } 162 isInsidePopup(MotionEvent evt)163 public boolean isInsidePopup(MotionEvent evt) { 164 if (!showsPopup()) return false; 165 return evt.getX() >= mPopup.getLeft() 166 && evt.getX() < mPopup.getRight() 167 && evt.getY() >= mPopup.getTop() 168 && evt.getY() < mPopup.getBottom(); 169 } 170 hidePopup()171 private void hidePopup() { 172 mShowingPopup = false; 173 setVisibility(View.VISIBLE); 174 if (mPopup != null && !animateHidePopup()) { 175 mPopup.setVisibility(View.INVISIBLE); 176 } 177 mParent.setOnTouchListener(null); 178 } 179 showSwitcher()180 private void showSwitcher() { 181 mShowingPopup = true; 182 if (mPopup == null) { 183 initPopup(); 184 } 185 mPopup.setVisibility(View.VISIBLE); 186 if (!animateShowPopup()) { 187 setVisibility(View.INVISIBLE); 188 } 189 mParent.setOnTouchListener(this); 190 } 191 192 @Override onTouch(View v, MotionEvent event)193 public boolean onTouch(View v, MotionEvent event) { 194 closePopup(); 195 return true; 196 } 197 closePopup()198 public void closePopup() { 199 if (showsPopup()) { 200 hidePopup(); 201 } 202 } 203 204 @Override setOrientation(int degree, boolean animate)205 public void setOrientation(int degree, boolean animate) { 206 super.setOrientation(degree, animate); 207 ViewGroup content = (ViewGroup) mPopup; 208 if (content == null) return; 209 for (int i = 0; i < content.getChildCount(); i++) { 210 RotateImageView iv = (RotateImageView) content.getChildAt(i); 211 iv.setOrientation(degree, animate); 212 } 213 } 214 updateInitialTranslations()215 private void updateInitialTranslations() { 216 if (getResources().getConfiguration().orientation 217 == Configuration.ORIENTATION_PORTRAIT) { 218 mTranslationX = -getWidth() / 2; 219 mTranslationY = getHeight(); 220 } else { 221 mTranslationX = getWidth(); 222 mTranslationY = getHeight() / 2; 223 } 224 } popupAnimationSetup()225 private void popupAnimationSetup() { 226 if (!ApiHelper.HAS_VIEW_PROPERTY_ANIMATOR) { 227 return; 228 } 229 updateInitialTranslations(); 230 mPopup.setScaleX(0.3f); 231 mPopup.setScaleY(0.3f); 232 mPopup.setTranslationX(mTranslationX); 233 mPopup.setTranslationY(mTranslationY); 234 mNeedsAnimationSetup = false; 235 } 236 animateHidePopup()237 private boolean animateHidePopup() { 238 if (!ApiHelper.HAS_VIEW_PROPERTY_ANIMATOR) { 239 return false; 240 } 241 if (mHideAnimationListener == null) { 242 mHideAnimationListener = new AnimatorListenerAdapter() { 243 @Override 244 public void onAnimationEnd(Animator animation) { 245 // Verify that we weren't canceled 246 if (!showsPopup()) { 247 mPopup.setVisibility(View.INVISIBLE); 248 } 249 } 250 }; 251 } 252 mPopup.animate() 253 .alpha(0f) 254 .scaleX(0.3f).scaleY(0.3f) 255 .translationX(mTranslationX) 256 .translationY(mTranslationY) 257 .setDuration(SWITCHER_POPUP_ANIM_DURATION) 258 .setListener(mHideAnimationListener); 259 animate().alpha(1f).setDuration(SWITCHER_POPUP_ANIM_DURATION) 260 .setListener(null); 261 return true; 262 } 263 animateShowPopup()264 private boolean animateShowPopup() { 265 if (!ApiHelper.HAS_VIEW_PROPERTY_ANIMATOR) { 266 return false; 267 } 268 if (mNeedsAnimationSetup) { 269 popupAnimationSetup(); 270 } 271 if (mShowAnimationListener == null) { 272 mShowAnimationListener = new AnimatorListenerAdapter() { 273 @Override 274 public void onAnimationEnd(Animator animation) { 275 // Verify that we weren't canceled 276 if (showsPopup()) { 277 setVisibility(View.INVISIBLE); 278 } 279 } 280 }; 281 } 282 mPopup.animate() 283 .alpha(1f) 284 .scaleX(1f).scaleY(1f) 285 .translationX(0) 286 .translationY(0) 287 .setDuration(SWITCHER_POPUP_ANIM_DURATION) 288 .setListener(null); 289 animate().alpha(0f).setDuration(SWITCHER_POPUP_ANIM_DURATION) 290 .setListener(mShowAnimationListener); 291 return true; 292 } 293 } 294