package com.android.camera; import java.util.ArrayList; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import com.android.camera.Camera; import com.android.camera.R; public class FocusRectangle extends View { @SuppressWarnings("unused") private static final String TAG = "FocusRectangle"; private static final String ONE_FINGER_TOUCHED = "one_finger_touch"; private static final String TWO_FINGER_TOUCHED = "two_finger_touch"; private static final String THREE_FINGER_TOUCHED = "three_finger_touch"; private static final String MULTI_TOUCH_MODE = android.hardware.Camera.Parameters.FOCUS_MODE_AUTO_MULTI; private static final String AUTO_MODE = android.hardware.Camera.Parameters.FOCUS_MODE_AUTO; private static final String MACRO_MODE = android.hardware.Camera.Parameters.FOCUS_MODE_MACRO; private static final int UPDATE_VIEW_DELAYED = 1; private static final int CLEAR_FOCUS_STATE = 2; private String touchCount = ONE_FINGER_TOUCHED; private ArrayList<Pointer> mPointers = new ArrayList<FocusRectangle.Pointer>(3); private String mMode = AUTO_MODE; private boolean resetToDefault = false; private Camera mCameraSwitch = null; private boolean isFocus = false; private boolean multiFocusModeSupported; private Handler handler = new UpdateHandler(); public FocusRectangle(Context context, AttributeSet attrs) { super(context, attrs); Pointer pointer = new Pointer(); pointer.updatePointBitmap(false); mPointers.add(pointer); resetToDefault = true; } public void setCamera(Camera camera){ mCameraSwitch = camera; } public String getMode(){ return mMode; } public void setMode(String mode) { if(mMode.equals(mode)){ return; } mMode = mode; if (mMode.equals(MULTI_TOUCH_MODE)) { reset(); Pointer pointer1 = mPointers.get(0); if(mPointers.size() == 1){ Pointer pointer = new Pointer(); pointer.updatePointBitmap(false); pointer.x = pointer1.x; pointer.y = pointer1.y; mPointers.add(pointer); } if(mPointers.size() == 2){ Pointer pointer = new Pointer(); pointer.updatePointBitmap(false); pointer.x = pointer1.x; pointer.y = pointer1.y; mPointers.add(pointer); } invalidate(); return; } while(mPointers.size() > 1){ Pointer pointer = mPointers.get(mPointers.size() - 1); pointer.clear(); mPointers.remove(pointer); pointer = null; } reset(); invalidate(); } public ArrayList<Pointer> getPointers(){ int count = 0; if(ONE_FINGER_TOUCHED.equals(touchCount) && mPointers.size() > 0) count = 1; else if (TWO_FINGER_TOUCHED.equals(touchCount)){ count = mPointers.size(); count = count > 2 ? 2 : count; } else if(THREE_FINGER_TOUCHED.equals(touchCount)){ count = mPointers.size(); count = count > 3 ? 3 : count; } if(!MULTI_TOUCH_MODE.equals(mMode)) count = count > 1 ? 1 : count; ArrayList<Pointer> pointers = new ArrayList<Pointer>(); for(int i = 0; i < count; i++){ Pointer p = new Pointer(); Pointer p1 = mPointers.get(i); p.x = p1.x; p.y = p1.y; pointers.add(p); } return pointers; } private void setDrawable(int resid) { setBackgroundDrawable(getResources().getDrawable(resid)); } public void showStart() { if(!multiFocusModeSupported){ setDrawable(R.drawable.focus_focusing); return; } for(int i = 0; i < mPointers.size(); ++i){ Pointer pointer = mPointers.get(i); pointer.showStart(); } invalidate(); } public void showSuccess() { if(!multiFocusModeSupported){ setDrawable(R.drawable.focus_focused); return; } for(int i = 0; i < mPointers.size(); ++i){ Pointer pointer = mPointers.get(i); pointer.showSuccess(); } invalidate(); } public void showFail() { if(!multiFocusModeSupported){ setDrawable(R.drawable.focus_focus_failed); return; } for(int i = 0; i < mPointers.size(); ++i){ Pointer pointer = mPointers.get(i); pointer.showFail(); } invalidate(); } public void clear() { if(!multiFocusModeSupported){ setBackgroundDrawable(null); return; } invalidate(); } private boolean isEqual(float x1, float y1, float x2, float y2) { boolean flag = false; double distance = (x1 - y1) * (x1 - y1) + (x2 - y2) * (x2 - y2); if (Math.sqrt(distance) == 0) { flag = true; } return flag; } public void reset() { resetToDefault = true; Pointer pointer1 = mPointers.get(0); pointer1.x = getWidth() / 2; pointer1.y = getHeight() / 2; if (!mMode.equals(MULTI_TOUCH_MODE)) { return; } for(int i = 1; i < mPointers.size(); ++ i){ final Pointer pointer = mPointers.get(i); pointer.x = getWidth() / 2; pointer.y = getHeight() / 2; } } @Override protected void onDraw(Canvas canvas) { if(!multiFocusModeSupported){ super.onDraw(canvas); return; } Pointer pointer1 = mPointers.get(0); float halfWidth = pointer1.getDistanceFromLeftToCenter(); float halfHeight = pointer1.getDistanceFromTopToCenter(); if (resetToDefault) { // add for bug pointers x = 0 && y = 0 at init //fixed 15641 int width = getWidth(); int height = getHeight(); pointer1.x = width / 2; pointer1.y = height / 2; int screenWidth = mCameraSwitch.getWindowManager().getDefaultDisplay().getWidth(); int screenHeight = mCameraSwitch.getWindowManager().getDefaultDisplay().getHeight(); if (width > screenWidth) { width = screenWidth; } if (height > screenHeight) { height = screenHeight; } Bitmap bitmap = pointer1.getShowBitmap(); if(bitmap != null && !bitmap.isRecycled()){ canvas.drawBitmap(bitmap, width / 2 - halfWidth, height / 2 - halfHeight, pointer1.getPaint()); } return; } Bitmap bitmap = pointer1.getShowBitmap(); if(bitmap != null && !bitmap.isRecycled()){ canvas.drawBitmap(pointer1.getShowBitmap(), pointer1.x - halfWidth, pointer1.y - halfHeight, pointer1.getPaint()); } if (!mMode.equals(MULTI_TOUCH_MODE)) return; if (!touchCount.equals(ONE_FINGER_TOUCHED) && mPointers.size() > 1) { Pointer pointer2 = mPointers.get(1); Bitmap showBm = pointer2.getShowBitmap(); if(showBm != null){ float halfWidth2 = pointer2.getDistanceFromLeftToCenter(); float halfHeight2 = pointer2.getDistanceFromTopToCenter(); canvas.drawBitmap(showBm, pointer2.x - halfWidth2, pointer2.y - halfHeight2, pointer2.getPaint()); } } if (touchCount.equals(THREE_FINGER_TOUCHED) && mPointers.size() > 2) { Pointer pointer3 = mPointers.get(2); Bitmap showBm = pointer3.getShowBitmap(); if(showBm != null){ float halfWidth3 = pointer3.getDistanceFromLeftToCenter(); float halfHeight3 = pointer3.getDistanceFromTopToCenter(); canvas.drawBitmap(showBm, pointer3.x - halfWidth3, pointer3.y - halfHeight3, pointer3.getPaint()); } } } boolean isTouch = false; @Override public boolean onTouchEvent(MotionEvent event) { //fixed bug 17024 /*if(!multiFocusModeSupported){ isTouch = false; return isTouch; }*/ if(mCameraSwitch.isFocusing()) return isTouch; resetToDefault = false; if(isFocus) return isTouch; if (!mMode.equals(MULTI_TOUCH_MODE)) { onSingleTouchEvent(event); invalidate(); return isTouch; } onMultiTouchEvent(event); invalidate(); return isTouch; } @SuppressWarnings("deprecation") private void onMultiTouchEvent(MotionEvent event) { // fixed bug 19284 start // int action = event.getAction(); // float dx1 = event.getX(0); // float dy1 = event.getY(0); // // float dx2 = event.getX(1); // float dy2 = event.getY(1); // // float dx3 = event.getX(2); // float dy3 = event.getY(2); // // Pointer pointer1 = mPointers.get(0); // Pointer pointer2 = mPointers.get(1); // Pointer pointer3 = mPointers.get(2); int action = event.getAction(); float dx1, dy1, dx2, dy2, dx3, dy3; Pointer pointer1, pointer2, pointer3; try { dx1 = event.getX(0); dy1 = event.getY(0); pointer1 = mPointers.get(0); dx2 = event.getX(1); dy2 = event.getY(1); pointer2 = mPointers.get(1); dx3 = event.getX(2); dy3 = event.getY(2); pointer3 = mPointers.get(2); } catch (ArrayIndexOutOfBoundsException e) { Log.d(TAG, String.format("onMultiTouchEvent() failed, action = %d", action), e); return; } // fixed bug 19284 end switch (action) { case MotionEvent.ACTION_DOWN: Log.v(TAG, "onMultiTouchEvent: ACTION_DOWN"); touchCount = ONE_FINGER_TOUCHED; multiTouchDown(event); break; case MotionEvent.ACTION_UP: Log.v(TAG, "onMultiTouchEvent: ACTION_UP"); multiTouchUp(event); break; case MotionEvent.ACTION_POINTER_1_DOWN: Log.v(TAG, "onMultiTouchEvent: ACTION_POINTER_1_DOWN"); setPointer(dx1, dy1, pointer1); pointer1.touched = true; pointer1.updatePointBitmap(true); break; case MotionEvent.ACTION_POINTER_1_UP: Log.v(TAG, "onMultiTouchEvent: ACTION_POINTER_1_UP"); pointer1.touched = false; pointer1.updatePointBitmap(false); break; case MotionEvent.ACTION_POINTER_2_DOWN: Log.v(TAG, "onMultiTouchEvent: ACTION_POINTER_2_DOWN"); if(touchCount != THREE_FINGER_TOUCHED){ touchCount = TWO_FINGER_TOUCHED; } if (pointer2.touched && (isEqual(dx1, dy1, dx2, dy2) == false || isEqual(dx2,dy2, dx3, dy3) == false)) { setPointer(dx2, dy2, pointer2); } pointer2.touched = true; pointer2.updatePointBitmap(true); break; case MotionEvent.ACTION_POINTER_2_UP: Log.v(TAG, "onMultiTouchEvent: ACTION_POINTER_2_UP"); pointer2.touched = false; pointer2.updatePointBitmap(false); break; case MotionEvent.ACTION_POINTER_3_DOWN: Log.v(TAG, "onMultiTouchEvent: ACTION_POINTER_3_DOWN"); touchCount = THREE_FINGER_TOUCHED; if ((isEqual(dx1, dy1, dx3, dy3) == false || isEqual(dx2, dy2, dx3,dy3) == false)) { setPointer(dx3, dy3, pointer3); } pointer3.touched = true; pointer3.updatePointBitmap(true); break; case MotionEvent.ACTION_POINTER_3_UP: Log.v(TAG, "onMultiTouchEvent: ACTION_POINTER_3_UP"); pointer3.touched = false; pointer3.updatePointBitmap(false); break; case MotionEvent.ACTION_MOVE: // Log.v(TAG, "ACTION_MOVE: x1 = " + mPointer1.x + " , y1 = " + mPointer1.y + ", x2 = " + mPointer2.x + " , y2 = " + mPointer2.y // + " ,x3 = " + pointer3.x + " ,y3 = " + pointer3.y); if (pointer1.touched && (isEqual(dx1, dy1, dx2, dy2) == false || isEqual(dx1, dy1, dx3, dy3) == false)) { setPointer(dx1, dy1, pointer1); } if (pointer2.touched && (isEqual(dx1, dy1, dx2, dy2) == false || isEqual(dx2,dy2, dx3, dy3) == false)) { setPointer(dx2, dy2, pointer2); } // System.out.println("111 dx3" + dx3 + " dy3 = " + dy3 + " dx1 = " + dx1 + " dy1 = " + dy1); if (pointer3.touched && (isEqual(dx1, dy1, dx3, dy3) == false || isEqual(dx2,dy2, dx3, dy3) == false)) { if(pointer2.touched == false){ setPointer(dx2, dy2, pointer3); return; } setPointer(dx3, dy3, pointer3); // System.out.println("222dx3" + dx3 + " dy3 = " + dy3 + " dx1 = " + dx1 + " dy1 = " + dy1); } break; default: break; } } private void multiTouchUp(MotionEvent event) { for(int i = 0; i < mPointers.size(); ++i){ Pointer pointer = mPointers.get(i); pointer.touched = false; pointer.updatePointBitmap(false); } isTouch = false; if (handler.hasMessages(UPDATE_VIEW_DELAYED)) { handler.removeMessages(UPDATE_VIEW_DELAYED); } handler.sendEmptyMessageDelayed(UPDATE_VIEW_DELAYED, 200); isFocus = true; } private void multiTouchDown(MotionEvent event) { mCameraSwitch.cancelAutoFocus(); resetToDefault = false; Pointer pointer = mPointers.get(0); setPointer(event.getX(0), event.getY(0), pointer); pointer.touched = true; pointer.updatePointBitmap(true); isTouch = true; } private void onSingleTouchEvent(MotionEvent event) { int action = event.getAction(); float x = event.getX(); float y = event.getY(); switch (action) { case MotionEvent.ACTION_DOWN: Log.v(TAG, "onTouchEvent: ACTION_DOWN"); singleTouchDown(event, x, y); break; case MotionEvent.ACTION_UP: Log.v(TAG, "onTouchEvent: ACTION_UP"); singleTouchUp(event, x, y); break; case MotionEvent.ACTION_MOVE: singleTouchMove(event, x, y); break; default: break; } } private void singleTouchMove(MotionEvent event, float x, float y) { Pointer pointer = mPointers.get(0); setPointer(x, y, pointer); } private void singleTouchUp(MotionEvent event, float x, float y) { Pointer pointer = mPointers.get(0); setPointer(x, y, pointer); pointer.touched = false; pointer.updatePointBitmap(false); isTouch = false; if (handler.hasMessages(UPDATE_VIEW_DELAYED)) { handler.removeMessages(UPDATE_VIEW_DELAYED); } handler.sendEmptyMessageDelayed(UPDATE_VIEW_DELAYED, 200); isFocus = true; } private void setPointer(float x, float y, Pointer p){ if(x < 0) p.x = 0; else if(x >= getWidth()) p.x = getWidth() - 1; else p.x = x; if(y < 0) p.y = 0; else if(y >= getHeight()) p.y = getHeight() - 1; else p.y = y; } private boolean singleTouchDown(MotionEvent event, float x, float y) { mCameraSwitch.cancelAutoFocus(); isTouch = true; Pointer pointer = mPointers.get(0); pointer.touched = true; pointer.x = x; pointer.y = y; pointer.updatePointBitmap(true); return true; } public class Pointer { public float x; public float y; public boolean touched; private Bitmap downBm; private Bitmap upBm; private Bitmap showBm; private Paint mPaint = new Paint(); public Bitmap updatePointBitmap(boolean touch) { if (touch) { if (downBm == null || downBm.isRecycled()) { downBm = getBitmap(R.drawable.focus_focusing); Bitmap temp = downBm; downBm = Bitmap.createScaledBitmap( downBm , downBm .getWidth() * 3 / 2 , downBm .getHeight() * 3 / 2 , true ); temp.recycle(); } showBm = downBm; return showBm; } if (upBm == null || upBm.isRecycled()) { upBm = getBitmap(R.drawable.focus_focusing); } showBm = upBm; return showBm; } public Paint getPaint(){ return mPaint; } public void showFail() { Bitmap bm = showBm; showBm = getBitmap(R.drawable.focus_focus_failed); if(bm != showBm){ bm.recycle(); bm = null; } } public void showSuccess() { Bitmap bm = showBm; showBm = getBitmap(R.drawable.focus_focused); if(bm != showBm){ bm.recycle(); bm = null; } } public void showStart() { Bitmap bm = showBm; showBm = getBitmap(R.drawable.focus_focusing); if(bm != showBm){ bm.recycle(); bm = null; } } public void clear(){ if(downBm != null && !downBm.isRecycled()){ downBm.recycle(); downBm = null; } if(upBm != null && !upBm.isRecycled()){ upBm.recycle(); upBm = null; } } public float getDistanceFromTopToCenter() { float distance = 0.0f; if (showBm != null) { distance = showBm.getWidth() / 2; } return distance; } public float getDistanceFromLeftToCenter() { float distance = 0.0f; if (showBm != null) { distance = showBm.getHeight() / 2; } return distance; } private Bitmap getShowBitmap() { return showBm; } private Bitmap getBitmap(int resId) { return BitmapFactory.decodeResource(getResources(), resId); } public void recycle() { if (downBm != null && downBm.isRecycled() == false) { downBm.recycle(); downBm = null; } if (upBm != null && upBm.isRecycled() == false) { upBm.recycle(); upBm = null; } } } public void dofocus(){ isTouch = false; if (handler.hasMessages(UPDATE_VIEW_DELAYED)) { handler.removeMessages(UPDATE_VIEW_DELAYED); } handler.sendEmptyMessageDelayed(UPDATE_VIEW_DELAYED, 200); isFocus = true; } class UpdateHandler extends Handler { @Override public void handleMessage(Message msg) { int what = msg.what; switch (what) { case UPDATE_VIEW_DELAYED: //fixed 17024 if(multiFocusModeSupported){ mCameraSwitch.doFocus(true); } if (handler.hasMessages(CLEAR_FOCUS_STATE)) { handler.removeMessages(CLEAR_FOCUS_STATE); } handler.sendMessageDelayed(handler.obtainMessage(CLEAR_FOCUS_STATE), 0); break; case CLEAR_FOCUS_STATE: mCameraSwitch.enableMenu(); isFocus = false; default: break; } super.handleMessage(msg); } } public boolean isMultiFocusModeSupported() { return multiFocusModeSupported; } public void setMultiFocusModeSupported(boolean b) { multiFocusModeSupported = b; } }