package com.integreight.onesheeld.shields.controller; import android.Manifest; import android.app.Activity; import android.app.AlertDialog; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.widget.Toast; import com.integreight.onesheeld.R; import com.integreight.onesheeld.enums.UIShield; import com.integreight.onesheeld.sdk.ShieldFrame; import com.integreight.onesheeld.shields.ControllerParent; import com.integreight.onesheeld.shields.controller.utils.CameraHeadService; import com.integreight.onesheeld.shields.controller.utils.CameraUtils; import com.integreight.onesheeld.utils.Log; import java.io.File; import java.io.Serializable; import java.util.Date; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; public class CameraShield extends ControllerParent<CameraShield> { public static final int CRASHED = 3; public final static int UNBIND_CAMERA_CAPTURE = 4, BIND_CAMERA_CAPTURE = 5, NEXT_CAPTURE = 14, SET_LAST_IMAGE_BUTTON = 17; private static final byte CAPTURE_METHOD_ID = (byte) 0x01; private static final byte FLASH_METHOD_ID = (byte) 0x02; private static final byte QUALITY_METHOD_ID = (byte) 0x04; private static final byte FRONT_CAPTURE = (byte) 0x03; private static String FLASH_MODE; private static int QUALITY_MODE = 0; private static String lastImageAbsoultePath = null; public Queue<CameraShield.CameraCapture> capturesQueue = new ConcurrentLinkedQueue<>(); public boolean isBackPreview = true; CameraCapture capture; int numberOfFrames = 0; Handler UIHandler; private Messenger cameraBinder; private boolean isCameraBound; private boolean isCameraCapturing = false; private CameraEventHandler eventHandler; private boolean hasFrontCamera = false; private boolean isChangingPreview = false; private Messenger mMessenger = new Messenger(new Handler() { public void handleMessage(Message msg) { if (msg.what == CRASHED) { cameraBinder = null; isCameraBound = false; if (capturesQueue == null) capturesQueue = new ConcurrentLinkedQueue<>(); bindService(); } else if (msg.what == NEXT_CAPTURE) { if (msg.getData().getBoolean("takenSuccessfuly")) { if (capturesQueue != null && !capturesQueue.isEmpty()) capturesQueue.poll(); } isCameraCapturing = false; checkQueue(); } else if (msg.what == CameraHeadService.SET_CAMERA_PREVIEW_TYPE) { isBackPreview = msg.getData().getBoolean("isBack"); if (eventHandler != null) eventHandler.setOnCameraPreviewTypeChanged(isBackPreview); isChangingPreview = false; } else if (msg.what == SET_LAST_IMAGE_BUTTON) { lastImageAbsoultePath = msg.getData().getString("absolutePath"); CameraUtils.setLastCapturedImagePathFromOneSheeldFolder(lastImageAbsoultePath, activity); Log.d("LastImage", lastImageAbsoultePath); File img = new File(lastImageAbsoultePath); if (img.exists() && eventHandler != null) { eventHandler.updatePreviewButton(lastImageAbsoultePath); } img = null; } super.handleMessage(msg); } }); private ServiceConnection cameraServiceConnector = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { isCameraCapturing = false; notifyHardwareOfShieldSelection(); cameraBinder = new Messenger(service); Message msg = Message.obtain(null, BIND_CAMERA_CAPTURE); msg.replyTo = mMessenger; try { cameraBinder.send(msg); } catch (RemoteException e) { } isCameraBound = true; checkQueue(); } @Override public void onServiceDisconnected(ComponentName name) { cameraBinder = null; isCameraBound = false; } }; public CameraShield() { } public CameraShield(Activity activity, String tag) { super(activity, tag, true); } public static String getLastImageAbsoultePath() { return lastImageAbsoultePath; } @Override public ControllerParent<CameraShield> init(String tag) { UIHandler = new Handler(); return super.init(tag, true); } void bindService() { getApplication().bindService(new Intent(getActivity(), CameraHeadService.class), cameraServiceConnector, Context.BIND_AUTO_CREATE); } @Override public ControllerParent<CameraShield> invalidate( com.integreight.onesheeld.shields.ControllerParent.SelectionAction selectionAction, boolean isToastable) { this.selectionAction = selectionAction; if (!checkCameraHardware(getApplication().getApplicationContext())) { if (selectionAction != null) selectionAction.onFailure(); if (isToastable) activity.showToast(R.string.camera_camera_is_unavailable_maybe_its_used_by_another_application_toast); } else { addRequiredPremission(Manifest.permission.CAMERA); addRequiredPremission(Manifest.permission.WRITE_EXTERNAL_STORAGE); if (Build.VERSION.SDK_INT >= 16) addRequiredPremission(Manifest.permission.READ_EXTERNAL_STORAGE); if (checkForPermissions()) { if (!activity.canDrawOverApps()) { final AlertDialog.Builder builder = new AlertDialog.Builder( activity); builder.setMessage( R.string.camera_we_need_you_to_enable_the_draw_over_apps_permission_in_order_to_show_the_camera_preview_correctly) .setCancelable(false) .setPositiveButton(R.string.camera_validation_dialog_ok_button, new DialogInterface.OnClickListener() { public void onClick(final DialogInterface dialog, final int id) { activity.requestDrawOverApps(); } }) .setNegativeButton(R.string.camera_validation_dialog_later_button, new DialogInterface.OnClickListener() { public void onClick(final DialogInterface dialog, final int id) { dialog.cancel(); activity.showToast(R.string.camera_please_enable_the_permission_to_be_able_to_select_this_shield_toast); } }); final AlertDialog alert = builder.create(); alert.show(); if (this.selectionAction != null) { this.selectionAction.onFailure(); } } else { if (selectionAction != null) selectionAction.onSuccess(); hasFrontCamera = CameraUtils.checkFrontCamera(activity.getApplicationContext()); bindService(); UIHandler = new Handler(); } } else { if (this.selectionAction != null) { this.selectionAction.onFailure(); } // bindService(); } } return super.invalidate(selectionAction, isToastable); } public boolean isBackPreview() { return isBackPreview; } public boolean setCameraToPreview(boolean isBack) { if (!isBack && !CameraUtils.checkFrontCamera(getActivity().getApplicationContext())) return false; if (isChangingPreview) return false; isChangingPreview = true; Log.d("Acc", isBack + " **"); Message msg = Message.obtain(null, CameraHeadService.SET_CAMERA_PREVIEW_TYPE); msg.replyTo = mMessenger; Bundle b = new Bundle(); b.putBoolean("isBack", isBack); msg.setData(b); if (cameraBinder != null) { try { cameraBinder.send(msg); } catch (RemoteException e) { return false; } } else { bindService(); } isBackPreview = isBack; return true; } private synchronized void checkQueue() { if (capturesQueue != null && !capturesQueue.isEmpty() && !isCameraCapturing) { if (isCameraBound) { capture = capturesQueue.peek(); if (capture.isFront()) { if (hasFrontCamera) sendFrontCaptureImageIntent(capture); else { Toast.makeText(getActivity(), R.string.camera_your_device_doesnt_have_a_front_camera_toast, Toast.LENGTH_SHORT).show(); capturesQueue.poll(); } } else { sendCaptureImageIntent(capture); } } else bindService(); } } /** * Check if this device has a camera */ private synchronized boolean checkCameraHardware(Context context) { if (context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_CAMERA)) { // this device has a camera return true; } else { // no camera on this device return false; } } public void setCameraEventHandler(CameraEventHandler eventHandler) { this.eventHandler = eventHandler; } public boolean showPreview() throws RemoteException { Message msg = Message.obtain(null, CameraHeadService.SHOW_PREVIEW); msg.replyTo = mMessenger; if (cameraBinder != null) { cameraBinder.send(msg); return true; } else { bindService(); return false; } } public void invalidatePreview() throws RemoteException { Message msg = Message.obtain(null, CameraHeadService.INVALIDATE_PREVIEW); msg.replyTo = mMessenger; if (cameraBinder != null) cameraBinder.send(msg); else bindService(); } public boolean hidePreview() throws RemoteException { Message msg = Message.obtain(null, CameraHeadService.HIDE_PREVIEW); msg.replyTo = mMessenger; if (cameraBinder != null) { cameraBinder.send(msg); return true; } else { return false; } } @Override public void onNewShieldFrameReceived(ShieldFrame frame) { if (frame.getShieldId() == UIShield.CAMERA_SHIELD.getId()) { switch (frame.getFunctionId()) { case QUALITY_METHOD_ID: byte quality_mode = frame.getArgument(0)[0]; switch (quality_mode) { case 1: QUALITY_MODE = 40; break; case 2: QUALITY_MODE = 70; break; case 3: QUALITY_MODE = 100; break; default: break; } break; case FLASH_METHOD_ID: byte flash_mode = frame.getArgument(0)[0]; switch (flash_mode) { case 0: FLASH_MODE = "off"; break; case 1: FLASH_MODE = "on"; break; case 2: FLASH_MODE = "auto"; break; default: break; } break; case CAPTURE_METHOD_ID: numberOfFrames++; Log.d("Camera", "Frames number = " + numberOfFrames); CameraCapture camCapture = new CameraCapture(FLASH_MODE, false, QUALITY_MODE, new Date().getTime()); if (capturesQueue == null) capturesQueue = new ConcurrentLinkedQueue<>(); capturesQueue.add(camCapture); checkQueue(); break; case FRONT_CAPTURE: numberOfFrames++; Log.d("Camera", "Frames number front = " + numberOfFrames); CameraCapture frontCamCapture = new CameraCapture(FLASH_MODE, true, QUALITY_MODE, new Date().getTime()); if (capturesQueue == null) capturesQueue = new ConcurrentLinkedQueue<>(); capturesQueue.add(frontCamCapture); checkQueue(); break; default: break; } } } @Override public void reset() { Message msg = Message.obtain(null, UNBIND_CAMERA_CAPTURE); try { if (cameraBinder != null) cameraBinder.send(msg); } catch (RemoteException e) { } try { getApplication().unbindService(cameraServiceConnector); } catch (IllegalArgumentException e) { } capturesQueue = new ConcurrentLinkedQueue<>(); isCameraBound = false; } @Override public void preConfigChange() { // Message msg = Message.obtain(null, UNBIND_CAMERA_CAPTURE); // try { // if (cameraBinder != null) // cameraBinder.send(msg); // } catch (RemoteException e) { // } // getActivity().unbindService(cameraServiceConnector); super.preConfigChange(); } @Override public void postConfigChange() { super.postConfigChange(); // bindService(); } private void sendCaptureImageIntent(CameraShield.CameraCapture camCapture) { if (camCapture != null) { if (isCameraBound) { isCameraCapturing = true; Bundle intent = new Bundle(); intent.putString("FLASH", camCapture.getFlash()); intent.putInt("Quality_Mode", camCapture.getQuality()); Message msg = Message.obtain(null, CameraHeadService.CAPTURE_IMAGE); msg.setData(intent); try { cameraBinder.send(msg); } catch (RemoteException e) { // capturesQueue.add(camCapture); checkQueue(); } } else bindService(); Log.d("ImageTakin", "OnTakeBack()"); } } private void sendFrontCaptureImageIntent(CameraShield.CameraCapture camCapture) { if (camCapture != null) { if (isCameraBound) { isCameraCapturing = true; Bundle intent = new Bundle(); intent.putInt("Quality_Mode", camCapture.getQuality()); intent.putBoolean("Front_Request", true); Message msg = Message.obtain(null, CameraHeadService.CAPTURE_IMAGE); msg.setData(intent); try { cameraBinder.send(msg); } catch (RemoteException e) { checkQueue(); } // service.takeImage(front_translucent); } else { bindService(); } } } public interface CameraEventHandler { void OnPictureTaken(); void checkCameraHardware(boolean isHasCamera); void takePicture(); void setFlashMode(String flash_mode); void setOnCameraPreviewTypeChanged(boolean isBack); void updatePreviewButton(String lastImagePath); } public class CameraCapture implements Serializable { private String flash; private boolean isFrontCamera; private long tag; private int mquality; public CameraCapture(String flash, boolean isFront, int quality, long tag) { this.flash = flash; isFrontCamera = isFront; mquality = quality; this.tag = tag; } public int getQuality() { return mquality; } public String getFlash() { return flash; } public boolean isFront() { return isFrontCamera; } public long getTag() { return tag; } public void setTag(long tag) { this.tag = tag; } } }