Skip to content

Commit 8ff6779

Browse files
committed
Feature/chromebook (#2)
* Make rotation work for fixed portrait in manifest * dfsa * Cleaning up Logs * Appearing to work * dfa * j * onVideoStarted Callback Removing Logs
1 parent b99cc8f commit 8ff6779

File tree

12 files changed

+240
-36
lines changed

12 files changed

+240
-36
lines changed

build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ buildscript {
55
jcenter()
66
}
77
dependencies {
8-
classpath 'com.android.tools.build:gradle:2.3.0'
8+
classpath 'com.android.tools.build:gradle:2.3.3'
99

1010
// NOTE: Do not place your application dependencies here; they belong
1111
// in the individual module build.gradle files

camerakit/build.gradle

+8-5
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,21 @@ ext {
88

99
android {
1010
compileSdkVersion 25
11-
buildToolsVersion "25.0.2"
11+
buildToolsVersion "25.0.3"
1212

1313
defaultConfig {
14-
minSdkVersion 15
14+
minSdkVersion 18
1515
targetSdkVersion 25
1616
versionCode 1
1717
versionName "1.0"
18+
19+
multiDexEnabled true
20+
vectorDrawables.useSupportLibrary = true // required for upgrade to 23.0.2 build tools
1821
}
1922
buildTypes {
2023
release {
2124
minifyEnabled false
22-
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
25+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
2326
}
2427
}
2528
sourceSets {
@@ -32,8 +35,8 @@ android {
3235
}
3336

3437
dependencies {
35-
compile 'com.android.support:appcompat-v7:25.2.0'
36-
38+
compile 'com.android.support:appcompat-v7:25.3.1'
39+
compile "com.android.support:exifinterface:25.3.1"
3740

3841
compile 'android.arch.lifecycle:runtime:1.0.0-alpha1'
3942
compile 'android.arch.lifecycle:extensions:1.0.0-alpha1'

camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java

+38-14
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
import android.media.MediaRecorder;
88
import android.os.Build;
99
import android.os.Handler;
10-
import android.util.Log;
1110
import android.support.annotation.Nullable;
11+
import android.util.Log;
1212
import android.view.MotionEvent;
1313
import android.view.SurfaceHolder;
1414
import android.view.View;
@@ -17,7 +17,6 @@
1717
import java.io.IOException;
1818
import java.util.ArrayList;
1919
import java.util.HashSet;
20-
import java.util.Iterator;
2120
import java.util.List;
2221
import java.util.Set;
2322
import java.util.TreeSet;
@@ -51,6 +50,7 @@ public class Camera1 extends CameraImpl {
5150
private boolean capturingImage = false;
5251

5352
private int mDisplayOrientation;
53+
private int mDeviceOrientation;
5454

5555
@Facing
5656
private int mFacing;
@@ -85,7 +85,6 @@ public void onSurfaceChanged() {
8585
});
8686

8787
mCameraInfo = new Camera.CameraInfo();
88-
8988
}
9089

9190
// CameraImpl:
@@ -106,8 +105,9 @@ void stop() {
106105
}
107106

108107
@Override
109-
void setDisplayOrientation(int displayOrientation) {
108+
void setDisplayOrientation(int displayOrientation, int deviceOrientation) {
110109
this.mDisplayOrientation = displayOrientation;
110+
this.mDeviceOrientation = deviceOrientation;
111111
}
112112

113113
@Override
@@ -221,6 +221,11 @@ void captureImage() {
221221
// Set boolean to wait for image callback
222222
capturingImage = true;
223223

224+
// Set the captureRotation right before taking a picture so it's accurate
225+
int captureRotation = calculateCaptureRotation();
226+
mCameraParameters.setRotation(captureRotation);
227+
mCamera.setParameters(mCameraParameters);
228+
224229
mCamera.takePicture(null, null, null,
225230
new Camera.PictureCallback() {
226231
@Override
@@ -260,6 +265,7 @@ void startVideo() {
260265
initMediaRecorder();
261266
prepareMediaRecorder();
262267
mMediaRecorder.start();
268+
mCameraListener.onVideoStarted();
263269
}
264270

265271
@Override
@@ -351,6 +357,14 @@ boolean isCameraOpened() {
351357
return mCamera != null;
352358
}
353359

360+
@Override
361+
boolean frontCameraOnly() {
362+
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
363+
Camera.getCameraInfo(0, cameraInfo);
364+
boolean isFrontCameraOnly = (Camera.getNumberOfCameras() == 1 && cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT);
365+
return isFrontCameraOnly;
366+
}
367+
354368
@Nullable
355369
@Override
356370
CameraProperties getCameraProperties() {
@@ -399,29 +413,39 @@ private void releaseCamera() {
399413

400414
private int calculatePreviewRotation() {
401415
if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
402-
return ((mCameraInfo.orientation - mDisplayOrientation) + 360 + 180) % 360;
416+
int result = (mCameraInfo.orientation + mDisplayOrientation) % 360;
417+
return (360 - result) % 360;
403418
} else {
404419
return (mCameraInfo.orientation - mDisplayOrientation + 360) % 360;
405420
}
406421
}
407422

408423
private int calculateCaptureRotation() {
409-
int previewRotation = calculatePreviewRotation();
424+
int captureRotation = 0;
410425
if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
411-
//Front is flipped
412-
return (previewRotation + 180 + 2*mDisplayOrientation + 720) %360;
413-
} else {
414-
return previewRotation;
426+
captureRotation = (mCameraInfo.orientation + mDisplayOrientation) % 360;
427+
} else { // back-facing camera
428+
captureRotation = (mCameraInfo.orientation - mDisplayOrientation + 360) % 360;
429+
}
430+
431+
// Accommodate for any extra device rotation relative to fixed screen orientations
432+
// (e.g. activity fixed in portrait, but user took photo/video in landscape)
433+
if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
434+
captureRotation = ((captureRotation - (mDisplayOrientation - mDeviceOrientation)) + 360) % 360;
435+
} else { // back-facing camera
436+
captureRotation = (captureRotation + (mDisplayOrientation - mDeviceOrientation) + 360) % 360;
415437
}
438+
439+
return captureRotation;
416440
}
417441

418442
private void adjustCameraParameters() {
419443
initResolutions();
420444

421-
boolean invertPreviewSizes = mDisplayOrientation%180 != 0;
445+
boolean invertPreviewSizes = (mCameraInfo.orientation + mDisplayOrientation) % 180 == 0;
422446
mPreview.setTruePreviewSize(
423-
invertPreviewSizes? getPreviewResolution().getHeight() : getPreviewResolution().getWidth(),
424-
invertPreviewSizes? getPreviewResolution().getWidth() : getPreviewResolution().getHeight()
447+
invertPreviewSizes ? getPreviewResolution().getHeight() : getPreviewResolution().getWidth(),
448+
invertPreviewSizes ? getPreviewResolution().getWidth() : getPreviewResolution().getHeight()
425449
);
426450

427451
mCameraParameters.setPreviewSize(
@@ -483,7 +507,7 @@ private void initMediaRecorder() {
483507

484508
mVideoFile = new File(mPreview.getView().getContext().getExternalFilesDir(null), "video.mp4");
485509
mMediaRecorder.setOutputFile(mVideoFile.getAbsolutePath());
486-
mMediaRecorder.setOrientationHint(calculatePreviewRotation());
510+
mMediaRecorder.setOrientationHint(calculateCaptureRotation());
487511
mMediaRecorder.setVideoSize(mCaptureSize.getWidth(), mCaptureSize.getHeight());
488512
}
489513

camerakit/src/main/api21/com/flurgle/camerakit/Camera2.java

+19-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import android.annotation.TargetApi;
44
import android.content.Context;
55
import android.graphics.ImageFormat;
6-
import android.graphics.PointF;
76
import android.hardware.camera2.CameraAccessException;
87
import android.hardware.camera2.CameraCharacteristics;
98
import android.hardware.camera2.CameraDevice;
@@ -89,7 +88,7 @@ void stop() {
8988
}
9089

9190
@Override
92-
void setDisplayOrientation(int displayOrientation) {
91+
void setDisplayOrientation(int displayOrientation, int deviceOrientation) {
9392

9493
}
9594

@@ -232,6 +231,24 @@ boolean isCameraOpened() {
232231
return mCamera != null;
233232
}
234233

234+
@Override
235+
boolean frontCameraOnly() {
236+
try {
237+
for (final String cameraId : mCameraManager.getCameraIdList()) {
238+
CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId);
239+
@SuppressWarnings("ConstantConditions")
240+
int orientation = characteristics.get(CameraCharacteristics.LENS_FACING);
241+
if (orientation == CameraCharacteristics.LENS_FACING_BACK) {
242+
return false;
243+
}
244+
}
245+
246+
return true;
247+
} catch (CameraAccessException e) {
248+
throw new RuntimeException("Failed to get camera view angles", e);
249+
}
250+
}
251+
235252
@Nullable
236253
@Override
237254
CameraProperties getCameraProperties() {

camerakit/src/main/base/com/flurgle/camerakit/CameraImpl.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ abstract class CameraImpl {
1515
abstract void start();
1616
abstract void stop();
1717

18-
abstract void setDisplayOrientation(int displayOrientation);
18+
abstract void setDisplayOrientation(int displayOrientation, int deviceOrientation);
1919

2020
abstract void setFacing(@Facing int facing);
2121
abstract void setFlash(@Flash int flash);
@@ -31,6 +31,7 @@ abstract class CameraImpl {
3131
abstract Size getCaptureResolution();
3232
abstract Size getPreviewResolution();
3333
abstract boolean isCameraOpened();
34+
abstract boolean frontCameraOnly();
3435

3536
@Nullable
3637
abstract CameraProperties getCameraProperties();

camerakit/src/main/java/com/flurgle/camerakit/CameraKit.java

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public static class Constants {
3838
public static final int PERMISSIONS_STRICT = 0;
3939
public static final int PERMISSIONS_LAZY = 1;
4040
public static final int PERMISSIONS_PICTURE = 2;
41+
public static final int PERMISSIONS_OFF = 3;
4142

4243
public static final int VIDEO_QUALITY_480P = 0;
4344
public static final int VIDEO_QUALITY_720P = 1;

camerakit/src/main/java/com/flurgle/camerakit/CameraListener.java

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ public void onPictureTaken(YuvImage yuv) {
2222

2323
}
2424

25+
public void onVideoStarted() {
26+
27+
}
28+
2529
public void onVideoTaken(File video) {
2630

2731
}

camerakit/src/main/java/com/flurgle/camerakit/CameraView.java

+35-3
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,24 @@
1010
import android.content.ContextWrapper;
1111
import android.content.pm.PackageManager;
1212
import android.content.res.TypedArray;
13+
import android.graphics.Bitmap;
1314
import android.graphics.Rect;
1415
import android.graphics.YuvImage;
1516
import android.os.Handler;
1617
import android.os.HandlerThread;
1718
import android.support.annotation.NonNull;
1819
import android.support.annotation.Nullable;
20+
import android.support.media.ExifInterface;
1921
import android.support.v4.app.ActivityCompat;
2022
import android.support.v4.content.ContextCompat;
2123
import android.support.v4.hardware.display.DisplayManagerCompat;
2224
import android.support.v4.view.ViewCompat;
2325
import android.util.AttributeSet;
2426
import android.view.Display;
2527
import android.view.MotionEvent;
28+
import android.view.Surface;
2629
import android.view.View;
30+
import android.view.WindowManager;
2731
import android.widget.FrameLayout;
2832

2933
import java.io.ByteArrayOutputStream;
@@ -39,6 +43,7 @@
3943
import static com.flurgle.camerakit.CameraKit.Constants.FLASH_TORCH;
4044
import static com.flurgle.camerakit.CameraKit.Constants.METHOD_STANDARD;
4145
import static com.flurgle.camerakit.CameraKit.Constants.PERMISSIONS_LAZY;
46+
import static com.flurgle.camerakit.CameraKit.Constants.PERMISSIONS_OFF;
4247
import static com.flurgle.camerakit.CameraKit.Constants.PERMISSIONS_PICTURE;
4348
import static com.flurgle.camerakit.CameraKit.Constants.PERMISSIONS_STRICT;
4449

@@ -144,6 +149,14 @@ private void init(@NonNull Context context, @Nullable AttributeSet attrs) {
144149
mCameraImpl = new Camera1(mCameraListener, mPreviewImpl);
145150

146151
mIsStarted = false;
152+
153+
// Handle situations where there's only 1 camera & it's front facing OR it's a chromebook in laptop mode
154+
WindowManager windowService = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
155+
boolean isChromebookInLaptopMode = (context.getPackageManager().hasSystemFeature("org.chromium.arc.device_management") && windowService.getDefaultDisplay().getRotation() == Surface.ROTATION_0);
156+
if(mCameraImpl.frontCameraOnly() || isChromebookInLaptopMode){
157+
mFacing = FACING_FRONT;
158+
}
159+
147160
setFacing(mFacing);
148161
setFlash(mFlash);
149162
setFocus(mFocus);
@@ -155,8 +168,8 @@ private void init(@NonNull Context context, @Nullable AttributeSet attrs) {
155168
if (!isInEditMode()) {
156169
mDisplayOrientationDetector = new DisplayOrientationDetector(context) {
157170
@Override
158-
public void onDisplayOrientationChanged(int displayOrientation) {
159-
mCameraImpl.setDisplayOrientation(displayOrientation);
171+
public void onDisplayOrientationChanged(int displayOrientation, int deviceOrientation) {
172+
mCameraImpl.setDisplayOrientation(displayOrientation, deviceOrientation);
160173
mPreviewImpl.setDisplayOrientation(displayOrientation);
161174
}
162175
};
@@ -293,6 +306,8 @@ public void start() {
293306
return;
294307
}
295308
break;
309+
case PERMISSIONS_OFF:
310+
break;
296311
}
297312

298313
sWorkerHandler.post(new Runnable() {
@@ -468,6 +483,7 @@ private class CameraListenerMiddleWare extends CameraListener {
468483
@Override
469484
public void onCameraOpened() {
470485
super.onCameraOpened();
486+
471487
getCameraListener().onCameraOpened();
472488
}
473489

@@ -480,6 +496,16 @@ public void onCameraClosed() {
480496
@Override
481497
public void onPictureTaken(byte[] jpeg) {
482498
super.onPictureTaken(jpeg);
499+
500+
// Handle cameras that don't give us the correctly rotated/mirrored image, but instead just set the corresponding EXIF data.
501+
// Exif data is lost when we do a BitmapFactory.decodeByteArray, so need to correct image here.
502+
if(ExifUtil.getExifOrientation(jpeg) != ExifInterface.ORIENTATION_NORMAL || mFacing == FACING_FRONT){
503+
Bitmap bitmap = ExifUtil.decodeBitmapWithRotation(jpeg, mFacing == FACING_FRONT);
504+
ByteArrayOutputStream stream = new ByteArrayOutputStream();
505+
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
506+
jpeg = stream.toByteArray();
507+
}
508+
483509
if (mCropOutput) {
484510
int width = mMethod == METHOD_STANDARD ? mCameraImpl.getCaptureResolution().getWidth() : mCameraImpl.getPreviewResolution().getWidth();
485511
int height = mMethod == METHOD_STANDARD ? mCameraImpl.getCaptureResolution().getHeight() : mCameraImpl.getPreviewResolution().getHeight();
@@ -503,6 +529,12 @@ public void onPictureTaken(YuvImage yuv) {
503529
}
504530
}
505531

532+
@Override
533+
public void onVideoStarted() {
534+
super.onVideoStarted();
535+
getCameraListener().onVideoStarted();
536+
}
537+
506538
@Override
507539
public void onVideoTaken(File video) {
508540
super.onVideoTaken(video);
@@ -521,4 +553,4 @@ public CameraListener getCameraListener() {
521553

522554
}
523555

524-
}
556+
}

camerakit/src/main/res/values/attrs.xml

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
<enum name="strict" value="0" />
4343
<enum name="lazy" value="1" />
4444
<enum name="picture" value="2" />
45+
<enum name="off" value="3" />
4546
</attr>
4647

4748
<attr name="ckJpegQuality" format="integer" />

camerakit/src/main/types/com/flurgle/camerakit/Permissions.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
import java.lang.annotation.RetentionPolicy;
77

88
import static com.flurgle.camerakit.CameraKit.Constants.PERMISSIONS_LAZY;
9+
import static com.flurgle.camerakit.CameraKit.Constants.PERMISSIONS_OFF;
910
import static com.flurgle.camerakit.CameraKit.Constants.PERMISSIONS_PICTURE;
1011
import static com.flurgle.camerakit.CameraKit.Constants.PERMISSIONS_STRICT;
1112

1213
@Retention(RetentionPolicy.SOURCE)
13-
@IntDef({PERMISSIONS_STRICT, PERMISSIONS_LAZY, PERMISSIONS_PICTURE})
14+
@IntDef({PERMISSIONS_STRICT, PERMISSIONS_LAZY, PERMISSIONS_PICTURE, PERMISSIONS_OFF})
1415
public @interface Permissions {
1516
}

0 commit comments

Comments
 (0)