@ -0,0 +1 @@ |
||||
/build |
@ -0,0 +1,25 @@ |
||||
apply plugin: 'com.android.application' |
||||
|
||||
android { |
||||
compileSdkVersion 25 |
||||
buildToolsVersion "25.0.2" |
||||
defaultConfig { |
||||
applicationId "com.wonderkiln.camerakit.demo" |
||||
minSdkVersion 21 |
||||
targetSdkVersion 25 |
||||
versionCode 1 |
||||
versionName "1.0" |
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" |
||||
} |
||||
buildTypes { |
||||
release { |
||||
minifyEnabled false |
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' |
||||
} |
||||
} |
||||
} |
||||
|
||||
dependencies { |
||||
compile 'com.android.support:appcompat-v7:25.0.1' |
||||
compile project(':camerakit') |
||||
} |
@ -0,0 +1,25 @@ |
||||
# Add project specific ProGuard rules here. |
||||
# By default, the flags in this file are appended to flags specified |
||||
# in /Users/dylanmcintyre/Library/Android/sdk/tools/proguard/proguard-android.txt |
||||
# You can edit the include path and order by changing the proguardFiles |
||||
# directive in build.gradle. |
||||
# |
||||
# For more details, see |
||||
# http://developer.android.com/guide/developing/tools/proguard.html |
||||
|
||||
# Add any project specific keep options here: |
||||
|
||||
# If your project uses WebView with JS, uncomment the following |
||||
# and specify the fully qualified class name to the JavaScript interface |
||||
# class: |
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { |
||||
# public *; |
||||
#} |
||||
|
||||
# Uncomment this to preserve the line number information for |
||||
# debugging stack traces. |
||||
#-keepattributes SourceFile,LineNumberTable |
||||
|
||||
# If you keep the line number information, uncomment this to |
||||
# hide the original source file name. |
||||
#-renamesourcefileattribute SourceFile |
@ -0,0 +1,26 @@ |
||||
package com.wonderkiln.camerakit.demo; |
||||
|
||||
import android.content.Context; |
||||
import android.support.test.InstrumentationRegistry; |
||||
import android.support.test.runner.AndroidJUnit4; |
||||
|
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
|
||||
import static org.junit.Assert.*; |
||||
|
||||
/** |
||||
* Instrumentation test, which will execute on an Android device. |
||||
* |
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a> |
||||
*/ |
||||
@RunWith(AndroidJUnit4.class) |
||||
public class ExampleInstrumentedTest { |
||||
@Test |
||||
public void useAppContext() throws Exception { |
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext(); |
||||
|
||||
assertEquals("com.wonderkiln.camerakit.demo", appContext.getPackageName()); |
||||
} |
||||
} |
@ -0,0 +1,21 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
||||
package="com.wonderkiln.camerakit.demo"> |
||||
|
||||
<application |
||||
android:allowBackup="true" |
||||
android:icon="@mipmap/ic_launcher" |
||||
android:label="@string/app_name" |
||||
android:roundIcon="@mipmap/ic_launcher_round" |
||||
android:supportsRtl="true" |
||||
android:theme="@style/AppTheme"> |
||||
<activity android:name=".MainActivity"> |
||||
<intent-filter> |
||||
<action android:name="android.intent.action.MAIN" /> |
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" /> |
||||
</intent-filter> |
||||
</activity> |
||||
</application> |
||||
|
||||
</manifest> |
@ -0,0 +1,14 @@ |
||||
package com.wonderkiln.camerakit.demo; |
||||
|
||||
import android.support.v7.app.AppCompatActivity; |
||||
import android.os.Bundle; |
||||
|
||||
public class MainActivity extends AppCompatActivity { |
||||
|
||||
@Override |
||||
protected void onCreate(Bundle savedInstanceState) { |
||||
super.onCreate(savedInstanceState); |
||||
setContentView(R.layout.activity_main); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,8 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent"> |
||||
|
||||
|
||||
|
||||
</FrameLayout> |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 6.0 KiB |
After Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 9.8 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 14 KiB |
@ -0,0 +1,6 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources> |
||||
<color name="colorPrimary">#3F51B5</color> |
||||
<color name="colorPrimaryDark">#303F9F</color> |
||||
<color name="colorAccent">#FF4081</color> |
||||
</resources> |
@ -0,0 +1,3 @@ |
||||
<resources> |
||||
<string name="app_name">CameraKit-Android</string> |
||||
</resources> |
@ -0,0 +1,11 @@ |
||||
<resources> |
||||
|
||||
<!-- Base application theme. --> |
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> |
||||
<!-- Customize your theme here. --> |
||||
<item name="colorPrimary">@color/colorPrimary</item> |
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> |
||||
<item name="colorAccent">@color/colorAccent</item> |
||||
</style> |
||||
|
||||
</resources> |
@ -0,0 +1,17 @@ |
||||
package com.wonderkiln.camerakit.demo; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
import static org.junit.Assert.*; |
||||
|
||||
/** |
||||
* Example local unit test, which will execute on the development machine (host). |
||||
* |
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a> |
||||
*/ |
||||
public class ExampleUnitTest { |
||||
@Test |
||||
public void addition_isCorrect() throws Exception { |
||||
assertEquals(4, 2 + 2); |
||||
} |
||||
} |
@ -0,0 +1,23 @@ |
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules. |
||||
|
||||
buildscript { |
||||
repositories { |
||||
jcenter() |
||||
} |
||||
dependencies { |
||||
classpath 'com.android.tools.build:gradle:2.3.0-beta1' |
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong |
||||
// in the individual module build.gradle files |
||||
} |
||||
} |
||||
|
||||
allprojects { |
||||
repositories { |
||||
jcenter() |
||||
} |
||||
} |
||||
|
||||
task clean(type: Delete) { |
||||
delete rootProject.buildDir |
||||
} |
@ -0,0 +1 @@ |
||||
/build |
@ -0,0 +1,26 @@ |
||||
apply plugin: 'com.android.library' |
||||
|
||||
android { |
||||
compileSdkVersion 25 |
||||
buildToolsVersion "25.0.2" |
||||
|
||||
defaultConfig { |
||||
minSdkVersion 21 |
||||
targetSdkVersion 25 |
||||
versionCode 1 |
||||
versionName "1.0" |
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" |
||||
|
||||
} |
||||
buildTypes { |
||||
release { |
||||
minifyEnabled false |
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' |
||||
} |
||||
} |
||||
} |
||||
|
||||
dependencies { |
||||
|
||||
} |
@ -0,0 +1,25 @@ |
||||
# Add project specific ProGuard rules here. |
||||
# By default, the flags in this file are appended to flags specified |
||||
# in /Users/dylanmcintyre/Library/Android/sdk/tools/proguard/proguard-android.txt |
||||
# You can edit the include path and order by changing the proguardFiles |
||||
# directive in build.gradle. |
||||
# |
||||
# For more details, see |
||||
# http://developer.android.com/guide/developing/tools/proguard.html |
||||
|
||||
# Add any project specific keep options here: |
||||
|
||||
# If your project uses WebView with JS, uncomment the following |
||||
# and specify the fully qualified class name to the JavaScript interface |
||||
# class: |
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { |
||||
# public *; |
||||
#} |
||||
|
||||
# Uncomment this to preserve the line number information for |
||||
# debugging stack traces. |
||||
#-keepattributes SourceFile,LineNumberTable |
||||
|
||||
# If you keep the line number information, uncomment this to |
||||
# hide the original source file name. |
||||
#-renamesourcefileattribute SourceFile |
@ -0,0 +1,26 @@ |
||||
package com.wonderkiln.camerakit; |
||||
|
||||
import android.content.Context; |
||||
import android.support.test.InstrumentationRegistry; |
||||
import android.support.test.runner.AndroidJUnit4; |
||||
|
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
|
||||
import static org.junit.Assert.*; |
||||
|
||||
/** |
||||
* Instrumentation test, which will execute on an Android device. |
||||
* |
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a> |
||||
*/ |
||||
@RunWith(AndroidJUnit4.class) |
||||
public class ExampleInstrumentedTest { |
||||
@Test |
||||
public void useAppContext() throws Exception { |
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext(); |
||||
|
||||
assertEquals("com.wonderkiln.camerakit.test", appContext.getPackageName()); |
||||
} |
||||
} |
@ -0,0 +1,13 @@ |
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
||||
package="com.wonderkiln.camerakit"> |
||||
|
||||
<uses-permission android:name="android.permission.CAMERA" /> |
||||
|
||||
<uses-feature android:name="android.hardware.camera" /> |
||||
<uses-feature |
||||
android:name="android.hardware.camera.autofocus" |
||||
android:required="false" /> |
||||
|
||||
<application /> |
||||
|
||||
</manifest> |
@ -0,0 +1,170 @@ |
||||
package com.wonderkiln.camerakit; |
||||
|
||||
import android.os.Parcel; |
||||
import android.os.Parcelable; |
||||
import android.support.annotation.NonNull; |
||||
import android.support.v4.util.SparseArrayCompat; |
||||
|
||||
public class AspectRatio implements Comparable<AspectRatio>, Parcelable { |
||||
|
||||
private final static SparseArrayCompat<SparseArrayCompat<AspectRatio>> sCache |
||||
= new SparseArrayCompat<>(16); |
||||
|
||||
private final int mX; |
||||
private final int mY; |
||||
|
||||
/** |
||||
* Returns an instance of {@link AspectRatio} specified by {@code x} and {@code y} values. |
||||
* The values {@code x} and {@code} will be reduced by their greatest common divider. |
||||
* |
||||
* @param x The width |
||||
* @param y The height |
||||
* @return An instance of {@link AspectRatio} |
||||
*/ |
||||
public static AspectRatio of(int x, int y) { |
||||
int gcd = gcd(x, y); |
||||
x /= gcd; |
||||
y /= gcd; |
||||
SparseArrayCompat<AspectRatio> arrayX = sCache.get(x); |
||||
if (arrayX == null) { |
||||
AspectRatio ratio = new AspectRatio(x, y); |
||||
arrayX = new SparseArrayCompat<>(); |
||||
arrayX.put(y, ratio); |
||||
sCache.put(x, arrayX); |
||||
return ratio; |
||||
} else { |
||||
AspectRatio ratio = arrayX.get(y); |
||||
if (ratio == null) { |
||||
ratio = new AspectRatio(x, y); |
||||
arrayX.put(y, ratio); |
||||
} |
||||
return ratio; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Parse an {@link AspectRatio} from a {@link String} formatted like "4:3". |
||||
* |
||||
* @param s The string representation of the aspect ratio |
||||
* @return The aspect ratio |
||||
* @throws IllegalArgumentException when the format is incorrect. |
||||
*/ |
||||
public static AspectRatio parse(String s) { |
||||
int position = s.indexOf(':'); |
||||
if (position == -1) { |
||||
throw new IllegalArgumentException("Malformed aspect ratio: " + s); |
||||
} |
||||
try { |
||||
int x = Integer.parseInt(s.substring(0, position)); |
||||
int y = Integer.parseInt(s.substring(position + 1)); |
||||
return AspectRatio.of(x, y); |
||||
} catch (NumberFormatException e) { |
||||
throw new IllegalArgumentException("Malformed aspect ratio: " + s, e); |
||||
} |
||||
} |
||||
|
||||
private AspectRatio(int x, int y) { |
||||
mX = x; |
||||
mY = y; |
||||
} |
||||
|
||||
public int getX() { |
||||
return mX; |
||||
} |
||||
|
||||
public int getY() { |
||||
return mY; |
||||
} |
||||
|
||||
public boolean matches(Size size) { |
||||
int gcd = gcd(size.getWidth(), size.getHeight()); |
||||
int x = size.getWidth() / gcd; |
||||
int y = size.getHeight() / gcd; |
||||
return mX == x && mY == y; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
if (o == null) { |
||||
return false; |
||||
} |
||||
if (this == o) { |
||||
return true; |
||||
} |
||||
if (o instanceof AspectRatio) { |
||||
AspectRatio ratio = (AspectRatio) o; |
||||
return mX == ratio.mX && mY == ratio.mY; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return mX + ":" + mY; |
||||
} |
||||
|
||||
public float toFloat() { |
||||
return (float) mX / mY; |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
// assuming most sizes are <2^16, doing a rotate will give us perfect hashing
|
||||
return mY ^ ((mX << (Integer.SIZE / 2)) | (mX >>> (Integer.SIZE / 2))); |
||||
} |
||||
|
||||
@Override |
||||
public int compareTo(@NonNull AspectRatio another) { |
||||
if (equals(another)) { |
||||
return 0; |
||||
} else if (toFloat() - another.toFloat() > 0) { |
||||
return 1; |
||||
} |
||||
return -1; |
||||
} |
||||
|
||||
/** |
||||
* @return The inverse of this {@link AspectRatio}. |
||||
*/ |
||||
public AspectRatio inverse() { |
||||
//noinspection SuspiciousNameCombination
|
||||
return AspectRatio.of(mY, mX); |
||||
} |
||||
|
||||
private static int gcd(int a, int b) { |
||||
while (b != 0) { |
||||
int c = b; |
||||
b = a % b; |
||||
a = c; |
||||
} |
||||
return a; |
||||
} |
||||
|
||||
@Override |
||||
public int describeContents() { |
||||
return 0; |
||||
} |
||||
|
||||
@Override |
||||
public void writeToParcel(Parcel dest, int flags) { |
||||
dest.writeInt(mX); |
||||
dest.writeInt(mY); |
||||
} |
||||
|
||||
public static final Parcelable.Creator<AspectRatio> CREATOR |
||||
= new Parcelable.Creator<AspectRatio>() { |
||||
|
||||
@Override |
||||
public AspectRatio createFromParcel(Parcel source) { |
||||
int x = source.readInt(); |
||||
int y = source.readInt(); |
||||
return AspectRatio.of(x, y); |
||||
} |
||||
|
||||
@Override |
||||
public AspectRatio[] newArray(int size) { |
||||
return new AspectRatio[size]; |
||||
} |
||||
}; |
||||
|
||||
} |
@ -0,0 +1,539 @@ |
||||
package com.wonderkiln.camerakit; |
||||
|
||||
import android.annotation.TargetApi; |
||||
import android.content.Context; |
||||
import android.graphics.ImageFormat; |
||||
import android.hardware.camera2.CameraAccessException; |
||||
import android.hardware.camera2.CameraCaptureSession; |
||||
import android.hardware.camera2.CameraCharacteristics; |
||||
import android.hardware.camera2.CameraDevice; |
||||
import android.hardware.camera2.CameraManager; |
||||
import android.hardware.camera2.CaptureRequest; |
||||
import android.hardware.camera2.TotalCaptureResult; |
||||
import android.hardware.camera2.params.StreamConfigurationMap; |
||||
import android.media.Image; |
||||
import android.media.ImageReader; |
||||
import android.media.MediaRecorder; |
||||
import android.os.Handler; |
||||
import android.os.HandlerThread; |
||||
import android.support.annotation.NonNull; |
||||
import android.util.Log; |
||||
import android.util.SparseIntArray; |
||||
import android.view.Surface; |
||||
import android.view.View; |
||||
|
||||
import java.nio.ByteBuffer; |
||||
import java.util.Arrays; |
||||
import java.util.SortedSet; |
||||
import java.util.TreeSet; |
||||
import java.util.concurrent.Semaphore; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
import static android.content.ContentValues.TAG; |
||||
|
||||
@TargetApi(21) |
||||
public class Camera2 extends CameraViewImpl { |
||||
|
||||
private static final SparseIntArray INTERNAL_FACINGS = new SparseIntArray(); |
||||
|
||||
static { |
||||
INTERNAL_FACINGS.put(Constants.FACING_BACK, CameraCharacteristics.LENS_FACING_BACK); |
||||
INTERNAL_FACINGS.put(Constants.FACING_FRONT, CameraCharacteristics.LENS_FACING_FRONT); |
||||
} |
||||
|
||||
private CameraManager mCameraManager; |
||||
private CameraDevice mCamera; |
||||
private CameraCaptureSession mCaptureSession; |
||||
private CaptureRequest.Builder mPreviewRequestBuilder; |
||||
private ImageReader mImageReader; |
||||
private MediaRecorder mMediaRecorder; |
||||
|
||||
private Semaphore mCameraOpenCloseLock; |
||||
|
||||
private int mFacing; |
||||
private int mFlash; |
||||
private int mDisplayOrientation; |
||||
private String mCameraId; |
||||
private CameraCharacteristics mCameraCharacteristics; |
||||
|
||||
private SortedSet<Size> mPreviewSizes; |
||||
private SortedSet<Size> mCaptureSizes; |
||||
|
||||
private HandlerThread mBackgroundThread; |
||||
private Handler mBackgroundHandler; |
||||
|
||||
Camera2(Context context, CameraListener cameraListener, PreviewImpl preview) { |
||||
super(cameraListener, preview); |
||||
mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); |
||||
mPreview.setCallback(new PreviewImpl.Callback() { |
||||
@Override |
||||
public void onSurfaceChanged() { |
||||
startCaptureSession(); |
||||
} |
||||
}); |
||||
|
||||
mCameraOpenCloseLock = new Semaphore(1); |
||||
|
||||
mPreviewSizes = new TreeSet<>(); |
||||
mCaptureSizes = new TreeSet<>(); |
||||
} |
||||
|
||||
@Override |
||||
View getView() { |
||||
return mPreview.getView(); |
||||
} |
||||
|
||||
@Override |
||||
void start() { |
||||
if (chooseCameraIdByFacing()) { |
||||
startBackgroundThread(); |
||||
collectCameraInfo(); |
||||
prepareImageReader(); |
||||
startOpeningCamera(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
void stop() { |
||||
try { |
||||
mCameraOpenCloseLock.acquire(); |
||||
if (mCaptureSession != null) { |
||||
mCaptureSession.close(); |
||||
mCaptureSession = null; |
||||
} |
||||
if (mCamera != null) { |
||||
mCamera.close(); |
||||
mCamera = null; |
||||
} |
||||
if (mImageReader != null) { |
||||
mImageReader.close(); |
||||
mImageReader = null; |
||||
} |
||||
} catch (InterruptedException e) { |
||||
throw new RuntimeException("Interrupted while trying to lock camera closing.", e); |
||||
} finally { |
||||
mCameraOpenCloseLock.release(); |
||||
|
||||
if (mBackgroundThread != null) { |
||||
stopBackgroundThread(); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
@Override |
||||
boolean isCameraOpened() { |
||||
return mCamera != null; |
||||
} |
||||
|
||||
@Override |
||||
void setFacing(int facing) { |
||||
int internalFacing = INTERNAL_FACINGS.get(facing); |
||||
if (mFacing == internalFacing) return; |
||||
this.mFacing = internalFacing; |
||||
if (isCameraOpened()) { |
||||
stop(); |
||||
start(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
int getFacing() { |
||||
return mFacing; |
||||
} |
||||
|
||||
@Override |
||||
void setFlash(int flash) { |
||||
if (mFlash == flash) return; |
||||
int fallback = flash; |
||||
mFlash = flash; |
||||
if (mPreviewRequestBuilder != null) { |
||||
updateFlash(mPreviewRequestBuilder); |
||||
if (mCaptureSession != null) { |
||||
try { |
||||
mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler); |
||||
} catch (CameraAccessException e) { |
||||
mFlash = fallback; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
int getFlash() { |
||||
return mFlash; |
||||
} |
||||
|
||||
@Override |
||||
void capturePicture() { |
||||
if (mFacing == Constants.FACING_BACK) { |
||||
lockFocus(); |
||||
} else { |
||||
captureStillPicture(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
void captureStill() { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
void startVideo() { |
||||
if (mCamera == null) { |
||||
return; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
void endVideo() { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
void setDisplayOrientation(int displayOrientation) { |
||||
mDisplayOrientation = displayOrientation; |
||||
mPreview.setDisplayOrientation(mDisplayOrientation); |
||||
} |
||||
|
||||
void updateFlash(CaptureRequest.Builder builder) { |
||||
switch (mFlash) { |
||||
case Constants.FLASH_OFF: |
||||
builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); |
||||
builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); |
||||
break; |
||||
case Constants.FLASH_ON: |
||||
builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH); |
||||
builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); |
||||
break; |
||||
case Constants.FLASH_AUTO: |
||||
builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); |
||||
builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
private boolean chooseCameraIdByFacing() { |
||||
try { |
||||
int internalFacing = mFacing; |
||||
final String[] ids = mCameraManager.getCameraIdList(); |
||||
if (ids.length == 0) { // No camera
|
||||
throw new RuntimeException("No camera available."); |
||||
} |
||||
for (String id : ids) { |
||||
CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id); |
||||
Integer level = characteristics.get( |
||||
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); |
||||
if (level == null || |
||||
level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) { |
||||
continue; |
||||
} |
||||
Integer internal = characteristics.get(CameraCharacteristics.LENS_FACING); |
||||
if (internal == null) { |
||||
throw new NullPointerException("Unexpected state: LENS_FACING null"); |
||||
} |
||||
if (internal == internalFacing) { |
||||
mCameraId = id; |
||||
mCameraCharacteristics = characteristics; |
||||
return true; |
||||
} |
||||
} |
||||
// Not found
|
||||
mCameraId = ids[0]; |
||||
mCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId); |
||||
Integer level = mCameraCharacteristics.get( |
||||
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); |
||||
if (level == null || |
||||
level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) { |
||||
return false; |
||||
} |
||||
Integer internal = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING); |
||||
if (internal == null) { |
||||
throw new NullPointerException("Unexpected state: LENS_FACING null"); |
||||
} |
||||
for (int i = 0, count = INTERNAL_FACINGS.size(); i < count; i++) { |
||||
if (INTERNAL_FACINGS.valueAt(i) == internal) { |
||||
mFacing = INTERNAL_FACINGS.keyAt(i); |
||||
return true; |
||||
} |
||||
} |
||||
// The operation can reach here when the only camera device is an external one.
|
||||
// We treat it as facing back.
|
||||
mFacing = Constants.FACING_BACK; |
||||
return true; |
||||
} catch (CameraAccessException e) { |
||||
throw new RuntimeException("Failed to get a list of camera devices", e); |
||||
} |
||||
} |
||||
|
||||
private void collectCameraInfo() { |
||||
StreamConfigurationMap map = mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); |
||||
if (map == null) { |
||||
throw new IllegalStateException("Failed to get configuration map: " + mCameraId); |
||||
} |
||||
|
||||
mPreviewSizes.clear(); |
||||
for (android.util.Size size : map.getOutputSizes(mPreview.getOutputClass())) { |
||||
mPreviewSizes.add(new Size(size.getWidth(), size.getHeight())); |
||||
} |
||||
|
||||
mCaptureSizes.clear(); |
||||
for (android.util.Size size : map.getOutputSizes(ImageFormat.JPEG)) { |
||||
mCaptureSizes.add(new Size(size.getWidth(), size.getHeight())); |
||||
} |
||||
} |
||||
|
||||
private Size getOptimalPreviewSize() { |
||||
int surfaceLonger, surfaceShorter; |
||||
final int surfaceWidth = mPreview.getWidth(); |
||||
final int surfaceHeight = mPreview.getHeight(); |
||||
if (surfaceWidth < surfaceHeight) { |
||||
surfaceLonger = surfaceHeight; |
||||
surfaceShorter = surfaceWidth; |
||||
} else { |
||||
surfaceLonger = surfaceWidth; |
||||
surfaceShorter = surfaceHeight; |
||||
} |
||||
// Pick the smallest of those big enough.
|
||||
for (Size size : mPreviewSizes) { |
||||
if (size.getWidth() >= surfaceLonger && size.getHeight() >= surfaceShorter) { |
||||
return size; |
||||
} |
||||
} |
||||
// If no size is big enough, pick the largest one.
|
||||
return mPreviewSizes.last(); |
||||
} |
||||
|
||||
private void prepareImageReader() { |
||||
Size previewSize = getOptimalPreviewSize(); |
||||
AspectRatio aspectRatio = AspectRatio.of(previewSize.getWidth(), previewSize.getHeight()); |
||||
Size bestSize = findSizeClosestTo(1500000, aspectRatio, mCaptureSizes); |
||||
mImageReader = ImageReader.newInstance(bestSize.getWidth(), bestSize.getHeight(), ImageFormat.JPEG, 1); |
||||
mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler); |
||||
} |
||||
|
||||
private Size findSizeClosestTo(int targetLength, AspectRatio targetAspectRatio, SortedSet<Size> sizes) { |
||||
int closestDistance = Integer.MAX_VALUE; |
||||
Size closestSize = null; |
||||
for (Size size : sizes) { |
||||
if (targetAspectRatio.matches(size)) { |
||||
int length = size.getWidth() * size.getHeight(); |
||||
int distance = Math.abs(targetLength - length); |
||||
if (closestSize == null) { |
||||
closestSize = size; |
||||
} else { |
||||
if (distance < closestDistance) { |
||||
closestSize = size; |
||||
closestDistance = length; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
return closestSize; |
||||
} |
||||
|
||||
private void startBackgroundThread() { |
||||
mBackgroundThread = new HandlerThread("CameraBackground"); |
||||
mBackgroundThread.start(); |
||||
mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); |
||||
} |
||||
|
||||
private void stopBackgroundThread() { |
||||
mBackgroundThread.quitSafely(); |
||||
try { |
||||
mBackgroundThread.join(); |
||||
mBackgroundThread = null; |
||||
mBackgroundHandler = null; |
||||
} catch (InterruptedException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
|
||||
@SuppressWarnings("MissingPermission") |
||||
private void startOpeningCamera() { |
||||
try { |
||||
if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) { |
||||
throw new RuntimeException("Time out waiting to lock camera opening."); |
||||
} |
||||
mCameraManager.openCamera(mCameraId, mCameraDeviceCallback, mBackgroundHandler); |
||||
} catch (CameraAccessException e) { |
||||
throw new RuntimeException("Failed to open camera: " + mCameraId, e); |
||||
} catch (InterruptedException e) { |
||||
throw new RuntimeException("Time out waiting to lock camera opening."); |
||||
} |
||||
} |
||||
|
||||
void startCaptureSession() { |
||||
if (!isCameraOpened() || !mPreview.isReady() || mImageReader == null) { |
||||
return; |
||||
} |
||||
|
||||
Size previewSize = getOptimalPreviewSize(); |
||||
mPreview.setBufferSize(previewSize.getWidth(), previewSize.getHeight()); |
||||
Surface surface = mPreview.getSurface(); |
||||
try { |
||||
mPreviewRequestBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); |
||||
mPreviewRequestBuilder.addTarget(surface); |
||||
mCamera.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), mSessionCallback, mBackgroundHandler); |
||||
} catch (CameraAccessException e) { |
||||
throw new RuntimeException("Failed to start camera session"); |
||||
} catch (IllegalStateException e) { |
||||
startOpeningCamera(); |
||||
} |
||||
} |
||||
|
||||
private void lockFocus() { |
||||
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START); |
||||
try { |
||||
mCaptureCallback.setState(PictureCaptureCallback.STATE_LOCKING); |
||||
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler); |
||||
} catch (CameraAccessException e) { |
||||
Log.e(TAG, "Failed to lock focus.", e); |
||||
} |
||||
} |
||||
|
||||
private void captureStillPicture() { |
||||
try { |
||||
CaptureRequest.Builder captureRequestBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); |
||||
captureRequestBuilder.addTarget(mImageReader.getSurface()); |
||||
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, mPreviewRequestBuilder.get(CaptureRequest.CONTROL_AF_MODE)); |
||||
updateFlash(captureRequestBuilder); |
||||
// Calculate JPEG orientation.
|
||||
@SuppressWarnings("ConstantConditions") |
||||
int sensorOrientation = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); |
||||
captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, |
||||
(sensorOrientation + |
||||
mDisplayOrientation * (mFacing == Constants.FACING_FRONT ? 1 : -1) + |
||||
360) % 360); |
||||
// Stop preview and capture a still picture.
|
||||
mCaptureSession.stopRepeating(); |
||||
mCaptureSession.capture(captureRequestBuilder.build(), new CameraCaptureSession.CaptureCallback() { |
||||
@Override |
||||
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { |
||||
unlockFocus(); |
||||
} |
||||
}, mBackgroundHandler); |
||||
} catch (CameraAccessException e) { |
||||
Log.e(TAG, "Cannot capture a still picture.", e); |
||||
} |
||||
} |
||||
|
||||
void unlockFocus() { |
||||
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_CANCEL); |
||||
try { |
||||
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, null); |
||||
//updateAutoFocus();
|
||||
updateFlash(mPreviewRequestBuilder); |
||||
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE); |
||||
mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler); |
||||
mCaptureCallback.setState(PictureCaptureCallback.STATE_PREVIEW); |
||||
} catch (CameraAccessException e) { |
||||
Log.e(TAG, "Failed to restart camera preview.", e); |
||||
} |
||||
} |
||||
|
||||
|
||||
private final CameraDevice.StateCallback mCameraDeviceCallback = new CameraDevice.StateCallback() { |
||||
|
||||
@Override |
||||
public void onOpened(@NonNull CameraDevice camera) { |
||||
mCameraOpenCloseLock.release(); |
||||
mCamera = camera; |
||||
getCameraListener().onCameraOpened(); |
||||
startCaptureSession(); |
||||
} |
||||
|
||||
@Override |
||||
public void onClosed(@NonNull CameraDevice camera) { |
||||
getCameraListener().onCameraClosed(); |
||||
} |
||||
|
||||
@Override |
||||
public void onDisconnected(@NonNull CameraDevice camera) { |
||||
mCameraOpenCloseLock.release(); |
||||
mCamera.close(); |
||||
mCamera = null; |
||||
} |
||||
|
||||
@Override |
||||
public void onError(@NonNull CameraDevice camera, int error) { |
||||
mCameraOpenCloseLock.release(); |
||||
Log.e(TAG, "onError: " + camera.getId() + " (" + error + ")"); |
||||
mCamera = null; |
||||
} |
||||
|
||||
}; |
||||
|
||||
private final CameraCaptureSession.StateCallback mSessionCallback = new CameraCaptureSession.StateCallback() { |
||||
|
||||
@Override |
||||
public void onConfigured(@NonNull CameraCaptureSession session) { |
||||
if (mCamera == null) { |
||||
return; |
||||
} |
||||
mCaptureSession = session; |
||||
updateFlash(mPreviewRequestBuilder); |
||||
try { |
||||
mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler); |
||||
} catch (CameraAccessException e) { |
||||
Log.e(TAG, "Failed to start camera preview because it couldn't access camera", e); |
||||
} catch (IllegalStateException e) { |
||||
Log.e(TAG, "Failed to start camera preview.", e); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onConfigureFailed(@NonNull CameraCaptureSession session) { |
||||
Log.e(TAG, "Failed to configure capture session."); |
||||
} |
||||
|
||||
@Override |
||||
public void onClosed(@NonNull CameraCaptureSession session) { |
||||
if (mCaptureSession != null && mCaptureSession.equals(session)) { |
||||
mCaptureSession = null; |
||||
} |
||||
} |
||||
|
||||
}; |
||||
|
||||
private PictureCaptureCallback mCaptureCallback = new PictureCaptureCallback() { |
||||
|
||||
@Override |
||||
public void onPrecaptureRequired() { |
||||
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); |
||||
setState(STATE_PRECAPTURE); |
||||
try { |
||||
mCaptureSession.capture(mPreviewRequestBuilder.build(), this, mBackgroundHandler); |
||||
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); |
||||
} catch (CameraAccessException e) { |
||||
Log.e(TAG, "Failed to run precapture sequence.", e); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onReady() { |
||||
captureStillPicture(); |
||||
} |
||||
|
||||
}; |
||||
|
||||
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() { |
||||
|
||||
@Override |
||||
public void onImageAvailable(ImageReader reader) { |
||||
try (Image image = reader.acquireNextImage()) { |
||||
Image.Plane[] planes = image.getPlanes(); |
||||
if (planes.length > 0) { |
||||
ByteBuffer buffer = planes[0].getBuffer(); |
||||
byte[] data = new byte[buffer.remaining()]; |
||||
buffer.get(data); |
||||
getCameraListener().onPictureTaken(data); |
||||
} |
||||
} |
||||
} |
||||
|
||||
}; |
||||
|
||||
} |
@ -0,0 +1,27 @@ |
||||
package com.wonderkiln.camerakit; |
||||
|
||||
import java.io.File; |
||||
|
||||
public abstract class CameraListener { |
||||
|
||||
public void onCameraOpened() { |
||||
|
||||
} |
||||
|
||||
public void onCameraClosed() { |
||||
|
||||
} |
||||
|
||||
public void onPictureTaken(File picture) { |
||||
|
||||
} |
||||
|
||||
public void onPictureTaken(byte[] picture) { |
||||
|
||||
} |
||||
|
||||
public void onVideoTaken(File video) { |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,254 @@ |
||||
package com.wonderkiln.camerakit; |
||||
|
||||
import android.content.Context; |
||||
import android.os.Parcel; |
||||
import android.os.Parcelable; |
||||
import android.support.annotation.IntDef; |
||||
import android.support.annotation.NonNull; |
||||
import android.support.annotation.Nullable; |
||||
import android.support.v4.hardware.display.DisplayManagerCompat; |
||||
import android.support.v4.os.ParcelableCompat; |
||||
import android.support.v4.os.ParcelableCompatCreatorCallbacks; |
||||
import android.support.v4.view.ViewCompat; |
||||
import android.util.AttributeSet; |
||||
import android.view.Display; |
||||
import android.widget.FrameLayout; |
||||
|
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
|
||||
public class CameraView extends FrameLayout { |
||||
|
||||
public static final int FACING_BACK = Constants.FACING_BACK; |
||||
|
||||
public static final int FACING_FRONT = Constants.FACING_FRONT; |
||||
|
||||
@IntDef({FACING_BACK, FACING_FRONT}) |
||||
@Retention(RetentionPolicy.SOURCE) |
||||
public @interface Facing { |
||||
} |
||||
|
||||
public static final int FLASH_OFF = Constants.FLASH_OFF; |
||||
|
||||
public static final int FLASH_ON = Constants.FLASH_ON; |
||||
|
||||
public static final int FLASH_AUTO = Constants.FLASH_AUTO; |
||||
|
||||
@Retention(RetentionPolicy.SOURCE) |
||||
@IntDef({FLASH_OFF, FLASH_ON, FLASH_AUTO}) |
||||
public @interface Flash { |
||||
} |
||||
|
||||
public static final int PICTURE_MODE_QUALITY = Constants.PICTURE_MODE_QUALITY; |
||||
public static final int PICTURE_MODE_SPEED = Constants.PICTURE_MODE_SPEED; |
||||
|
||||
@Retention(RetentionPolicy.SOURCE) |
||||
@IntDef({PICTURE_MODE_QUALITY, PICTURE_MODE_SPEED}) |
||||
public @interface PictureMode { |
||||
} |
||||
|
||||
private int mFacing; |
||||
private int mDefaultFacing; |
||||
|
||||
private int mFlash; |
||||
private int mDefaultFlash; |
||||
|
||||
private int mPictureMode; |
||||
|
||||
private CameraListener mCameraListener; |
||||
private DisplayOrientationDetector mDisplayOrientationDetector; |
||||
|
||||
private CameraViewImpl mCameraImpl; |
||||
|
||||
public CameraView(@NonNull Context context) { |
||||
super(context, null); |
||||
} |
||||
|
||||
public CameraView(@NonNull Context context, @Nullable AttributeSet attrs) { |
||||
super(context, attrs); |
||||
|
||||
final PreviewImpl preview = new TextureViewPreview(context, this); |
||||
mCameraImpl = new Camera2(context, mCameraListener, preview); |
||||
|
||||
setFacing(mFacing); |
||||
setFlash(mFlash); |
||||
|
||||
mDisplayOrientationDetector = new DisplayOrientationDetector(context) { |
||||
@Override |
||||
public void onDisplayOrientationChanged(int displayOrientation) { |
||||
mCameraImpl.setDisplayOrientation(displayOrientation); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
@Override |
||||
protected void onAttachedToWindow() { |
||||
super.onAttachedToWindow(); |
||||
mDisplayOrientationDetector.enable( |
||||
ViewCompat.isAttachedToWindow(this) |
||||
? DisplayManagerCompat.getInstance(getContext()).getDisplay(Display.DEFAULT_DISPLAY) |
||||
: null |
||||
); |
||||
} |
||||
|
||||
@Override |
||||
protected void onDetachedFromWindow() { |
||||
mDisplayOrientationDetector.disable(); |
||||
super.onDetachedFromWindow(); |
||||
} |
||||
|
||||
@Override |
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec); |
||||
} |
||||
|
||||
@Override |
||||
protected Parcelable onSaveInstanceState() { |
||||
SavedState state = new SavedState(super.onSaveInstanceState()); |
||||
state.facing = mFacing; |
||||
state.flash = mFlash; |
||||
return state; |
||||
} |
||||
|
||||
@Override |
||||
protected void onRestoreInstanceState(Parcelable state) { |
||||
if (!(state instanceof SavedState)) { |
||||
super.onRestoreInstanceState(state); |
||||
return; |
||||
} |
||||
|
||||
SavedState ss = (SavedState) state; |
||||
super.onRestoreInstanceState(ss.getSuperState()); |
||||
setFacing(ss.facing); |
||||
setFlash(ss.flash); |
||||
} |
||||
|
||||
public void start() { |
||||
mCameraImpl.start(); |
||||
} |
||||
|
||||
public void stop() { |
||||
if (mCameraImpl != null) { |
||||
mCameraImpl.stop(); |
||||
} |
||||
} |
||||
|
||||
public void setFacing(@Facing int facing) { |
||||
this.mFacing = facing; |
||||
if (mCameraImpl != null) { |
||||
mCameraImpl.setFacing(facing); |
||||
} |
||||
} |
||||
|
||||
@Facing |
||||
public int toggleFacing() { |
||||
switch (mFacing) { |
||||
case FACING_BACK: |
||||
setFacing(FACING_FRONT); |
||||
break; |
||||
|
||||
case FACING_FRONT: |
||||
setFacing(FACING_BACK); |
||||
break; |
||||
} |
||||
|
||||
return mFacing; |
||||
} |
||||
|
||||
public void setFlash(@Flash int flash) { |
||||
this.mFlash = flash; |
||||
if (mCameraImpl != null) { |
||||
mCameraImpl.setFlash(flash); |
||||
} |
||||
} |
||||
|
||||
@Flash |
||||
public int toggleFlash() { |
||||
switch (mFlash) { |
||||
case FLASH_OFF: |
||||
setFlash(FLASH_ON); |
||||
break; |
||||
|
||||
case FLASH_ON: |
||||
setFlash(FLASH_AUTO); |
||||
break; |
||||
|
||||
case FLASH_AUTO: |
||||
setFlash(FLASH_OFF); |
||||
break; |
||||
} |
||||
|
||||
return mFlash; |
||||
} |
||||
|
||||
public void setPictureMode(@PictureMode int pictureMode) { |
||||
this.mPictureMode = pictureMode; |
||||
} |
||||
|
||||
public void setCameraListener(CameraListener cameraListener) { |
||||
this.mCameraListener = cameraListener; |
||||
mCameraImpl.setCameraListener(cameraListener); |
||||
} |
||||
|
||||
public void capturePicture() { |
||||
switch (mPictureMode) { |
||||
case PICTURE_MODE_QUALITY: |
||||
mCameraImpl.capturePicture(); |
||||
break; |
||||
case PICTURE_MODE_SPEED: |
||||
mCameraImpl.captureStill(); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
public void startRecordingVideo() { |
||||
|
||||
} |
||||
|
||||
public void stopRecordingVideo() { |
||||
|
||||
} |
||||
|
||||
protected static class SavedState extends BaseSavedState { |
||||
|
||||
@Facing |
||||
private int facing; |
||||
|
||||
@Flash |
||||
private int flash; |
||||
|
||||
@SuppressWarnings("WrongConstant") |
||||
public SavedState(Parcel source, ClassLoader loader) { |
||||
super(source); |
||||
facing = source.readInt(); |
||||
flash = source.readInt(); |
||||
} |
||||
|
||||
public SavedState(Parcelable superState) { |
||||
super(superState); |
||||
} |
||||
|
||||
@Override |
||||
public void writeToParcel(Parcel out, int flags) { |
||||
super.writeToParcel(out, flags); |
||||
out.writeInt(facing); |
||||
out.writeInt(flash); |
||||
} |
||||
|
||||
public static final Parcelable.Creator<SavedState> CREATOR = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() { |
||||
|
||||
@Override |
||||
public SavedState createFromParcel(Parcel in, ClassLoader loader) { |
||||
return new SavedState(in, loader); |
||||
} |
||||
|
||||
@Override |
||||
public SavedState[] newArray(int size) { |
||||
return new SavedState[size]; |
||||
} |
||||
|
||||
}); |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,52 @@ |
||||
package com.wonderkiln.camerakit; |
||||
|
||||
import android.view.View; |
||||
|
||||
abstract class CameraViewImpl { |
||||
|
||||
protected CameraListener mCameraListener; |
||||
|
||||
protected final PreviewImpl mPreview; |
||||
|
||||
CameraViewImpl(CameraListener callback, PreviewImpl preview) { |
||||
mCameraListener = callback; |
||||
mPreview = preview; |
||||
} |
||||
|
||||
View getView() { |
||||
return mPreview.getView(); |
||||
} |
||||
|
||||
abstract void start(); |
||||
|
||||
abstract void stop(); |
||||
|
||||
abstract boolean isCameraOpened(); |
||||
|
||||
abstract void setFacing(int facing); |
||||
|
||||
abstract int getFacing(); |
||||
|
||||
abstract void setFlash(int flash); |
||||
|
||||
abstract int getFlash(); |
||||
|
||||
abstract void capturePicture(); |
||||
|
||||
abstract void captureStill(); |
||||
|
||||
abstract void startVideo(); |
||||
|
||||
abstract void endVideo(); |
||||
|
||||
abstract void setDisplayOrientation(int displayOrientation); |
||||
|
||||
void setCameraListener(CameraListener cameraListener) { |
||||
this.mCameraListener = cameraListener; |
||||
} |
||||
|
||||
protected CameraListener getCameraListener() { |
||||
return mCameraListener != null ? mCameraListener : new CameraListener() {}; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,15 @@ |
||||
package com.wonderkiln.camerakit; |
||||
|
||||
public class Constants { |
||||
|
||||
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 PICTURE_MODE_QUALITY = 0; |
||||
public static final int PICTURE_MODE_SPEED = 1; |
||||
|
||||
} |
@ -0,0 +1,69 @@ |
||||
package com.wonderkiln.camerakit; |
||||
|
||||
import android.content.Context; |
||||
import android.util.SparseIntArray; |
||||
import android.view.Display; |
||||
import android.view.OrientationEventListener; |
||||
import android.view.Surface; |
||||
|
||||
abstract class DisplayOrientationDetector { |
||||
|
||||
private final OrientationEventListener mOrientationEventListener; |
||||
|
||||
static final SparseIntArray DISPLAY_ORIENTATIONS = new SparseIntArray(); |
||||
|
||||
static { |
||||
DISPLAY_ORIENTATIONS.put(Surface.ROTATION_0, 0); |
||||
DISPLAY_ORIENTATIONS.put(Surface.ROTATION_90, 90); |
||||
DISPLAY_ORIENTATIONS.put(Surface.ROTATION_180, 180); |
||||
DISPLAY_ORIENTATIONS.put(Surface.ROTATION_270, 270); |
||||
} |
||||
|
||||
private Display mDisplay; |
||||
|
||||
private int mLastKnownDisplayOrientation = 0; |
||||
|
||||
public DisplayOrientationDetector(Context context) { |
||||
mOrientationEventListener = new OrientationEventListener(context) { |
||||
|
||||
private int mLastKnownRotation = -1; |
||||
|
||||
@Override |
||||
public void onOrientationChanged(int orientation) { |
||||
if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN || |
||||
mDisplay == null) { |
||||
return; |
||||
} |
||||
final int rotation = mDisplay.getRotation(); |
||||
if (mLastKnownRotation != rotation) { |
||||
mLastKnownRotation = rotation; |
||||
dispatchOnDisplayOrientationChanged(DISPLAY_ORIENTATIONS.get(rotation)); |
||||
} |
||||
} |
||||
}; |
||||
} |
||||
|
||||
public void enable(Display display) { |
||||
mDisplay = display; |
||||
mOrientationEventListener.enable(); |
||||
// Immediately dispatch the first callback
|
||||
dispatchOnDisplayOrientationChanged(DISPLAY_ORIENTATIONS.get(display.getRotation())); |
||||
} |
||||
|
||||
public void disable() { |
||||
mOrientationEventListener.disable(); |
||||
mDisplay = null; |
||||
} |
||||
|
||||
public int getLastKnownDisplayOrientation() { |
||||
return mLastKnownDisplayOrientation; |
||||
} |
||||
|
||||
void dispatchOnDisplayOrientationChanged(int displayOrientation) { |
||||
mLastKnownDisplayOrientation = displayOrientation; |
||||
onDisplayOrientationChanged(displayOrientation); |
||||
} |
||||
|
||||
public abstract void onDisplayOrientationChanged(int displayOrientation); |
||||
|
||||
} |
@ -0,0 +1,81 @@ |
||||
package com.wonderkiln.camerakit; |
||||
|
||||
import android.hardware.camera2.CameraCaptureSession; |
||||
import android.hardware.camera2.CaptureRequest; |
||||
import android.hardware.camera2.CaptureResult; |
||||
import android.hardware.camera2.TotalCaptureResult; |
||||
import android.support.annotation.NonNull; |
||||
|
||||
abstract class PictureCaptureCallback extends CameraCaptureSession.CaptureCallback { |
||||
|
||||
static final int STATE_PREVIEW = 0; |
||||
static final int STATE_LOCKING = 1; |
||||
static final int STATE_LOCKED = 2; |
||||
static final int STATE_PRECAPTURE = 3; |
||||
static final int STATE_WAITING = 4; |
||||
static final int STATE_CAPTURING = 5; |
||||
|
||||
private int mState; |
||||
|
||||
PictureCaptureCallback() { |
||||
} |
||||
|
||||
void setState(int state) { |
||||
mState = state; |
||||
} |
||||
|
||||
@Override |
||||
public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) { |
||||
process(partialResult); |
||||
} |
||||
|
||||
@Override |
||||
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { |
||||
process(result); |
||||
} |
||||
|
||||
private void process(@NonNull CaptureResult result) { |
||||
switch (mState) { |
||||
case STATE_LOCKING: { |
||||
Integer af = result.get(CaptureResult.CONTROL_AF_STATE); |
||||
if (af == null) { |
||||
break; |
||||
} |
||||
if (af == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED || |
||||
af == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) { |
||||
Integer ae = result.get(CaptureResult.CONTROL_AE_STATE); |
||||
if (ae == null || ae == CaptureResult.CONTROL_AE_STATE_CONVERGED) { |
||||
setState(STATE_CAPTURING); |
||||
onReady(); |
||||
} else { |
||||
setState(STATE_LOCKED); |
||||
onPrecaptureRequired(); |
||||
} |
||||
} |
||||
break; |
||||
} |
||||
case STATE_PRECAPTURE: { |
||||
Integer ae = result.get(CaptureResult.CONTROL_AE_STATE); |
||||
if (ae == null || ae == CaptureResult.CONTROL_AE_STATE_PRECAPTURE || |
||||
ae == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED || |
||||
ae == CaptureResult.CONTROL_AE_STATE_CONVERGED) { |
||||
setState(STATE_WAITING); |
||||
} |
||||
break; |
||||
} |
||||
case STATE_WAITING: { |
||||
Integer ae = result.get(CaptureResult.CONTROL_AE_STATE); |
||||
if (ae == null || ae != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) { |
||||
setState(STATE_CAPTURING); |
||||
onReady(); |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
public abstract void onReady(); |
||||
|
||||
public abstract void onPrecaptureRequired(); |
||||
|
||||
} |
@ -0,0 +1,62 @@ |
||||
package com.wonderkiln.camerakit; |
||||
|
||||
import android.graphics.SurfaceTexture; |
||||
import android.view.Surface; |
||||
import android.view.SurfaceHolder; |
||||
import android.view.View; |
||||
|
||||
abstract class PreviewImpl { |
||||
|
||||
interface Callback { |
||||
void onSurfaceChanged(); |
||||
} |
||||
|
||||
private Callback mCallback; |
||||
|
||||
private int mWidth; |
||||
|
||||
private int mHeight; |
||||
|
||||
void setCallback(Callback callback) { |
||||
mCallback = callback; |
||||
} |
||||
|
||||
abstract Surface getSurface(); |
||||
|
||||
abstract View getView(); |
||||
|
||||
abstract Class getOutputClass(); |
||||
|
||||
abstract void setDisplayOrientation(int displayOrientation); |
||||
|
||||
abstract boolean isReady(); |
||||
|
||||
protected void dispatchSurfaceChanged() { |
||||
mCallback.onSurfaceChanged(); |
||||
} |
||||
|
||||
SurfaceHolder getSurfaceHolder() { |
||||
return null; |
||||
} |
||||
|
||||
SurfaceTexture getSurfaceTexture() { |
||||
return null; |
||||
} |
||||
|
||||
void setBufferSize(int width, int height) { |
||||
} |
||||
|
||||
void setSize(int width, int height) { |
||||
mWidth = width; |
||||
mHeight = height; |
||||
} |
||||
|
||||
int getWidth() { |
||||
return mWidth; |
||||
} |
||||
|
||||
int getHeight() { |
||||
return mHeight; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,54 @@ |
||||
package com.wonderkiln.camerakit; |
||||
|
||||
import android.support.annotation.NonNull; |
||||
|
||||
public class Size implements Comparable<Size> { |
||||
|
||||
private final int mWidth; |
||||
private final int mHeight; |
||||
|
||||
public Size(int width, int height) { |
||||
mWidth = width; |
||||
mHeight = height; |
||||
} |
||||
|
||||
public int getWidth() { |
||||
return mWidth; |
||||
} |
||||
|
||||
public int getHeight() { |
||||
return mHeight; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
if (o == null) { |
||||
return false; |
||||
} |
||||
if (this == o) { |
||||
return true; |
||||
} |
||||
if (o instanceof Size) { |
||||
Size size = (Size) o; |
||||
return mWidth == size.mWidth && mHeight == size.mHeight; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return mWidth + "x" + mHeight; |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
// assuming most sizes are <2^16, doing a rotate will give us perfect hashing
|
||||
return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2))); |
||||
} |
||||
|
||||
@Override |
||||
public int compareTo(@NonNull Size another) { |
||||
return mWidth * mHeight - another.mWidth * another.mHeight; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,130 @@ |
||||
package com.wonderkiln.camerakit; |
||||
|
||||
import android.annotation.TargetApi; |
||||
import android.content.Context; |
||||
import android.graphics.Matrix; |
||||
import android.graphics.SurfaceTexture; |
||||
import android.view.Surface; |
||||
import android.view.TextureView; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
|
||||
@TargetApi(14) |
||||
public class TextureViewPreview extends PreviewImpl { |
||||
|
||||
private final TextureView mTextureView; |
||||
|
||||
private int mDisplayOrientation; |
||||
|
||||
TextureViewPreview(Context context, ViewGroup parent) { |
||||
final View view = View.inflate(context, R.layout.texture_view, parent); |
||||
mTextureView = (TextureView) view.findViewById(R.id.texture_view); |
||||
mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { |
||||
|
||||
@Override |
||||
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { |
||||
setSize(width, height); |
||||
configureTransform(); |
||||
dispatchSurfaceChanged(); |
||||
} |
||||
|
||||
@Override |
||||
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { |
||||
setSize(width, height); |
||||
configureTransform(); |
||||
dispatchSurfaceChanged(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { |
||||
setSize(0, 0); |
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public void onSurfaceTextureUpdated(SurfaceTexture surface) { |
||||
} |
||||
}); |
||||
} |
||||
|
||||
@Override |
||||
void setCallback(Callback callback) { |
||||
super.setCallback(callback); |
||||
} |
||||
|
||||
@Override |
||||
Surface getSurface() { |
||||
return new Surface(mTextureView.getSurfaceTexture()); |
||||
} |
||||
|
||||
@Override |
||||
View getView() { |
||||
return mTextureView; |
||||
} |
||||
|
||||
@Override |
||||
Class getOutputClass() { |
||||
return SurfaceTexture.class; |
||||
} |
||||
|
||||
@Override |
||||
void setDisplayOrientation(int displayOrientation) { |
||||
mDisplayOrientation = displayOrientation; |
||||
configureTransform(); |
||||
} |
||||
|
||||
@Override |
||||
boolean isReady() { |
||||
return mTextureView.getSurfaceTexture() != null; |
||||
} |
||||
|
||||
@Override |
||||
protected void dispatchSurfaceChanged() { |
||||
super.dispatchSurfaceChanged(); |
||||
} |
||||
|
||||
@Override |
||||
SurfaceTexture getSurfaceTexture() { |
||||
return mTextureView.getSurfaceTexture(); |
||||
} |
||||
|
||||
@TargetApi(15) |
||||
@Override |
||||
void setBufferSize(int width, int height) { |
||||
mTextureView.getSurfaceTexture().setDefaultBufferSize(width, height); |
||||
} |
||||
|
||||
void configureTransform() { |
||||
Matrix matrix = new Matrix(); |
||||
if (mDisplayOrientation % 180 == 90) { |
||||
final int width = getWidth(); |
||||
final int height = getHeight(); |
||||
// Rotate the camera preview when the screen is landscape.
|
||||
matrix.setPolyToPoly( |
||||
new float[]{ |
||||
0.f, 0.f, // top left
|
||||
width, 0.f, // top right
|
||||
0.f, height, // bottom left
|
||||
width, height, // bottom right
|
||||
}, 0, |
||||
mDisplayOrientation == 90 ? |
||||
// Clockwise
|
||||
new float[]{ |
||||
0.f, height, // top left
|
||||
0.f, 0.f, // top right
|
||||
width, height, // bottom left
|
||||
width, 0.f, // bottom right
|
||||
} : // mDisplayOrientation == 270
|
||||
// Counter-clockwise
|
||||
new float[]{ |
||||
width, 0.f, // top left
|
||||
width, height, // top right
|
||||
0.f, 0.f, // bottom left
|
||||
0.f, height, // bottom right
|
||||
}, 0, |
||||
4); |
||||
} |
||||
mTextureView.setTransform(matrix); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,9 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"> |
||||
|
||||
<TextureView |
||||
android:id="@+id/texture_view" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" /> |
||||
|
||||
</merge> |
@ -0,0 +1,8 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources> |
||||
|
||||
<declare-styleable name="CameraView"> |
||||
|
||||
</declare-styleable> |
||||
|
||||
</resources> |
@ -0,0 +1,3 @@ |
||||
<resources> |
||||
<string name="app_name">CameraKit</string> |
||||
</resources> |
@ -0,0 +1,17 @@ |
||||
package com.wonderkiln.camerakit; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
import static org.junit.Assert.*; |
||||
|
||||
/** |
||||
* Example local unit test, which will execute on the development machine (host). |
||||
* |
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a> |
||||
*/ |
||||
public class ExampleUnitTest { |
||||
@Test |
||||
public void addition_isCorrect() throws Exception { |
||||
assertEquals(4, 2 + 2); |
||||
} |
||||
} |
@ -0,0 +1,17 @@ |
||||
# Project-wide Gradle settings. |
||||
|
||||
# IDE (e.g. Android Studio) users: |
||||
# Gradle settings configured through the IDE *will override* |
||||
# any settings specified in this file. |
||||
|
||||
# For more details on how to configure your build environment visit |
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html |
||||
|
||||
# Specifies the JVM arguments used for the daemon process. |
||||
# The setting is particularly useful for tweaking memory settings. |
||||
org.gradle.jvmargs=-Xmx1536m |
||||
|
||||
# When configured, Gradle will run in incubating parallel mode. |
||||
# This option should only be used with decoupled projects. More details, visit |
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects |
||||
# org.gradle.parallel=true |
@ -0,0 +1,6 @@ |
||||
#Tue Jan 17 16:25:25 EST 2017 |
||||
distributionBase=GRADLE_USER_HOME |
||||
distributionPath=wrapper/dists |
||||
zipStoreBase=GRADLE_USER_HOME |
||||
zipStorePath=wrapper/dists |
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.2-all.zip |
@ -0,0 +1,160 @@ |
||||
#!/usr/bin/env bash |
||||
|
||||
############################################################################## |
||||
## |
||||
## Gradle start up script for UN*X |
||||
## |
||||
############################################################################## |
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. |
||||
DEFAULT_JVM_OPTS="" |
||||
|
||||
APP_NAME="Gradle" |
||||
APP_BASE_NAME=`basename "$0"` |
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value. |
||||
MAX_FD="maximum" |
||||
|
||||
warn ( ) { |
||||
echo "$*" |
||||
} |
||||
|
||||
die ( ) { |
||||
echo |
||||
echo "$*" |
||||
echo |
||||
exit 1 |
||||
} |
||||
|
||||
# OS specific support (must be 'true' or 'false'). |
||||
cygwin=false |
||||
msys=false |
||||
darwin=false |
||||
case "`uname`" in |
||||
CYGWIN* ) |
||||
cygwin=true |
||||
;; |
||||
Darwin* ) |
||||
darwin=true |
||||
;; |
||||
MINGW* ) |
||||
msys=true |
||||
;; |
||||
esac |
||||
|
||||
# Attempt to set APP_HOME |
||||
# Resolve links: $0 may be a link |
||||
PRG="$0" |
||||
# Need this for relative symlinks. |
||||
while [ -h "$PRG" ] ; do |
||||
ls=`ls -ld "$PRG"` |
||||
link=`expr "$ls" : '.*-> \(.*\)$'` |
||||
if expr "$link" : '/.*' > /dev/null; then |
||||
PRG="$link" |
||||
else |
||||
PRG=`dirname "$PRG"`"/$link" |
||||
fi |
||||
done |
||||
SAVED="`pwd`" |
||||
cd "`dirname \"$PRG\"`/" >/dev/null |
||||
APP_HOME="`pwd -P`" |
||||
cd "$SAVED" >/dev/null |
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar |
||||
|
||||
# Determine the Java command to use to start the JVM. |
||||
if [ -n "$JAVA_HOME" ] ; then |
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then |
||||
# IBM's JDK on AIX uses strange locations for the executables |
||||
JAVACMD="$JAVA_HOME/jre/sh/java" |
||||
else |
||||
JAVACMD="$JAVA_HOME/bin/java" |
||||
fi |
||||
if [ ! -x "$JAVACMD" ] ; then |
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME |
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the |
||||
location of your Java installation." |
||||
fi |
||||
else |
||||
JAVACMD="java" |
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. |
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the |
||||
location of your Java installation." |
||||
fi |
||||
|
||||
# Increase the maximum file descriptors if we can. |
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then |
||||
MAX_FD_LIMIT=`ulimit -H -n` |
||||
if [ $? -eq 0 ] ; then |
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then |
||||
MAX_FD="$MAX_FD_LIMIT" |
||||
fi |
||||
ulimit -n $MAX_FD |
||||
if [ $? -ne 0 ] ; then |
||||
warn "Could not set maximum file descriptor limit: $MAX_FD" |
||||
fi |
||||
else |
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" |
||||
fi |
||||
fi |
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock |
||||
if $darwin; then |
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" |
||||
fi |
||||
|
||||
# For Cygwin, switch paths to Windows format before running java |
||||
if $cygwin ; then |
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"` |
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` |
||||
JAVACMD=`cygpath --unix "$JAVACMD"` |
||||
|
||||
# We build the pattern for arguments to be converted via cygpath |
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` |
||||
SEP="" |
||||
for dir in $ROOTDIRSRAW ; do |
||||
ROOTDIRS="$ROOTDIRS$SEP$dir" |
||||
SEP="|" |
||||
done |
||||
OURCYGPATTERN="(^($ROOTDIRS))" |
||||
# Add a user-defined pattern to the cygpath arguments |
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then |
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" |
||||
fi |
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh |
||||
i=0 |
||||
for arg in "$@" ; do |
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` |
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option |
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition |
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` |
||||
else |
||||
eval `echo args$i`="\"$arg\"" |
||||
fi |
||||
i=$((i+1)) |
||||
done |
||||
case $i in |
||||
(0) set -- ;; |
||||
(1) set -- "$args0" ;; |
||||
(2) set -- "$args0" "$args1" ;; |
||||
(3) set -- "$args0" "$args1" "$args2" ;; |
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;; |
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; |
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; |
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; |
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; |
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; |
||||
esac |
||||
fi |
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules |
||||
function splitJvmOpts() { |
||||
JVM_OPTS=("$@") |
||||
} |
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS |
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" |
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" |
@ -0,0 +1,90 @@ |
||||
@if "%DEBUG%" == "" @echo off |
||||
@rem ########################################################################## |
||||
@rem |
||||
@rem Gradle startup script for Windows |
||||
@rem |
||||
@rem ########################################################################## |
||||
|
||||
@rem Set local scope for the variables with windows NT shell |
||||
if "%OS%"=="Windows_NT" setlocal |
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. |
||||
set DEFAULT_JVM_OPTS= |
||||
|
||||
set DIRNAME=%~dp0 |
||||
if "%DIRNAME%" == "" set DIRNAME=. |
||||
set APP_BASE_NAME=%~n0 |
||||
set APP_HOME=%DIRNAME% |
||||
|
||||
@rem Find java.exe |
||||
if defined JAVA_HOME goto findJavaFromJavaHome |
||||
|
||||
set JAVA_EXE=java.exe |
||||
%JAVA_EXE% -version >NUL 2>&1 |
||||
if "%ERRORLEVEL%" == "0" goto init |
||||
|
||||
echo. |
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. |
||||
echo. |
||||
echo Please set the JAVA_HOME variable in your environment to match the |
||||
echo location of your Java installation. |
||||
|
||||
goto fail |
||||
|
||||
:findJavaFromJavaHome |
||||
set JAVA_HOME=%JAVA_HOME:"=% |
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe |
||||
|
||||
if exist "%JAVA_EXE%" goto init |
||||
|
||||
echo. |
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% |
||||
echo. |
||||
echo Please set the JAVA_HOME variable in your environment to match the |
||||
echo location of your Java installation. |
||||
|
||||
goto fail |
||||
|
||||
:init |
||||
@rem Get command-line arguments, handling Windowz variants |
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args |
||||
if "%@eval[2+2]" == "4" goto 4NT_args |
||||
|
||||
:win9xME_args |
||||
@rem Slurp the command line arguments. |
||||
set CMD_LINE_ARGS= |
||||
set _SKIP=2 |
||||
|
||||
:win9xME_args_slurp |
||||
if "x%~1" == "x" goto execute |
||||
|
||||
set CMD_LINE_ARGS=%* |
||||
goto execute |
||||
|
||||
:4NT_args |
||||
@rem Get arguments from the 4NT Shell from JP Software |
||||
set CMD_LINE_ARGS=%$ |
||||
|
||||
:execute |
||||
@rem Setup the command line |
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar |
||||
|
||||
@rem Execute Gradle |
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% |
||||
|
||||
:end |
||||
@rem End local scope for the variables with windows NT shell |
||||
if "%ERRORLEVEL%"=="0" goto mainEnd |
||||
|
||||
:fail |
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of |
||||
rem the _cmd.exe /c_ return code! |
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 |
||||
exit /b 1 |
||||
|
||||
:mainEnd |
||||
if "%OS%"=="Windows_NT" endlocal |
||||
|
||||
:omega |
@ -0,0 +1 @@ |
||||
include ':app', ':camerakit' |