More Related Content Similar to Building a Native Camera Access Library - Part I.pdf (20) More from ShaiAlmog1 (20) Building a Native Camera Access Library - Part I.pdf2. Introduction
© Codename One 2017 all rights reserved
✦Low level camera access has been a long time “wish
list” item
✦First Step: Survey Existing Solutions
✦Existing platforms don’t have something close
✦Camera Kit Android stood out as the best/simplest
option
https://github.com/CameraKit/camerakit-android/
3. Process
© Codename One 2017 all rights reserved
✦I went with the Android API “As Is”
✦Camera Kit Android already did the hard work of “design”
✦I started with an app that uses native interfaces, not a
cn1lib
✦API is mostly based on CameraView:
https://github.com/CameraKit/camerakit-android/blob/
master/camerakit-core/src/main/java/com/wonderkiln/
camerakit/CameraView.java
4. public interface CameraNativeAccess extends NativeInterface {
PeerComponent getView();
boolean isStarted();
void start();
void stop();
float getVerticalViewingAngle();
float getHorizontalViewingAngle();
int getFacing();
boolean isFacingFront();
boolean isFacingBack();
void setFacing(int facing);
void setFlash(int flash);
int toggleFacing();
int toggleFlash();
int getFlash();
void setFocus(int focus);
void setMethod(int method);
void setPinchToZoom(boolean zoom);
void setZoom(float zoom);
void setPermissions(int permissions);
void setVideoQuality(int videoQuality);
void setVideoBitRate(int videoBitRate);
void setLockVideoAspectRatio(boolean lockVideoAspectRatio);
CameraNativeAccess
5. public interface CameraNativeAccess extends NativeInterface {
PeerComponent getView();
boolean isStarted();
void start();
void stop();
float getVerticalViewingAngle();
float getHorizontalViewingAngle();
int getFacing();
boolean isFacingFront();
boolean isFacingBack();
void setFacing(int facing);
void setFlash(int flash);
int toggleFacing();
int toggleFlash();
int getFlash();
void setFocus(int focus);
void setMethod(int method);
void setPinchToZoom(boolean zoom);
void setZoom(float zoom);
void setPermissions(int permissions);
void setVideoQuality(int videoQuality);
void setVideoBitRate(int videoBitRate);
void setLockVideoAspectRatio(boolean lockVideoAspectRatio);
CameraNativeAccess
6. public interface CameraNativeAccess extends NativeInterface {
PeerComponent getView();
boolean isStarted();
void start();
void stop();
float getVerticalViewingAngle();
float getHorizontalViewingAngle();
int getFacing();
boolean isFacingFront();
boolean isFacingBack();
void setFacing(int facing);
void setFlash(int flash);
int toggleFacing();
int toggleFlash();
int getFlash();
void setFocus(int focus);
void setMethod(int method);
void setPinchToZoom(boolean zoom);
void setZoom(float zoom);
void setPermissions(int permissions);
void setVideoQuality(int videoQuality);
void setVideoBitRate(int videoBitRate);
void setLockVideoAspectRatio(boolean lockVideoAspectRatio);
CameraNativeAccess
7. public interface CameraNativeAccess extends NativeInterface {
PeerComponent getView();
boolean isStarted();
void start();
void stop();
float getVerticalViewingAngle();
float getHorizontalViewingAngle();
int getFacing();
boolean isFacingFront();
boolean isFacingBack();
void setFacing(int facing);
void setFlash(int flash);
int toggleFacing();
int toggleFlash();
int getFlash();
void setFocus(int focus);
void setMethod(int method);
void setPinchToZoom(boolean zoom);
void setZoom(float zoom);
void setPermissions(int permissions);
void setVideoQuality(int videoQuality);
void setVideoBitRate(int videoBitRate);
void setLockVideoAspectRatio(boolean lockVideoAspectRatio);
CameraNativeAccess
8. void setFlash(int flash);
int toggleFacing();
int toggleFlash();
int getFlash();
void setFocus(int focus);
void setMethod(int method);
void setPinchToZoom(boolean zoom);
void setZoom(float zoom);
void setPermissions(int permissions);
void setVideoQuality(int videoQuality);
void setVideoBitRate(int videoBitRate);
void setLockVideoAspectRatio(boolean lockVideoAspectRatio);
void setJpegQuality(int jpegQuality);
void setCropOutput(boolean cropOutput);
void captureImage();
void captureVideo();
void captureVideoFile(String videoFile);
void stopVideo();
int getPreviewWidth();
int getPreviewHeight();
int getCaptureWidth();
int getCaptureHeight();
}
CameraNativeAccess
9. void setFlash(int flash);
int toggleFacing();
int toggleFlash();
int getFlash();
void setFocus(int focus);
void setMethod(int method);
void setPinchToZoom(boolean zoom);
void setZoom(float zoom);
void setPermissions(int permissions);
void setVideoQuality(int videoQuality);
void setVideoBitRate(int videoBitRate);
void setLockVideoAspectRatio(boolean lockVideoAspectRatio);
void setJpegQuality(int jpegQuality);
void setCropOutput(boolean cropOutput);
void captureImage();
void captureVideo();
void captureVideoFile(String videoFile);
void stopVideo();
int getPreviewWidth();
int getPreviewHeight();
int getCaptureWidth();
int getCaptureHeight();
}
CameraNativeAccess
10. public boolean setTextDetectionListener(
CameraKitEventCallback<CameraKitTextDetect> callback);
public void captureImage(CameraKitEventCallback<CameraKitImage> callback);
public void captureVideo(CameraKitEventCallback<CameraKitVideo> callback);
public void captureVideo(File videoFile,
CameraKitEventCallback<CameraKitVideo> callback);
public void addCameraKitListener(
CameraKitEventListener CameraKitEventListener);
public void bindCameraKitListener(Object object);
Missing from the Native Interface
11. public interface Constants {
public static final int PERMISSION_REQUEST_CAMERA = 16;
public static final int FACING_BACK = 0;
public static final int FACING_FRONT = 1;
public static final int FLASH_OFF = 0;
public static final int FLASH_ON = 1;
public static final int FLASH_AUTO = 2;
public static final int FLASH_TORCH = 3;
public static final int FOCUS_OFF = 0;
public static final int FOCUS_CONTINUOUS = 1;
public static final int FOCUS_TAP = 2;
public static final int FOCUS_TAP_WITH_MARKER = 3;
public static final int METHOD_STANDARD = 0;
public static final int METHOD_STILL = 1;
public static final int PERMISSIONS_STRICT = 0;
public static final int PERMISSIONS_LAZY = 1;
public static final int PERMISSIONS_PICTURE = 2;
public static final int VIDEO_QUALITY_480P = 0;
public static final int VIDEO_QUALITY_720P = 1;
public static final int VIDEO_QUALITY_1080P = 2;
public static final int VIDEO_QUALITY_2160P = 3;
public static final int VIDEO_QUALITY_HIGHEST = 4;
public static final int VIDEO_QUALITY_LOWEST = 5;
public static final int VIDEO_QUALITY_QVGA = 6;
}
Constants
12. High Level Abstraction
© Codename One 2017 all rights reserved
✦Never expose a native interface to a user
✦Always wrap the native interface in a regular class
✦This lets you change the native API
13. public class CameraKit implements Constants {
private CameraNativeAccess cma;
private static CameraKit instance;
private ArrayList<CameraListener> listeners = new ArrayList<>();
static boolean thisIsForIOS;
private static void initBuildHint() {
Map<String, String> buildHints = Display.getInstance().
getProjectBuildHints();
if(!buildHints.containsKey("ios.NSCameraUsageDescription")) {
Display.getInstance().setProjectBuildHint(
"ios.NSCameraUsageDescription",
"We need camera access to grab pictures and videos");
}
}
public static CameraKit create() {
if(instance == null) {
if(isSimulator()) {
initBuildHint();
CameraKit
14. public class CameraKit implements Constants {
private CameraNativeAccess cma;
private static CameraKit instance;
private ArrayList<CameraListener> listeners = new ArrayList<>();
static boolean thisIsForIOS;
private static void initBuildHint() {
Map<String, String> buildHints = Display.getInstance().
getProjectBuildHints();
if(!buildHints.containsKey("ios.NSCameraUsageDescription")) {
Display.getInstance().setProjectBuildHint(
"ios.NSCameraUsageDescription",
"We need camera access to grab pictures and videos");
}
}
public static CameraKit create() {
if(instance == null) {
if(isSimulator()) {
initBuildHint();
CameraKit
15. public class CameraKit implements Constants {
private CameraNativeAccess cma;
private static CameraKit instance;
private ArrayList<CameraListener> listeners = new ArrayList<>();
static boolean thisIsForIOS;
private static void initBuildHint() {
Map<String, String> buildHints = Display.getInstance().
getProjectBuildHints();
if(!buildHints.containsKey("ios.NSCameraUsageDescription")) {
Display.getInstance().setProjectBuildHint(
"ios.NSCameraUsageDescription",
"We need camera access to grab pictures and videos");
}
}
public static CameraKit create() {
if(instance == null) {
if(isSimulator()) {
initBuildHint();
CameraKit
16. public class CameraKit implements Constants {
private CameraNativeAccess cma;
private static CameraKit instance;
private ArrayList<CameraListener> listeners = new ArrayList<>();
static boolean thisIsForIOS;
private static void initBuildHint() {
Map<String, String> buildHints = Display.getInstance().
getProjectBuildHints();
if(!buildHints.containsKey("ios.NSCameraUsageDescription")) {
Display.getInstance().setProjectBuildHint(
"ios.NSCameraUsageDescription",
"We need camera access to grab pictures and videos");
}
}
public static CameraKit create() {
if(instance == null) {
if(isSimulator()) {
initBuildHint();
CameraKit
17. public class CameraKit implements Constants {
private CameraNativeAccess cma;
private static CameraKit instance;
private ArrayList<CameraListener> listeners = new ArrayList<>();
static boolean thisIsForIOS;
private static void initBuildHint() {
Map<String, String> buildHints = Display.getInstance().
getProjectBuildHints();
if(!buildHints.containsKey("ios.NSCameraUsageDescription")) {
Display.getInstance().setProjectBuildHint(
"ios.NSCameraUsageDescription",
"We need camera access to grab pictures and videos");
}
}
public static CameraKit create() {
if(instance == null) {
if(isSimulator()) {
initBuildHint();
CameraKit
18. public class CameraKit implements Constants {
private CameraNativeAccess cma;
private static CameraKit instance;
private ArrayList<CameraListener> listeners = new ArrayList<>();
static boolean thisIsForIOS;
private static void initBuildHint() {
Map<String, String> buildHints = Display.getInstance().
getProjectBuildHints();
if(!buildHints.containsKey("ios.NSCameraUsageDescription")) {
Display.getInstance().setProjectBuildHint(
"ios.NSCameraUsageDescription",
"We need camera access to grab pictures and videos");
}
}
public static CameraKit create() {
if(instance == null) {
if(isSimulator()) {
initBuildHint();
CameraKit
19. public class CameraKit implements Constants {
private CameraNativeAccess cma;
private static CameraKit instance;
private ArrayList<CameraListener> listeners = new ArrayList<>();
static boolean thisIsForIOS;
private static void initBuildHint() {
Map<String, String> buildHints = Display.getInstance().
getProjectBuildHints();
if(!buildHints.containsKey("ios.NSCameraUsageDescription")) {
Display.getInstance().setProjectBuildHint(
"ios.NSCameraUsageDescription",
"We need camera access to grab pictures and videos");
}
}
public static CameraKit create() {
if(instance == null) {
if(isSimulator()) {
initBuildHint();
CameraKit
20. public class CameraKit implements Constants {
private CameraNativeAccess cma;
private static CameraKit instance;
private ArrayList<CameraListener> listeners = new ArrayList<>();
static boolean thisIsForIOS;
private static void initBuildHint() {
Map<String, String> buildHints = Display.getInstance().
getProjectBuildHints();
if(!buildHints.containsKey("ios.NSCameraUsageDescription")) {
Display.getInstance().setProjectBuildHint(
"ios.NSCameraUsageDescription",
"We need camera access to grab pictures and videos");
}
}
public static CameraKit create() {
if(instance == null) {
if(isSimulator()) {
initBuildHint();
CameraKit
21. public static CameraKit create() {
if(instance == null) {
if(isSimulator()) {
initBuildHint();
if(thisIsForIOS) {
CameraCallbacks.onError(null, null, null);
CameraCallbacks.onImage(null);
CameraCallbacks.onVideo(null);
}
return null;
}
instance = new CameraKit();
instance.cma =
NativeLookup.create(CameraNativeAccess.class);
if(instance.cma != null && instance.cma.isSupported()) {
return instance;
}
instance = null;
CameraKit
22. public static CameraKit create() {
if(instance == null) {
if(isSimulator()) {
initBuildHint();
if(thisIsForIOS) {
CameraCallbacks.onError(null, null, null);
CameraCallbacks.onImage(null);
CameraCallbacks.onVideo(null);
}
return null;
}
instance = new CameraKit();
instance.cma =
NativeLookup.create(CameraNativeAccess.class);
if(instance.cma != null && instance.cma.isSupported()) {
return instance;
}
instance = null;
CameraKit
23. public static CameraKit create() {
if(instance == null) {
if(isSimulator()) {
initBuildHint();
if(thisIsForIOS) {
CameraCallbacks.onError(null, null, null);
CameraCallbacks.onImage(null);
CameraCallbacks.onVideo(null);
}
return null;
}
instance = new CameraKit();
instance.cma =
NativeLookup.create(CameraNativeAccess.class);
if(instance.cma != null && instance.cma.isSupported()) {
return instance;
}
instance = null;
CameraKit
24. initBuildHint();
if(thisIsForIOS) {
CameraCallbacks.onError(null, null, null);
CameraCallbacks.onImage(null);
CameraCallbacks.onVideo(null);
}
return null;
}
instance = new CameraKit();
instance.cma =
NativeLookup.create(CameraNativeAccess.class);
if(instance.cma != null && instance.cma.isSupported()) {
return instance;
}
instance = null;
}
return instance;
}
CameraKit
25. public PeerComponent getView() {
return cma.getView();
}
public boolean isStarted() {
return cma.isStarted();
}
public void start() {
cma.start();
}
public void stop() {
cma.stop();
}
CameraKit
26. public int toggleFacing() {
if(getFacing() == FACING_BACK) {
setFacing(FACING_FRONT);
return FACING_FRONT;
}
setFacing(FACING_BACK);
return FACING_BACK;
}
public int toggleFlash() {
switch (getFlash()) {
case FLASH_OFF:
setFlash(FLASH_ON);
break;
case FLASH_ON:
setFlash(FLASH_AUTO);
break;
case FLASH_AUTO:
case FLASH_TORCH:
setFlash(FLASH_OFF);
break;
}
return getFlash();
}
CameraKit
27. public int toggleFacing() {
if(getFacing() == FACING_BACK) {
setFacing(FACING_FRONT);
return FACING_FRONT;
}
setFacing(FACING_BACK);
return FACING_BACK;
}
public int toggleFlash() {
switch (getFlash()) {
case FLASH_OFF:
setFlash(FLASH_ON);
break;
case FLASH_ON:
setFlash(FLASH_AUTO);
break;
case FLASH_AUTO:
case FLASH_TORCH:
setFlash(FLASH_OFF);
break;
}
return getFlash();
}
CameraKit
28. public void addCameraListener(CameraListener listener) { listeners.add(listener); }
public void removeCameraListener(CameraListener listener) { listeners.remove(listener); }
public void fireCameraErrorEvent(final CameraEvent ev) {
if(!isEdt()) {
callSerially(() -> fireCameraErrorEvent(ev));
return;
}
for(CameraListener l : listeners) {
l.onError(ev);
}
}
public void fireCameraImageEvent(final CameraEvent ev) {
if(!isEdt()) {
callSerially(() -> fireCameraImageEvent(ev));
return;
}
for(CameraListener l : listeners) { l.onImage(ev); }
}
public void fireCameraVideoEvent(final CameraEvent ev) {
if(!isEdt()) {
callSerially(() -> fireCameraVideoEvent(ev));
return;
}
for(CameraListener l : listeners) { l.onVideo(ev); }
}
CameraKit
29. public void addCameraListener(CameraListener listener) { listeners.add(listener); }
public void removeCameraListener(CameraListener listener) { listeners.remove(listener); }
public void fireCameraErrorEvent(final CameraEvent ev) {
if(!isEdt()) {
callSerially(() -> fireCameraErrorEvent(ev));
return;
}
for(CameraListener l : listeners) {
l.onError(ev);
}
}
public void fireCameraImageEvent(final CameraEvent ev) {
if(!isEdt()) {
callSerially(() -> fireCameraImageEvent(ev));
return;
}
for(CameraListener l : listeners) { l.onImage(ev); }
}
public void fireCameraVideoEvent(final CameraEvent ev) {
if(!isEdt()) {
callSerially(() -> fireCameraVideoEvent(ev));
return;
}
for(CameraListener l : listeners) { l.onVideo(ev); }
}
CameraKit
30. public void addCameraListener(CameraListener listener) { listeners.add(listener); }
public void removeCameraListener(CameraListener listener) { listeners.remove(listener); }
public void fireCameraErrorEvent(final CameraEvent ev) {
if(!isEdt()) {
callSerially(() -> fireCameraErrorEvent(ev));
return;
}
for(CameraListener l : listeners) {
l.onError(ev);
}
}
public void fireCameraImageEvent(final CameraEvent ev) {
if(!isEdt()) {
callSerially(() -> fireCameraImageEvent(ev));
return;
}
for(CameraListener l : listeners) { l.onImage(ev); }
}
public void fireCameraVideoEvent(final CameraEvent ev) {
if(!isEdt()) {
callSerially(() -> fireCameraVideoEvent(ev));
return;
}
for(CameraListener l : listeners) { l.onVideo(ev); }
}
CameraKit
31. public void addCameraListener(CameraListener listener) { listeners.add(listener); }
public void removeCameraListener(CameraListener listener) { listeners.remove(listener); }
public void fireCameraErrorEvent(final CameraEvent ev) {
if(!isEdt()) {
callSerially(() -> fireCameraErrorEvent(ev));
return;
}
for(CameraListener l : listeners) {
l.onError(ev);
}
}
public void fireCameraImageEvent(final CameraEvent ev) {
if(!isEdt()) {
callSerially(() -> fireCameraImageEvent(ev));
return;
}
for(CameraListener l : listeners) { l.onImage(ev); }
}
public void fireCameraVideoEvent(final CameraEvent ev) {
if(!isEdt()) {
callSerially(() -> fireCameraVideoEvent(ev));
return;
}
for(CameraListener l : listeners) { l.onVideo(ev); }
}
CameraKit
32. public void addCameraListener(CameraListener listener) { listeners.add(listener); }
public void removeCameraListener(CameraListener listener) { listeners.remove(listener); }
public void fireCameraErrorEvent(final CameraEvent ev) {
if(!isEdt()) {
callSerially(() -> fireCameraErrorEvent(ev));
return;
}
for(CameraListener l : listeners) {
l.onError(ev);
}
}
public void fireCameraImageEvent(final CameraEvent ev) {
if(!isEdt()) {
callSerially(() -> fireCameraImageEvent(ev));
return;
}
for(CameraListener l : listeners) { l.onImage(ev); }
}
public void fireCameraVideoEvent(final CameraEvent ev) {
if(!isEdt()) {
callSerially(() -> fireCameraVideoEvent(ev));
return;
}
for(CameraListener l : listeners) { l.onVideo(ev); }
}
CameraKit
33. public class CameraCallbacks {
public static void onError(String type, String message,
String exceptionMessage) {
CameraKit ck = CameraKit.create();
if(ck != null) {
ck.fireCameraErrorEvent(
new CameraEvent(type, message, exceptionMessage));
}
}
public static void onImage(byte[] jpeg) {
CameraKit ck = CameraKit.create();
if(ck != null) {
ck.fireCameraImageEvent(new CameraEvent(jpeg));
}
}
public static void onVideo(String file) {
CameraKit ck = CameraKit.create();
if(ck != null) {
ck.fireCameraVideoEvent(new CameraEvent(file));
}
}
}
CameraCallbacks
34. public class CameraCallbacks {
public static void onError(String type, String message,
String exceptionMessage) {
CameraKit ck = CameraKit.create();
if(ck != null) {
ck.fireCameraErrorEvent(
new CameraEvent(type, message, exceptionMessage));
}
}
public static void onImage(byte[] jpeg) {
CameraKit ck = CameraKit.create();
if(ck != null) {
ck.fireCameraImageEvent(new CameraEvent(jpeg));
}
}
public static void onVideo(String file) {
CameraKit ck = CameraKit.create();
if(ck != null) {
ck.fireCameraVideoEvent(new CameraEvent(file));
}
}
}
CameraCallbacks
35. public class CameraCallbacks {
public static void onError(String type, String message,
String exceptionMessage) {
CameraKit ck = CameraKit.create();
if(ck != null) {
ck.fireCameraErrorEvent(
new CameraEvent(type, message, exceptionMessage));
}
}
public static void onImage(byte[] jpeg) {
CameraKit ck = CameraKit.create();
if(ck != null) {
ck.fireCameraImageEvent(new CameraEvent(jpeg));
}
}
public static void onVideo(String file) {
CameraKit ck = CameraKit.create();
if(ck != null) {
ck.fireCameraVideoEvent(new CameraEvent(file));
}
}
}
CameraCallbacks