/* 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.opencam_plus; +++ --> */ // <!-- -+- package com.almalence.opencam; //-+- --> import java.util.ArrayList; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.annotation.TargetApi; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.hardware.Camera; import android.hardware.camera2.CaptureResult; import android.os.Environment; import android.preference.EditTextPreference; import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceCategory; import android.preference.PreferenceFragment; import android.preference.PreferenceManager; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.widget.ImageView; import com.almalence.asynctaskmanager.Task; /* <!-- +++ import com.almalence.opencam_plus.cameracontroller.CameraController; import com.almalence.opencam_plus.cameracontroller.CameraController.Size; import com.almalence.opencam_plus.R; +++ --> */ //<!-- -+- import com.almalence.opencam.cameracontroller.CameraController; import com.almalence.opencam.cameracontroller.CameraController.Size; import com.almalence.opencam.R; //-+- --> /*** * Abstract class for plugins ***/ public abstract class Plugin { // unique plugin id public String ID; // preferences file name - file distributed with plugin - analog of // preference.xml - should be also with unique name. private int prefName = 0; // name of advanced preference file. // each plugin can shot it's preference by type + can add advanced // preferences for expert users private int advancedPrefName = 0; // indicates if plugin has preferences and want to show it. Default - false // (no settings to show) // plugin should set this to true if want to show preferences protected boolean isShowPreferences = false; // ID of icon and title for creating quick control button // Each plugin may have only one quick control button public int quickControlIconID = -1; public String quickControlTitle = ""; private View quickControlView = null; protected static final String TIME_STAMP_NAME = "'IMG'_yyyyMMdd_HHmmss"; protected long SessionID = 0; protected int[] requestIDArray; protected int requestIDArrayLenght = 0;; protected boolean captureRAW = false; public enum ViewfinderZone { // 6 zones of ordinary controls VIEWFINDER_ZONE_TOP_LEFT, VIEWFINDER_ZONE_TOP_RIGHT, VIEWFINDER_ZONE_CENTER_RIGHT, VIEWFINDER_ZONE_BOTTOM_RIGHT, VIEWFINDER_ZONE_BOTTOM_LEFT, VIEWFINDER_ZONE_CENTER_LEFT, // Center screen controls VIEWFINDER_ZONE_FULLSCREEN, VIEWFINDER_ZONE_CENTER; public static int getInt(ViewfinderZone value) { switch (value) { case VIEWFINDER_ZONE_TOP_LEFT: return 0; case VIEWFINDER_ZONE_TOP_RIGHT: return 1; case VIEWFINDER_ZONE_CENTER_RIGHT: return 2; case VIEWFINDER_ZONE_BOTTOM_RIGHT: return 3; case VIEWFINDER_ZONE_BOTTOM_LEFT: return 4; case VIEWFINDER_ZONE_CENTER_LEFT: return 5; default: return 7; } } } // Views (generally a Buttons) for GUI protected Map<View, ViewfinderZone> pluginViews; // Informational views protected List<View> infoViews; // Postprocessing view. Actually a layout protected View postProcessingView = null; public Plugin(String sID, int preferenceID, int advancedPreferenceID, int quickControlID, String quickControlInitTitle) { ID = sID; if (preferenceID != 0) { setPreferenceName(preferenceID); isShowPreferences = true; } setAdvancedPreferenceName(advancedPreferenceID); quickControlIconID = quickControlID; quickControlTitle = quickControlInitTitle; pluginViews = new Hashtable<View, ViewfinderZone>(); infoViews = new ArrayList<View>(); } // base onCreate stage; public void onCreate() { } // base onStart stage; public void onStart() { } public void onStartProcessing(long SessionID) { } public void onStartPostProcessing() { } // base onStop stage; public void onStop() { } // base onDestroy stage public void onDestroy() { } // base onResume stage public void onResume() { } // base onPause stage public void onPause() { } // base onGUIStart stage public void onGUICreate() { } public void onShowPreferences() { } public void onShutterClick() { } public void onFocusButtonClick() { } public boolean onTouch(View view, MotionEvent e) { return false; } public boolean onMultiTouch(View view, MotionEvent e) { return false; } public void onOrientationChanged(int orientation) { } public boolean onKeyDown(int keyCode, KeyEvent event) { return false; } public boolean needPreviewFrame() { return false; } /****************************************************************************************************** * VF/Capture Interfaces ******************************************************************************************************/ public void onAutoFocus(boolean paramBoolean) { } public void onAutoFocusMoving(boolean paramBoolean) { } public void takePicture() { } public void onShutter() { } public void onImageTaken(int frame, byte[] frameData, int frame_len, int format) { } public void addToSharedMemExifTags(byte[] frameData) { } public void onPreviewFrame(byte[] data) { } @TargetApi(21) public void onCaptureCompleted(CaptureResult result) { } private long MPIX_8 = 3504 * 2336; // Actually 8.2 mpix, // some reserve for // unusual cameras; public void selectImageDimension() { // ----- Figure how much memory do we have and possibly limit resolution long maxMem = Runtime.getRuntime().maxMemory(); long maxMpix = (maxMem - 1000000) / 3; // 2 x Mpix - result, 1/4 x Mpix // x 4 - compressed input jpegs, // 1Mb - safe reserve // find index selected in preferences int prefIdx = -1; try { prefIdx = ApplicationScreen.instance.getImageSizeIndex(); } catch (IndexOutOfBoundsException e) { prefIdx = -1; } List<CameraController.Size> cs = CameraController.getResolutionsSizeList(); int defaultCaptureIdx = -1; long defaultCaptureMpix = 0; int defaultCaptureWidth = 0; int defaultCaptureHeight = 0; long CaptureMpix = 0; int CaptureWidth = 0; int CaptureHeight = 0; int CaptureIdx = -1; boolean prefFound = false; // figure default resolution int ii = 0; for (CameraController.Size s : cs) { long mpix = (long) s.getWidth() * s.getHeight(); if ((mpix >= CameraController.MIN_MPIX_SUPPORTED) && (mpix < maxMpix)) { if (mpix > defaultCaptureMpix && (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT || mpix <= MPIX_8)) { defaultCaptureIdx = Integer.parseInt(CameraController.getResolutionsIdxesList().get(ii)); defaultCaptureMpix = mpix; defaultCaptureWidth = s.getWidth(); defaultCaptureHeight = s.getHeight(); } } ii++; } ii = 0; for (CameraController.Size s : cs) { long mpix = (long) s.getWidth() * s.getHeight(); if ((Integer.parseInt(CameraController.getResolutionsIdxesList().get(ii)) == prefIdx) && (mpix >= CameraController.MIN_MPIX_SUPPORTED)) { prefFound = true; CaptureIdx = prefIdx; CaptureMpix = mpix; CaptureWidth = s.getWidth(); CaptureHeight = s.getHeight(); break; } if (mpix > CaptureMpix) { CaptureIdx = Integer.parseInt(CameraController.getResolutionsIdxesList().get(ii)); CaptureMpix = mpix; CaptureWidth = s.getWidth(); CaptureHeight = s.getHeight(); } ii++; } // default to about 8Mpix if nothing is set in preferences or maximum // resolution is above memory limits if (defaultCaptureMpix > 0) { if (!prefFound) { CaptureIdx = defaultCaptureIdx; CaptureMpix = defaultCaptureMpix; CaptureWidth = defaultCaptureWidth; CaptureHeight = defaultCaptureHeight; } } ApplicationScreen.instance.setCameraImageSizeIndex(CaptureIdx, true); CameraController.setCameraImageSize(new CameraController.Size(CaptureWidth, CaptureHeight)); } public void setCameraPreviewSize() { List<CameraController.Size> cs = CameraController.getSupportedPreviewSizes(); CameraController.Size imageSize = CameraController.getCameraImageSize(); CameraController.Size os = getOptimalPreviewSize(cs, imageSize.getWidth(), imageSize.getHeight()); ApplicationScreen.instance.setCameraPreviewSize(os.getWidth(), os.getHeight()); // ApplicationScreen.setPreviewWidth(os.getWidth()); // ApplicationScreen.setPreviewHeight(os.getHeight()); } // Used only in old camera interface (Camera2 don't use it) // called to set specific plugin's camera parameters public void setupCameraParameters() { Camera camera = CameraController.getCamera(); if (null == camera) return; SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ApplicationScreen.getMainContext()); int jpegQuality = Integer.parseInt(prefs.getString(ApplicationScreen.sJPEGQualityPref, "95")); Size imageSize = CameraController.getCameraImageSize(); Camera.Parameters cp = CameraController.getCameraParameters(); cp.setPictureSize(imageSize.getWidth(), imageSize.getHeight()); cp.setJpegQuality(jpegQuality); try { CameraController.setCameraParameters(cp); } catch (RuntimeException e) { Log.e("Plugin", "ApplicationScreen.setupCamera unable setParameters " + e.getMessage()); } } // from google example protected CameraController.Size getOptimalPreviewSize(List<CameraController.Size> sizes, int w, int h) { final double ASPECT_TOLERANCE = 0.05; double targetRatio = (double) w / h; if (sizes == null) return null; CameraController.Size optimalSize = null; double minDiff = Double.MAX_VALUE; int targetHeight = h; // Try to find an size match aspect ratio and size for (CameraController.Size size : sizes) { double ratio = (double) size.getWidth() / size.getHeight(); if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; if (Math.abs(size.getHeight() - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.getHeight() - targetHeight); } } // Cannot find the one match the aspect ratio, ignore the requirement if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (CameraController.Size size : sizes) { if (Math.abs(size.getHeight() - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.getHeight() - targetHeight); } } } return optimalSize; } // called after camera parameters setup public void onCameraSetup() { } // // called to set specific plugin's camera parameters // public void setupCameraParameters() // { // } // called before camera parameters setup - to set plugin specific options public void onCameraParametersSetup() { } // Called for each plugin on first camera startup. Camera setup is // guaranteed when it's called. public void onDefaultsSelect() { } public void onCaptureFinished() { } // return true in implementation of plugin if plugin can call onShutterClick // with delay, specified in general settings. public boolean delayedCaptureSupported() { return false; } public boolean photoTimeLapseCaptureSupported() { return false; } //Capture plugin may call that method if it want to know RequestID of each captured frames //It used in camera2 mode public void createRequestIDList(int nFrames) { requestIDArray = new int[nFrames]; requestIDArrayLenght = nFrames; } public void addRequestID(int nFrame, int requestID) { if(nFrame < requestIDArrayLenght) { requestIDArray[nFrame] = requestID; } } /****************************************************************************************************** * Processing Interfaces ******************************************************************************************************/ public void startProcessing() { } // called on task complete public void onTaskComplete(Task task) { } // called on intermediate result ready. For example if during processing // some preview available public void onPreviewComplete(Task task) { } public void onClick(View v) { } // onBroadcast message - receives broadcast message. // if message ignored - return false (continue onBroadcast) // if message needed and no need to send it further - return true (stop // onBroadcast) // if message needed and need to send it further - return false (continue // onBroadcast) public boolean onBroadcast(int arg1, int arg2) { return false; } // supplementary methods public String getID() { return ID; } public void setPreferenceName(int id) { prefName = id; } public void setAdvancedPreferenceName(int id) { advancedPrefName = id; } public int getPreferenceName() { return prefName; } public int getAdvancedPreferenceName() { return advancedPrefName; } public void showInitialSummary(PreferenceFragment preferenceFragment) { for (int i = 0; i < preferenceFragment.getPreferenceScreen().getPreferenceCount(); i++) { initSummary(preferenceFragment.getPreferenceScreen().getPreference(i)); } onPreferenceCreate(preferenceFragment); } private void initSummary(Preference p) { if (p instanceof PreferenceCategory) { PreferenceCategory pCat = (PreferenceCategory) p; for (int i = 0; i < pCat.getPreferenceCount(); i++) { initSummary(pCat.getPreference(i)); } } else { updatePrefSummary(p); } } public void updatePrefSummary(Preference p) { if (p instanceof ListPreference) { ListPreference listPref = (ListPreference) p; p.setSummary(listPref.getEntry()); } if (p instanceof EditTextPreference) { EditTextPreference editTextPref = (EditTextPreference) p; if (p.getKey().equalsIgnoreCase("editKey")) { p.setSummary("*****"); } else { p.setSummary(editTextPref.getText()); } } } public void onPreferenceCreate(PreferenceFragment preferenceFragment) { } public boolean ShowPreferences() { return isShowPreferences; } // called for multishot plugin to obtain bitmap at specific index public Bitmap getMultishotBitmap(int index) { return null; } public Bitmap getScaledMultishotBitmap(int index, int scaled_width, int scaled_height) { return null; } public int getResultYUV(int index) { return -1; } public int getMultishotImageCount() { return 0; } public boolean isPostProcessingNeeded() { return false; } /****************************************************************************************************** * Export Interface ******************************************************************************************************/ public void onExportActive(long SessionID) { } // called when export finished to clean all allocated memory public void freeMemory() { } public void onExportFinished() { } /****************************************************************************************************** * GUI Interface ******************************************************************************************************/ // method is used by children of class Plugin protected void clearViews() { pluginViews.clear(); } protected void addView(View view, ViewfinderZone position) { pluginViews.put(view, position); ApplicationScreen.getGUIManager().addViewQuick(view, position); } protected void addView(View view) { pluginViews.put(view, ViewfinderZone.VIEWFINDER_ZONE_BOTTOM_LEFT); } protected void removeView(View view) { pluginViews.remove(view); } protected void removeViewQuick(View view) { ApplicationScreen.getGUIManager().removeViewQuick(view); } // used by GUIManager to obtain list of view for current plugin public Map<View, ViewfinderZone> getPluginViews() { return pluginViews; } // method is used by children of class Plugin protected void clearInfoViews() { Iterator<View> it = infoViews.iterator(); while(it.hasNext()) ApplicationScreen.getGUIManager().removeInfoView(it.next()); infoViews.clear(); } protected void addInfoView(View view) { infoViews.add(view); ApplicationScreen.getGUIManager().addInfoView(view); } protected void removeInfoView(View view) { infoViews.remove(view); ApplicationScreen.getGUIManager().removeInfoView(view); } // used by GUIManager to obtain list of view for current plugin public List<View> getInfoViews() { return infoViews; } public View getPostProcessingView() { return postProcessingView; } // Quick control interfaces public int getQuickControlIconID() { return quickControlIconID; } public String getQuickControlTitle() { return quickControlTitle; } public void onQuickControlClick() { } public void setQuickControlView(View view) { quickControlView = view; } public void refreshQuickControl() { if (this.quickControlView != null) { int icon_id = this.getQuickControlIconID(); Drawable icon = ApplicationScreen.getMainContext().getResources().getDrawable(icon_id); ((ImageView) this.quickControlView.findViewById(R.id.imageView)).setImageDrawable(icon); } } /****************************************************************************************************** * OpenGL layer functions ******************************************************************************************************/ public boolean isGLSurfaceNeeded() { return false; } public void onGLSurfaceCreated(GL10 gl, EGLConfig config) { } public void onGLSurfaceChanged(GL10 gl, int width, int height) { } public void onGLDrawFrame(GL10 gl) { } }