summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/callcomposer/camera
diff options
context:
space:
mode:
authorEric Erfanian <erfanian@google.com>2017-08-31 06:57:16 -0700
committerEric Erfanian <erfanian@google.com>2017-08-31 16:13:53 +0000
commit2ca4318cc1ee57dda907ba2069bd61d162b1baef (patch)
treee282668a9587cf6c1ec7b604dea860400c75c6c7 /java/com/android/dialer/callcomposer/camera
parent68038172793ee0e2ab3e2e56ddfbeb82879d1f58 (diff)
Update Dialer source to latest internal Google revision.
Previously, Android's Dialer app was developed in an internal Google source control system and only exported to public during AOSP drops. The Dialer team is now switching to a public development model similar to the telephony team. This CL represents all internal Google changes that were committed to Dialer between the public O release and today's tip of tree on internal master. This CL squashes those changes into a single commit. In subsequent changes, changes will be exported on a per-commit basis. Test: make, flash install, run Merged-In: I45270eaa8ce732d71a1bd84b08c7fa0e99af3160 Change-Id: I529aaeb88535b9533c0ae4ef4e6c1222d4e0f1c8 PiperOrigin-RevId: 167068436
Diffstat (limited to 'java/com/android/dialer/callcomposer/camera')
-rw-r--r--java/com/android/dialer/callcomposer/camera/CameraManager.java146
-rw-r--r--java/com/android/dialer/callcomposer/camera/ImagePersistWorker.java (renamed from java/com/android/dialer/callcomposer/camera/ImagePersistTask.java)98
-rw-r--r--java/com/android/dialer/callcomposer/camera/camerafocus/FocusOverlayManager.java2
-rw-r--r--java/com/android/dialer/callcomposer/camera/exif/ExifInterface.java2
-rw-r--r--java/com/android/dialer/callcomposer/camera/exif/ExifParser.java2
-rw-r--r--java/com/android/dialer/callcomposer/camera/exif/ExifTag.java2
6 files changed, 146 insertions, 106 deletions
diff --git a/java/com/android/dialer/callcomposer/camera/CameraManager.java b/java/com/android/dialer/callcomposer/camera/CameraManager.java
index 4cc08ba32..f79f6548c 100644
--- a/java/com/android/dialer/callcomposer/camera/CameraManager.java
+++ b/java/com/android/dialer/callcomposer/camera/CameraManager.java
@@ -35,6 +35,7 @@ import com.android.dialer.callcomposer.camera.camerafocus.FocusOverlayManager;
import com.android.dialer.callcomposer.camera.camerafocus.RenderOverlay;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.common.concurrent.DialerExecutors;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@@ -118,7 +119,7 @@ public class CameraManager implements FocusOverlayManager.Listener {
/**
* The task for opening the camera, so it doesn't block the UI thread Using AsyncTask rather than
* SafeAsyncTask because the tasks need to be serialized, but don't need to be on the UI thread
- * TODO: If we have other AyncTasks (not SafeAsyncTasks) this may contend and we may need
+ * TODO(blemmon): If we have other AyncTasks (not SafeAsyncTasks) this may contend and we may need
* to create a dedicated thread, or synchronize the threads in the thread pool
*/
private AsyncTask<Integer, Void, Camera> mOpenCameraTask;
@@ -457,9 +458,9 @@ public class CameraManager implements FocusOverlayManager.Listener {
int height;
if (mRotation == 90 || mRotation == 270) {
// Is rotated, so swapping dimensions is desired
- //noinspection SuspiciousNameCombination
+ // noinspection SuspiciousNameCombination
width = size.height;
- //noinspection SuspiciousNameCombination
+ // noinspection SuspiciousNameCombination
height = size.width;
} else {
width = size.width;
@@ -467,9 +468,20 @@ public class CameraManager implements FocusOverlayManager.Listener {
}
LogUtil.i(
"CameraManager.onPictureTaken", "taken picture size: " + bytes.length + " bytes");
- new ImagePersistTask(
- width, height, heightPercent, bytes, mCameraPreview.getContext(), callback)
- .execute();
+ DialerExecutors.createNonUiTaskBuilder(
+ new ImagePersistWorker(
+ width, height, heightPercent, bytes, mCameraPreview.getContext()))
+ .onSuccess(
+ (result) -> {
+ callback.onMediaReady(
+ result.getUri(), "image/jpeg", result.getWidth(), result.getHeight());
+ })
+ .onFailure(
+ (throwable) -> {
+ callback.onMediaFailed(new Exception("Persisting image failed", throwable));
+ })
+ .build()
+ .executeSerial(null);
}
};
@@ -509,62 +521,61 @@ public class CameraManager implements FocusOverlayManager.Listener {
}.execute();
}
- /** Updates the orientation of the camera to match the orientation of the device */
- private void updateCameraOrientation() {
- if (mCamera == null || mCameraPreview == null || mTakingPicture) {
- return;
+ /**
+ * Updates the orientation of the {@link Camera} w.r.t. the orientation of the device and the
+ * orientation that the physical camera is mounted on the device.
+ *
+ * @param camera that needs to be reorientated
+ * @param screenRotation rotation of the physical device
+ * @param cameraOrientation {@link CameraInfo#orientation}
+ * @param cameraIsFrontFacing {@link CameraInfo#CAMERA_FACING_FRONT}
+ * @return rotation that images returned from {@link
+ * android.hardware.Camera.PictureCallback#onPictureTaken(byte[], Camera)} will be rotated.
+ */
+ @VisibleForTesting
+ static int updateCameraRotation(
+ @NonNull Camera camera,
+ int screenRotation,
+ int cameraOrientation,
+ boolean cameraIsFrontFacing) {
+ Assert.isNotNull(camera);
+ Assert.checkArgument(cameraOrientation % 90 == 0);
+
+ int rotation = screenRotationToDegress(screenRotation);
+ boolean portrait = rotation == 0 || rotation == 180;
+
+ if (!portrait && !cameraIsFrontFacing) {
+ rotation += 180;
}
+ rotation += cameraOrientation;
+ rotation %= 360;
- final WindowManager windowManager =
- (WindowManager) mCameraPreview.getContext().getSystemService(Context.WINDOW_SERVICE);
+ // Rotate the camera
+ if (portrait && cameraIsFrontFacing) {
+ camera.setDisplayOrientation((rotation + 180) % 360);
+ } else {
+ camera.setDisplayOrientation(rotation);
+ }
+
+ // Rotate the images returned when a picture is taken
+ Camera.Parameters params = camera.getParameters();
+ params.setRotation(rotation);
+ camera.setParameters(params);
+ return rotation;
+ }
- int degrees;
- switch (windowManager.getDefaultDisplay().getRotation()) {
+ private static int screenRotationToDegress(int screenRotation) {
+ switch (screenRotation) {
case Surface.ROTATION_0:
- degrees = 0;
- break;
+ return 0;
case Surface.ROTATION_90:
- degrees = 90;
- break;
+ return 90;
case Surface.ROTATION_180:
- degrees = 180;
- break;
+ return 180;
case Surface.ROTATION_270:
- degrees = 270;
- break;
+ return 270;
default:
- throw Assert.createAssertionFailException("");
- }
-
- // The display orientation of the camera (this controls the preview image).
- int orientation;
-
- // The clockwise rotation angle relative to the orientation of the camera. This affects
- // pictures returned by the camera in Camera.PictureCallback.
- int rotation;
- if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
- orientation = (mCameraInfo.orientation + degrees) % 360;
- rotation = orientation;
- // compensate the mirror but only for orientation
- orientation = (360 - orientation) % 360;
- } else { // back-facing
- orientation = (mCameraInfo.orientation - degrees + 360) % 360;
- rotation = orientation;
- }
- mRotation = rotation;
- try {
- mCamera.setDisplayOrientation(orientation);
- final Camera.Parameters params = mCamera.getParameters();
- params.setRotation(rotation);
- mCamera.setParameters(params);
- } catch (final RuntimeException e) {
- LogUtil.e(
- "CameraManager.updateCameraOrientation",
- "RuntimeException in CameraManager.updateCameraOrientation",
- e);
- if (mListener != null) {
- mListener.onCameraError(ERROR_OPENING_CAMERA, e);
- }
+ throw Assert.createIllegalStateFailException("Invalid surface rotation.");
}
}
@@ -589,13 +600,19 @@ public class CameraManager implements FocusOverlayManager.Listener {
mOrientationHandler.disable();
mOrientationHandler = null;
}
- // releaseMediaRecorder(true /* cleanupFile */);
mFocusOverlayManager.onPreviewStopped();
return;
}
try {
mCamera.stopPreview();
- updateCameraOrientation();
+ if (!mTakingPicture) {
+ mRotation =
+ updateCameraRotation(
+ mCamera,
+ getScreenRotation(),
+ mCameraInfo.orientation,
+ mCameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT);
+ }
final Camera.Parameters params = mCamera.getParameters();
final Camera.Size pictureSize = chooseBestPictureSize();
@@ -644,6 +661,14 @@ public class CameraManager implements FocusOverlayManager.Listener {
}
}
+ private int getScreenRotation() {
+ return mCameraPreview
+ .getContext()
+ .getSystemService(WindowManager.class)
+ .getDefaultDisplay()
+ .getRotation();
+ }
+
public boolean isCameraAvailable() {
return mCamera != null && !mTakingPicture && mIsHardwareAccelerationSupported;
}
@@ -681,7 +706,14 @@ public class CameraManager implements FocusOverlayManager.Listener {
@Override
public void onOrientationChanged(final int orientation) {
- updateCameraOrientation();
+ if (!mTakingPicture) {
+ mRotation =
+ updateCameraRotation(
+ mCamera,
+ getScreenRotation(),
+ mCameraInfo.orientation,
+ mCameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT);
+ }
}
}
diff --git a/java/com/android/dialer/callcomposer/camera/ImagePersistTask.java b/java/com/android/dialer/callcomposer/camera/ImagePersistWorker.java
index 31751e536..26b0bde00 100644
--- a/java/com/android/dialer/callcomposer/camera/ImagePersistTask.java
+++ b/java/com/android/dialer/callcomposer/camera/ImagePersistWorker.java
@@ -20,18 +20,18 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
import android.net.Uri;
import android.os.Build.VERSION_CODES;
+import android.support.annotation.NonNull;
import android.support.v4.content.FileProvider;
+import com.android.dialer.callcomposer.camera.ImagePersistWorker.Result;
import com.android.dialer.callcomposer.camera.exif.ExifInterface;
-import com.android.dialer.callcomposer.camera.exif.ExifTag;
import com.android.dialer.callcomposer.util.BitmapResizer;
import com.android.dialer.common.Assert;
-import com.android.dialer.common.concurrent.FallibleAsyncTask;
+import com.android.dialer.common.concurrent.DialerExecutor.Worker;
import com.android.dialer.constants.Constants;
import com.android.dialer.util.DialerUtils;
+import com.google.auto.value.AutoValue;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -39,58 +39,70 @@ import java.io.OutputStream;
/** Persisting image routine. */
@TargetApi(VERSION_CODES.M)
-public class ImagePersistTask extends FallibleAsyncTask<Void, Void, Uri> {
+public class ImagePersistWorker implements Worker<Void, Result> {
private int mWidth;
private int mHeight;
private final float mHeightPercent;
private final byte[] mBytes;
private final Context mContext;
- private final CameraManager.MediaCallback mCallback;
- ImagePersistTask(
+ @AutoValue
+ abstract static class Result {
+
+ public static Builder builder() {
+ return new AutoValue_ImagePersistWorker_Result.Builder();
+ }
+
+ @NonNull
+ abstract Uri getUri();
+
+ abstract int getWidth();
+
+ abstract int getHeight();
+
+ @AutoValue.Builder
+ abstract static class Builder {
+ abstract Builder setUri(@NonNull Uri uri);
+
+ abstract Builder setWidth(int width);
+
+ abstract Builder setHeight(int height);
+
+ abstract Result build();
+ }
+ }
+
+ ImagePersistWorker(
final int width,
final int height,
final float heightPercent,
final byte[] bytes,
- final Context context,
- final CameraManager.MediaCallback callback) {
+ final Context context) {
Assert.checkArgument(heightPercent >= 0 && heightPercent <= 1);
Assert.isNotNull(bytes);
Assert.isNotNull(context);
- Assert.isNotNull(callback);
mWidth = width;
mHeight = height;
mHeightPercent = heightPercent;
mBytes = bytes;
mContext = context;
- mCallback = callback;
}
@Override
- protected Uri doInBackgroundFallible(final Void... params) throws Exception {
+ public Result doInBackground(Void unused) throws Exception {
File outputFile = DialerUtils.createShareableFile(mContext);
try (OutputStream outputStream = new FileOutputStream(outputFile)) {
- if (mHeightPercent != 1.0f) {
- writeClippedBitmap(outputStream);
- } else {
- Bitmap bitmap = BitmapFactory.decodeByteArray(mBytes, 0, mBytes.length);
- bitmap = BitmapResizer.resizeForEnrichedCalling(bitmap);
- bitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream);
- }
+ writeClippedBitmap(outputStream);
}
- return FileProvider.getUriForFile(
- mContext, Constants.get().getFileProviderAuthority(), outputFile);
- }
-
- @Override
- protected void onPostExecute(FallibleTaskResult<Uri> result) {
- if (result.isFailure()) {
- mCallback.onMediaFailed(new Exception("Persisting image failed", result.getThrowable()));
- } else {
- mCallback.onMediaReady(result.getResult(), "image/jpeg", mWidth, mHeight);
- }
+ return Result.builder()
+ .setUri(
+ FileProvider.getUriForFile(
+ mContext, Constants.get().getFileProviderAuthority(), outputFile))
+ .setWidth(mWidth)
+ .setHeight(mHeight)
+ .build();
}
private void writeClippedBitmap(OutputStream outputStream) throws IOException {
@@ -105,10 +117,12 @@ public class ImagePersistTask extends FallibleAsyncTask<Void, Void, Uri> {
} catch (final IOException e) {
// Couldn't get exif tags, not the end of the world
}
+
+ ExifInterface.OrientationParams params = ExifInterface.getOrientationParams(orientation);
Bitmap bitmap = BitmapFactory.decodeByteArray(mBytes, 0, mBytes.length);
final int clippedWidth;
final int clippedHeight;
- if (ExifInterface.getOrientationParams(orientation).invertDimensions) {
+ if (params.invertDimensions) {
Assert.checkState(mWidth == bitmap.getHeight());
Assert.checkState(mHeight == bitmap.getWidth());
clippedWidth = (int) (mHeight * mHeightPercent);
@@ -119,24 +133,18 @@ public class ImagePersistTask extends FallibleAsyncTask<Void, Void, Uri> {
clippedWidth = mWidth;
clippedHeight = (int) (mHeight * mHeightPercent);
}
- final int offsetTop = (bitmap.getHeight() - clippedHeight) / 2;
- final int offsetLeft = (bitmap.getWidth() - clippedWidth) / 2;
+
+ int offsetTop = (bitmap.getHeight() - clippedHeight) / 2;
+ int offsetLeft = (bitmap.getWidth() - clippedWidth) / 2;
mWidth = clippedWidth;
mHeight = clippedHeight;
+
Bitmap clippedBitmap =
- Bitmap.createBitmap(clippedWidth, clippedHeight, Bitmap.Config.ARGB_8888);
- clippedBitmap.setDensity(bitmap.getDensity());
- final Canvas clippedBitmapCanvas = new Canvas(clippedBitmap);
- final Matrix matrix = new Matrix();
- matrix.postTranslate(-offsetLeft, -offsetTop);
- clippedBitmapCanvas.drawBitmap(bitmap, matrix, null /* paint */);
- clippedBitmapCanvas.save();
- clippedBitmap = BitmapResizer.resizeForEnrichedCalling(clippedBitmap);
- // EXIF data can take a big chunk of the file size and is often cleared by the
- // carrier, only store orientation since that's critical
- final ExifTag orientationTag = exifInterface.getTag(ExifInterface.TAG_ORIENTATION);
+ Bitmap.createBitmap(bitmap, offsetLeft, offsetTop, clippedWidth, clippedHeight);
+ clippedBitmap = BitmapResizer.resizeForEnrichedCalling(clippedBitmap, params.rotation);
+ // EXIF data can take a big chunk of the file size and we've already manually rotated our image,
+ // so remove all of the exif data.
exifInterface.clearExif();
- exifInterface.setTag(orientationTag);
exifInterface.writeExif(clippedBitmap, outputStream);
clippedBitmap.recycle();
diff --git a/java/com/android/dialer/callcomposer/camera/camerafocus/FocusOverlayManager.java b/java/com/android/dialer/callcomposer/camera/camerafocus/FocusOverlayManager.java
index 1c5ac380c..a5edf3309 100644
--- a/java/com/android/dialer/callcomposer/camera/camerafocus/FocusOverlayManager.java
+++ b/java/com/android/dialer/callcomposer/camera/camerafocus/FocusOverlayManager.java
@@ -389,7 +389,7 @@ public class FocusOverlayManager {
focusIndicator.showStart();
} else {
if (Parameters.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusMode)) {
- // TODO: check HAL behavior and decide if this can be removed.
+ // TODO(blemmon): check HAL behavior and decide if this can be removed.
focusIndicator.showSuccess(false);
} else if (mState == STATE_SUCCESS) {
focusIndicator.showSuccess(false);
diff --git a/java/com/android/dialer/callcomposer/camera/exif/ExifInterface.java b/java/com/android/dialer/callcomposer/camera/exif/ExifInterface.java
index 92dee1c94..1bf9519ad 100644
--- a/java/com/android/dialer/callcomposer/camera/exif/ExifInterface.java
+++ b/java/com/android/dialer/callcomposer/camera/exif/ExifInterface.java
@@ -286,7 +286,7 @@ public class ExifInterface {
/** Wrapper class to define some orientation parameters. */
public static class OrientationParams {
- int rotation = 0;
+ public int rotation = 0;
int scaleX = 1;
int scaleY = 1;
public boolean invertDimensions = false;
diff --git a/java/com/android/dialer/callcomposer/camera/exif/ExifParser.java b/java/com/android/dialer/callcomposer/camera/exif/ExifParser.java
index 23d748c17..c728845a1 100644
--- a/java/com/android/dialer/callcomposer/camera/exif/ExifParser.java
+++ b/java/com/android/dialer/callcomposer/camera/exif/ExifParser.java
@@ -499,7 +499,7 @@ public class ExifParser {
mTiffStream.skip(4);
return null;
}
- // TODO: handle numOfComp overflow
+ // TODO(blemmon): handle numOfComp overflow
ExifTag tag =
new ExifTag(
tagId,
diff --git a/java/com/android/dialer/callcomposer/camera/exif/ExifTag.java b/java/com/android/dialer/callcomposer/camera/exif/ExifTag.java
index a254ae93b..9a03c103c 100644
--- a/java/com/android/dialer/callcomposer/camera/exif/ExifTag.java
+++ b/java/com/android/dialer/callcomposer/camera/exif/ExifTag.java
@@ -187,7 +187,7 @@ public class ExifTag {
/** Gets the component count of this tag. */
- // TODO: fix integer overflows with this
+ // TODO(blemmon): fix integer overflows with this
int getComponentCount() {
return mComponentCountActual;
}