content: /*
  The contents of this file are subject to the Mozilla Public License
  Version 1.1 (the "License"); you may not use this file except in
  compliance with the License. You may obtain a copy of the License at
  http://www.mozilla.org/MPL/
  
  Software distributed under the License is distributed on an "AS IS"
  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
  License for the specific language governing rights and limitations
  under the License.
  
  The Original Code is collection of files collectively known as Open Camera.
  
  The Initial Developer of the Original Code is Almalence Inc.
  Portions created by Initial Developer are Copyright (C) 2013 
  by Almalence Inc. All Rights Reserved.
   */
  
  package com.almalence.plugins.vf.zoom;
  
  import java.util.ArrayList;
  import java.util.List;
  
  import android.content.SharedPreferences;
  import android.graphics.PointF;
  import android.os.Handler;
  import android.os.Message;
  import android.preference.PreferenceManager;
  import android.util.Log;
  import android.view.KeyEvent;
  import android.view.LayoutInflater;
  import android.view.MotionEvent;
  import android.view.ScaleGestureDetector;
  import android.view.View;
  import android.view.ScaleGestureDetector.OnScaleGestureListener;
  import android.view.View.OnTouchListener;
  import android.view.ViewGroup;
  import android.view.ViewGroup.LayoutParams;
  import android.view.animation.Animation;
  import android.view.animation.Animation.AnimationListener;
  import android.view.animation.LinearInterpolator;
  import android.view.animation.TranslateAnimation;
  import android.widget.ImageButton;
  import android.widget.LinearLayout;
  import android.widget.RelativeLayout;
  import android.widget.SeekBar;
  import android.widget.SeekBar.OnSeekBarChangeListener;
  
  import com.almalence.sony.cameraremote.ZoomCallbackSonyRemote;
  import com.almalence.ui.VerticalSeekBar;
  
  /* <!-- +++
   import com.almalence.opencam_plus.ApplicationInterface;
   import com.almalence.opencam_plus.ApplicationScreen;
   import com.almalence.opencam_plus.MainScreen;
   import com.almalence.opencam_plus.PluginViewfinder;
   import com.almalence.opencam_plus.cameracontroller.CameraController;
   import com.almalence.opencam_plus.R;
   +++ --> */
  
  // <!-- -+-
  import com.almalence.opencam.ApplicationInterface;
  import com.almalence.opencam.ApplicationScreen;
  import com.almalence.opencam.MainScreen;
  import com.almalence.opencam.PluginViewfinder;
  import com.almalence.opencam.cameracontroller.CameraController;
  import com.almalence.opencam.R;
  
  //-+- -->
  
  /***
   * Implements zoom functionality - slider, pinch, sound buttons
   ***/
  
  public class ZoomVFPlugin extends PluginViewfinder
  {
  	private VerticalSeekBar			zoomBar				= null;
  	private ImageButton				mButtonZoomIn		= null;
  	private ImageButton				mButtonZoomOut		= null;
  	private float					zoomCurrent			= 0;
  	private View					zoomPanelView		= null;
  	private LinearLayout			zoomPanel			= null;
  
  	private int						mainLayoutHeight	= 0;
  	private int						zoomPanelWidth		= 0;
  
  	private boolean					panelOpened			= false;
  	private boolean					panelToBeOpen		= false;
  	private boolean					panelOpening		= false;
  	private boolean					panelClosing		= false;
  	private boolean					mZoomDisabled		= false;
  
  	private boolean					isEnabled			= true;
  
  	private Handler					zoomHandler;
  	
  	private boolean				zoomStopping			= false;
  	
  	private static final int	CLOSE_ZOOM_PANEL		= 0;
  	private static final int	CLOSE_ZOOM_PANEL_DELAY	= 1500;
  	
  	private class ZoomHandler extends Handler
  	{
  		@Override
  		public void handleMessage(Message msg)
  		{
  			if (msg.what == CLOSE_ZOOM_PANEL)
  				closeZoomPanel();
  		}
  	}
  	
  	private ScaleGestureDetector  scaleGestureDetector;
  
  	public ZoomVFPlugin()
  	{
  		super("com.almalence.plugins.zoomvf",  R.xml.preferences_vf_zoom, 0, 0, null);
  		zoomHandler = new ZoomHandler();
  	}
  
  	@Override
  	public void onCreate()
  	{
  		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(MainScreen.getMainContext());
  		isEnabled = prefs.getBoolean("enabledPrefZoom", true);
  
  		panelOpened = false;
  		
  		LayoutInflater inflator = MainScreen.getInstance().getLayoutInflater();
  		zoomPanelView = inflator.inflate(R.layout.plugin_vf_zoom_layout, null, false);
  		zoomPanel = (LinearLayout) zoomPanelView.findViewById(R.id.zoomLayout);
  		zoomPanel.setOnTouchListener(new OnTouchListener()
  		{
  			@Override
  			public boolean onTouch(View v, MotionEvent event)
  			{
  				return false;
  			}
  		});
  
  		mButtonZoomIn = (ImageButton) zoomPanel.findViewById(R.id.button_zoom_in);
  		mButtonZoomOut = (ImageButton) zoomPanel.findViewById(R.id.button_zoom_out);
  		initZoomButtons();
  		ZoomCallbackSonyRemote zoomCallbackSonyRemote = new ZoomCallbackSonyRemote()
  		{
  			@Override
  			public void onZoomPositionChanged(final int zoomPosition)
  			{
  				MainScreen.getInstance().runOnUiThread(new Runnable()
  				{
  
  					@Override
  					public void run()
  					{
  						if (zoomPosition == 0)
  						{
  							mButtonZoomIn.setEnabled(true);
  							mButtonZoomOut.setEnabled(false);
  						} else if (zoomPosition == 100)
  						{
  							mButtonZoomIn.setEnabled(false);
  							mButtonZoomOut.setEnabled(true);
  						} else
  						{
  							mButtonZoomIn.setEnabled(true);
  							mButtonZoomOut.setEnabled(true);
  						}
  					}
  				});
  
  			}
  
  			@Override
  			public void onZoomAvailabelChanged(final boolean isZoomAvailable)
  			{
  				MainScreen.getInstance().runOnUiThread(new Runnable()
  				{
  					@Override
  					public void run()
  					{
  						prepareActZoomButtons(isZoomAvailable);
  					}
  				});
  			}
  		};
  		CameraController.setZoomCallbackSonyRemote(zoomCallbackSonyRemote);
  		
  		this.zoomBar = (VerticalSeekBar) zoomPanelView.findViewById(R.id.zoomSeekBar);
  		this.zoomBar.setOnTouchListener(new OnTouchListener()
  		{
  			@Override
  			public boolean onTouch(View v, MotionEvent event)
  			{
  				if (mZoomDisabled)
  				{
  					if (panelOpened)
  						zoomHandler.sendEmptyMessageDelayed(CLOSE_ZOOM_PANEL, CLOSE_ZOOM_PANEL_DELAY);
  					return true;
  				}
  
  				switch (event.getAction() & MotionEvent.ACTION_MASK)
  				{
  				case MotionEvent.ACTION_DOWN:
  					{
  						if (!panelOpened)
  						{
  							openZoomPanel();
  							zoomHandler.removeMessages(CLOSE_ZOOM_PANEL);
  							return true;
  						}
  						if (panelClosing)
  						{
  							panelToBeOpen = true;
  							return true;
  						}
  					}
  					break;
  				case MotionEvent.ACTION_UP:
  					{
  						if (panelOpened || panelOpening)
  							zoomHandler.sendEmptyMessageDelayed(CLOSE_ZOOM_PANEL, CLOSE_ZOOM_PANEL_DELAY);
  					}
  					break;
  				case MotionEvent.ACTION_MOVE:
  					return false;
  				default:
  					break;
  				}
  
  				return false;
  			}
  		});
  		this.zoomBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener()
  		{
  
  			@Override
  			public void onStopTrackingTouch(SeekBar seekBar)
  			{
  			}
  
  			@Override
  			public void onStartTrackingTouch(SeekBar seekBar)
  			{
  				zoomHandler.removeMessages(CLOSE_ZOOM_PANEL);
  			}
  
  			@Override
  			public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
  			{
  				if (fromUser)
  				{
  					zoomHandler.removeMessages(CLOSE_ZOOM_PANEL);
  					
  					zoomCurrent = progress;
  					if (CameraController.isUseCamera2())
  					{
  						// Calculate scaleFactor from seekBar progress.
  						zoomCurrent = (float)progress / 10.f + 1.f;
  						Log.e("!!!!!!!", "zoom current caculated = " + zoomCurrent);
  					}
  					
  					if (zoomCurrent > CameraController.getMaxZoom())
  					{
  						zoomCurrent = CameraController.getMaxZoom();
  					}
  
  					//workaround for S7 issue with zooming.
  					if (CameraController.isGalaxyS7 && zoomCurrent>1.2)
  					{
  						zoomCurrent+=0.001f;
  					}
  					
  					CameraController.setZoom(zoomCurrent);
  				}
  			}
  		});
  	}
  
  	private void prepareActZoomButtons(boolean flag)
  	{
  		if (flag)
  		{
  			zoomPanel.setVisibility(View.VISIBLE);
  			mButtonZoomOut.setVisibility(View.VISIBLE);
  			mButtonZoomIn.setVisibility(View.VISIBLE);
  		} else
  		{
  			zoomPanel.setVisibility(View.GONE);
  			mButtonZoomOut.setVisibility(View.GONE);
  			mButtonZoomIn.setVisibility(View.GONE);
  		}
  	}
  
  	private void initZoomButtons()
  	{
  		mButtonZoomIn.setOnClickListener(new View.OnClickListener()
  		{
  
  			@Override
  			public void onClick(View v)
  			{
  				CameraController.actZoomSonyRemote("in", "1shot");
  			}
  		});
  
  		mButtonZoomOut.setOnClickListener(new View.OnClickListener()
  		{
  
  			@Override
  			public void onClick(View v)
  			{
  				CameraController.actZoomSonyRemote("out", "1shot");
  			}
  		});
  
  		mButtonZoomIn.setOnLongClickListener(new View.OnLongClickListener()
  		{
  
  			@Override
  			public boolean onLongClick(View arg0)
  			{
  				CameraController.actZoomSonyRemote("in", "start");
  				return true;
  			}
  		});
  
  		mButtonZoomOut.setOnLongClickListener(new View.OnLongClickListener()
  		{
  
  			@Override
  			public boolean onLongClick(View arg0)
  			{
  				CameraController.actZoomSonyRemote("out", "start");
  				return true;
  			}
  		});
  
  		mButtonZoomIn.setOnTouchListener(new View.OnTouchListener()
  		{
  
  			private long	downTime	= -1;
  
  			@Override
  			public boolean onTouch(View v, MotionEvent event)
  			{
  
  				if (event.getAction() == MotionEvent.ACTION_UP)
  				{
  					if (System.currentTimeMillis() - downTime > 500)
  					{
  						CameraController.actZoomSonyRemote("in", "stop");
  					}
  				}
  				if (event.getAction() == MotionEvent.ACTION_DOWN)
  				{
  					downTime = System.currentTimeMillis();
  				}
  				return false;
  			}
  		});
  
  		mButtonZoomOut.setOnTouchListener(new View.OnTouchListener()
  		{
  
  			private long	downTime	= -1;
  
  			@Override
  			public boolean onTouch(View v, MotionEvent event)
  			{
  
  				if (event.getAction() == MotionEvent.ACTION_UP)
  				{
  					if (System.currentTimeMillis() - downTime > 500)
  					{
  						CameraController.actZoomSonyRemote("out", "stop");
  					}
  				}
  				if (event.getAction() == MotionEvent.ACTION_DOWN)
  				{
  					downTime = System.currentTimeMillis();
  				}
  				return false;
  			}
  		});
  	}
  
  	@Override
  	public void onStart()
  	{
  		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(MainScreen.getMainContext());
  		isEnabled = prefs.getBoolean("enabledPrefZoom", true);
  		zoomStopping = false;
  	}
  
  	@Override
  	public void onStop()
  	{
  		zoomStopping = true;
  		MainScreen.getGUIManager().removeViews(zoomPanel, R.id.specialPluginsLayout);
  	}
  
  	@Override
  	public void onGUICreate()
  	{
  		MainScreen.getGUIManager().removeViews(zoomPanel, R.id.specialPluginsLayout);
  
  		RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) MainScreen.getInstance()
  				.findViewById(R.id.specialPluginsLayout).getLayoutParams();
  		mainLayoutHeight = lp.height;
  
  		RelativeLayout.LayoutParams params;
  
  		if (!CameraController.isRemoteCamera())
  		{
  			params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
  			zoomPanelWidth = MainScreen.getAppResources().getDrawable(R.drawable.scrubber_control_pressed_holo)
  					.getMinimumWidth();
  			params.setMargins(-zoomPanelWidth / 2, 0, 0, 0);
  			params.height = (int) (mainLayoutHeight / 2.2);
  		} else
  		{
  			params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
  			params.setMargins(10, 0, 0, 0);
  		}
  
  		params.addRule(RelativeLayout.CENTER_VERTICAL);
  		params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
  
  		((RelativeLayout) MainScreen.getInstance().findViewById(R.id.specialPluginsLayout)).addView(this.zoomPanel,
  				params);
  
  		this.zoomPanel.setLayoutParams(params);
  		showZoomControls();
  
  		scaleGestureDetector = new ScaleGestureDetector(ApplicationScreen.instance, new OnScaleGestureListener()
  		{
  			@Override
  			public boolean onScale(final ScaleGestureDetector scaleGestureDetector)
  			{
  				if (CameraController.isRemoteCamera())
  				{
  					return false;
  				}
  				
  				if (!CameraController.isUseCamera2()) {
  					// Division by zero required for smooth zooming.
  					zoomModify((scaleGestureDetector.getCurrentSpan() - scaleGestureDetector
  							.getPreviousSpan()) / 10);
  				} else {
  					zoomModify(zoomCurrent * scaleGestureDetector.getScaleFactor() - zoomCurrent);
  				}
  				
  				return true;
  			}
  
  			@Override
  			public boolean onScaleBegin(final ScaleGestureDetector scaleGestureDetector)
  			{
  				if (CameraController.isRemoteCamera())
  				{
  					return false;
  				}
  				return true;
  			}
  
  			@Override
  			public void onScaleEnd(final ScaleGestureDetector scaleGestureDetector)
  			{
  
  			}
  		});
  		onCameraParametersSetup();
  	}
  
  	@Override
  	public void onResume()
  	{
  		zoomStopping = false;
  		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(MainScreen.getMainContext());
  		isEnabled = prefs.getBoolean("enabledPrefZoom", true);
  		showZoomControls();
  	}
  
  	public void showZoomControls()
  	{
  		if (!CameraController.isRemoteCamera())
  		{
  			zoomPanel.findViewById(R.id.zoom_buttons_container).setVisibility(View.GONE);
  			if (!isEnabled)
  
  				zoomBar.setVisibility(View.GONE);
  			else
  				zoomBar.setVisibility(View.VISIBLE);
  		} else
  		{
  			zoomBar.setVisibility(View.GONE);
  			if (!isEnabled)
  				zoomPanel.findViewById(R.id.zoom_buttons_container).setVisibility(View.GONE);
  			else
  				zoomPanel.findViewById(R.id.zoom_buttons_container).setVisibility(View.VISIBLE);
  		}
  	}
  
  	@Override
  	public void onCameraParametersSetup()
  	{
  		if (!CameraController.isUseCamera2())
  		{
  			zoomCurrent = 0;
  		} else {
  			zoomCurrent = 1.f;
  		}
  
  		if (CameraController.isZoomSupported())
  		{
  			// If isCamera2 mode, then decrease value by 1 and multiple maxZoom 10x, because it represent by scale factor (from 1.0 to maxZoom).
  			// Else just set the exact value, given by CameraController (from 0 to maxZoom).
  			zoomBar.setMax(CameraController.isUseCamera2() ? (int)(CameraController.getMaxZoom() * 10 - 10) : (int)CameraController.getMaxZoom());
  			zoomBar.setProgressAndThumb(0);
  			zoomPanel.setVisibility(View.VISIBLE);
  			CameraController.setZoom(zoomCurrent);
  		} else
  			zoomPanel.setVisibility(View.GONE);
  	}
  
  	private void zoomModify(float delta)
  	{
  		if (CameraController.isZoomSupported())
  		{
  			try
  			{
  				zoomCurrent += delta;
  
  				if (!CameraController.isUseCamera2()) {
  					if (zoomCurrent < 0)
  						zoomCurrent = 0;
  					
  				}
  				else {
  					if (zoomCurrent < 1)
  						zoomCurrent = 1;
  				}
  				
  				if (zoomCurrent > CameraController.getMaxZoom())
  				{
  					zoomCurrent = CameraController.getMaxZoom();
  				}
  
  				//workaround for S7 issue with zooming.
  				if (CameraController.isGalaxyS7 && zoomCurrent>1.2)
  				{
  					zoomCurrent+=0.001f;
  				}
  				CameraController.setZoom(zoomCurrent);
  				zoomBar.setProgressAndThumb((int) (CameraController.isUseCamera2() ? zoomCurrent * 10.f - 10 : zoomCurrent));
  			} catch (Exception e)
  			{
  				e.printStackTrace();
  			}
  		}
  	}
  
  	public boolean onKeyDown(int keyCode, KeyEvent event)
  	{
  		if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_ZOOM_OUT)
  		{
  			this.zoomModify(CameraController.isUseCamera2() ? -0.1f : -1);
  			return true;
  		} else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_ZOOM_IN)
  		{
  			this.zoomModify(CameraController.isUseCamera2() ? 0.1f : 1);
  			return true;
  		}
  		return false;
  	}
  
  	PointF				mid		= new PointF();
  	static final int	NONE	= 0;
  	static final int	DRAG	= 1;
  	static final int	ZOOM	= 2;
  	int					mode	= NONE;
  
  	public void closeZoomPanel()
  	{
  		panelClosing = true;
  
  		this.zoomPanel.clearAnimation();
  		Animation animation = new TranslateAnimation(0, -zoomPanelWidth / 2, 0, 0);
  		animation.setDuration(300);
  		animation.setRepeatCount(0);
  		animation.setInterpolator(new LinearInterpolator());
  		animation.setFillAfter(true);
  
  		this.zoomPanel.setAnimation(animation);
  
  		animation.setAnimationListener(new AnimationListener()
  		{
  			@Override
  			public void onAnimationEnd(Animation animation)
  			{
  				if (zoomStopping)
  				{
  					List<View> specialView = new ArrayList<View>();
  					RelativeLayout specialLayout = (RelativeLayout) MainScreen.getInstance().findViewById(
  							R.id.specialPluginsLayout);
  					for (int i = 0; i < specialLayout.getChildCount(); i++)
  						specialView.add(specialLayout.getChildAt(i));
  
  					for (int j = 0; j < specialView.size(); j++)
  					{
  						final View view = specialView.get(j);
  						int view_id = view.getId();
  						int zoom_id = zoomPanel.getId();
  						if (view_id == zoom_id)
  						{
  							final ViewGroup parentView = (ViewGroup) view.getParent();
  							if (parentView != null)
  							{
  								parentView.post(new Runnable()
  								{
  									public void run()
  									{
  										// it works without the runOnUiThread,
  										// but all UI updates must
  										// be done on the UI thread
  										MainScreen.getInstance().runOnUiThread(new Runnable()
  										{
  											public void run()
  											{
  												parentView.removeView(view);
  											}
  										});
  									}
  								});
  							}
  						}
  					}
  					return;
  				}
  
  				RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) zoomPanel.getLayoutParams();
  				if (params == null)
  				{
  					zoomPanel.clearAnimation();
  					return;
  				}
  				params.setMargins(-zoomPanelWidth / 2, 0, 0, 0);
  				zoomPanel.setLayoutParams(params);
  				zoomPanel.clearAnimation();
  
  				panelOpened = false;
  				panelClosing = false;
  
  				if (panelToBeOpen)
  				{
  					panelToBeOpen = false;
  					openZoomPanel();
  				}
  			}
  
  			@Override
  			public void onAnimationRepeat(Animation animation)
  			{
  			}
  
  			@Override
  			public void onAnimationStart(Animation animation)
  			{
  			}
  		});
  	}
  
  	public void openZoomPanel()
  	{
  		panelOpening = true;
  		this.zoomPanel.clearAnimation();
  		Animation animation = new TranslateAnimation(0, zoomPanelWidth / 2, 0, 0);
  		animation.setDuration(500);
  		animation.setRepeatCount(0);
  		animation.setInterpolator(new LinearInterpolator());
  		animation.setFillAfter(true);
  
  		this.zoomPanel.setAnimation(animation);
  
  		animation.setAnimationListener(new AnimationListener()
  		{
  
  			@Override
  			public void onAnimationEnd(Animation animation)
  			{
  				RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) zoomPanel.getLayoutParams();
  
  				if (params == null)
  				{
  					zoomPanel.clearAnimation();
  					return;
  				}
  
  				params.setMargins(0, 0, 0, 0);
  				zoomPanel.setLayoutParams(params);
  
  				zoomPanel.clearAnimation();
  				zoomPanel.requestLayout();
  
  				panelOpened = true;
  				panelOpening = false;
  			}
  
  			@Override
  			public void onAnimationRepeat(Animation animation)
  			{
  			}
  
  			@Override
  			public void onAnimationStart(Animation animation)
  			{
  			}
  		});
  	}
  
  	@Override
  	public boolean onBroadcast(int arg1, int arg2)
  	{
  		if (!isEnabled)
  			return false;
  		if (arg1 == ApplicationInterface.MSG_CONTROL_LOCKED)
  			mZoomDisabled = true;
  		else if (arg1 == ApplicationInterface.MSG_CONTROL_UNLOCKED)
  			mZoomDisabled = false;
  		return false;
  	}
  	
  	@Override
  	public boolean onMultiTouch(View view, MotionEvent e)
  	{
  		return scaleGestureDetector.onTouchEvent(e);
  	}
  }
  