import com.android.camera.app.CameraAppUI;
import com.android.camera.app.CameraAppUI.BottomBarUISpec;
import com.android.camera.app.LocationManager;
-import com.android.camera.async.MainThreadExecutor;
+import com.android.camera.async.MainThread;
import com.android.camera.burst.BurstFacade;
import com.android.camera.burst.BurstFacadeFactory;
import com.android.camera.burst.BurstReadyStateChangeListener;
private final OneCamera.PictureSaverCallback mPictureSaverCallback =
new OneCamera.PictureSaverCallback() {
- @Override
- public void onThumbnailProcessingBegun() {
- mMainHandler.post(new Runnable() {
@Override
- public void run() {
- mAppController.getCameraAppUI().startCaptureIndicatorRevealAnimation(
- getPeekAccessibilityString());
+ public void onRemoteThumbnailAvailable(final byte[] jpegImage) {
+ mMainHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mAppController.getServices().getRemoteShutterListener().onPictureTaken(jpegImage);
+ }
+ });
}
- });
- }
- @Override
- public void onThumbnailAvailable(final Bitmap thumbnailBitmap, final int rotation) {
- mMainHandler.post(new Runnable() {
@Override
- public void run() {
- mAppController.getCameraAppUI().updateCaptureIndicatorThumbnail(
- thumbnailBitmap, rotation);
+ public void onThumbnailProcessingBegun() {
+ mMainHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mAppController.getCameraAppUI().startCaptureIndicatorRevealAnimation(
+ getPeekAccessibilityString());
+ }
+ });
}
- });
- }
- };
+
+ @Override
+ public void onThumbnailAvailable(final Bitmap thumbnailBitmap, final int rotation) {
+ mMainHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mAppController.getCameraAppUI().updateCaptureIndicatorThumbnail(
+ thumbnailBitmap, rotation);
+ }
+ });
+ }
+
+ };
/** State by the module state machine. */
private static enum ModuleState {
PhotoCaptureParameters params = new PhotoCaptureParameters(
session.getTitle(), orientation, session.getLocation(),
mContext.getExternalCacheDir(), this, mPictureSaverCallback,
- mHeadingSensor.getCurrentHeading(), getFlashModeFromSettings(), mZoomValue, 0);
+ mHeadingSensor.getCurrentHeading(), mZoomValue, 0);
mCamera.takePicture(params, session);
}
// Create the image saver.
// Used to rotate images the right way based on the sensor used
// for taking the image.
- MainThreadExecutor mainThreadExecutor = MainThreadExecutor.create();
+ MainThread mainThread = MainThread.create();
ImageRotationCalculator imageRotationCalculator = ImageRotationCalculatorImpl
.from(cameraCharacteristics);
ImageBackend imageBackend = ProcessingServiceManager.getImageBackendInstance();
ImageSaver.Builder imageSaverBuilder = new YuvImageBackendImageSaver(
- mainThreadExecutor, imageRotationCalculator, imageBackend);
+ mainThread, imageRotationCalculator, imageBackend);
// Only enable HDR on the back camera
boolean useHdr = mHdrEnabled && mCameraFacing == Facing.BACK;
// TextureView.
updateFrameDistributorBufferSize();
}
-
- /**
- * @return The currently set Flash settings. Defaults to AUTO if the setting
- * could not be parsed.
- */
- private Flash getFlashModeFromSettings() {
- String flashSetting = mSettingsManager.getString(mAppController.getCameraScope(),
- Keys.KEY_FLASH_MODE);
- try {
- return Flash.valueOf(flashSetting.toUpperCase());
- } catch (IllegalArgumentException ex) {
- Log.w(TAG, "Could not parse Flash Setting. Defaulting to AUTO.");
- return Flash.AUTO;
- }
- }
}
public OrientationManager getOrientationManager();
/**
- * Returns the {@link com.android.camera.LocationManager}.
+ * Returns the {@link LocationManager}.
*
* @return {@code null} if not available yet.
*/
public LocationManager getLocationManager();
/**
- * Returns the {@link com.android.camera.SettingsManager}.
- *
- * @return {@code null} if not available yet.
+ * Returns the {@link SettingsManager}.
*/
public SettingsManager getSettingsManager();
--- /dev/null
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera.async;
+
+import com.android.camera.util.Callback;
+
+import java.util.concurrent.Executor;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+import javax.annotation.concurrent.ThreadSafe;
+
+/**
+ * Wraps a not-necessarily-thread-safe callback into a thread-safe callback
+ * which runs it on an executor.
+ */
+@ThreadSafe
+@ParametersAreNonnullByDefault
+public class ExecutorCallback<T> implements Updatable<T> {
+ private final Callback<T> mCallback;
+ private final Executor mExecutor;
+
+ /**
+ * @param callback The callback to wrap.
+ * @param executor The executor on which to invoke the callback.
+ */
+ public ExecutorCallback(Callback<T> callback, Executor executor) {
+ mCallback = callback;
+ mExecutor = executor;
+ }
+
+ @Override
+ public void update(final T t) {
+ mExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onCallback(t);
+ }
+ });
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera.async;
+
+import com.android.camera.util.Callback;
+
+import java.util.concurrent.Executor;
+
+public class ForwardingObservable<T> implements Observable<T> {
+ private final Observable<T> mDelegate;
+
+ public ForwardingObservable(Observable<T> delegate) {
+ mDelegate = delegate;
+ }
+
+ @Override
+ public SafeCloseable addCallback(Callback<T> callback, Executor executor) {
+ return mDelegate.addCallback(callback, executor);
+ }
+
+ @Override
+ public T get() {
+ return mDelegate.get();
+ }
+}
import android.os.Handler;
+import javax.annotation.ParametersAreNonnullByDefault;
+
/**
* An {@link Executor} which posts to a {@link Handler}.
*/
+@ParametersAreNonnullByDefault
public class HandlerExecutor implements Executor {
private final Handler mHandler;
--- /dev/null
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera.async;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import javax.annotation.Nonnull;
+
+import static com.google.common.base.Preconditions.checkState;
+
+public class MainThread extends HandlerExecutor {
+ private MainThread(Handler handler) {
+ super(handler);
+ }
+
+ public static MainThread create() {
+ return new MainThread(new Handler(Looper.getMainLooper()));
+ }
+
+ /**
+ * Caches whether or not the current thread is the main thread.
+ */
+ private static final ThreadLocal<Boolean> sIsMainThread = new ThreadLocal<Boolean>() {
+ @Override
+ protected Boolean initialValue() {
+ return Looper.getMainLooper().getThread() == Thread.currentThread();
+ }
+ };
+
+ /**
+ * Asserts that the current thread is the main thread.
+ */
+ public static void checkMainThread() {
+ checkState(sIsMainThread.get(), "Not main thread.");
+ }
+
+ /**
+ * Returns a fake MainThreadExecutor which executes immediately.
+ */
+ @VisibleForTesting
+ public static MainThread createFakeForTesting() {
+ return new MainThread(null) {
+ @Override
+ public void execute(@Nonnull Runnable runnable) {
+ //
+ sIsMainThread.set(true);
+ try {
+ runnable.run();
+ } finally {
+ sIsMainThread.set(false);
+ }
+ }
+ };
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera.async;
+
+import com.android.camera.util.Callback;
+import com.google.common.base.Function;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Helper methods for {@link Observable}.
+ */
+public class Observables {
+ private Observables() {
+ }
+
+ /**
+ * Transforms an observable with a function.
+ *
+ * @return The transformed observable.
+ */
+ public static <F, T> Observable<T> transform(final Observable<F> input,
+ final Function<F, T> function) {
+ return new Observable<T>() {
+ @Override
+ public T get() {
+ return function.apply(input.get());
+ }
+
+ @Override
+ public SafeCloseable addCallback(final Callback<T> callback, Executor executor) {
+ return input.addCallback(new Callback<F>() {
+ @Override
+ public void onCallback(F result) {
+ callback.onCallback(function.apply(result));
+ }
+ }, executor);
+ }
+ };
+ }
+
+ /**
+ * @return An observable which has the given constant value.
+ */
+ public static <T> Observable<T> of(final T constant) {
+ return new Observable<T>() {
+ @Override
+ public T get() {
+ return constant;
+ }
+
+ @Override
+ public SafeCloseable addCallback(Callback<T> callback, Executor executor) {
+ return new SafeCloseable() {
+ @Override
+ public void close() {
+ }
+ };
+ }
+ };
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera.one;
+
+import com.android.camera.async.ForwardingObservable;
+import com.android.camera.async.Observable;
+import com.android.camera.async.Observables;
+import com.google.common.base.Function;
+
+/**
+ * Translates from the Flash Mode setting (stored as a string) to the
+ * appropriate {@link OneCamera.PhotoCaptureParameters.Flash} value.
+ */
+public class FlashSetting extends ForwardingObservable<OneCamera.PhotoCaptureParameters.Flash> {
+ private static class FlashStringToEnum implements
+ Function<String, OneCamera.PhotoCaptureParameters.Flash> {
+ @Override
+ public OneCamera.PhotoCaptureParameters.Flash apply(String settingString) {
+ return OneCamera.PhotoCaptureParameters.Flash.decodeSettingsString(settingString);
+ }
+ }
+
+ public FlashSetting(Observable<String> flashSettingString) {
+ super(Observables.transform(flashSettingString, new FlashStringToEnum()));
+ }
+}
import com.android.camera.burst.BurstConfiguration;
import com.android.camera.burst.ResultsAccessor;
import com.android.camera.session.CaptureSession;
+import com.android.camera.settings.SettingsManager;
import com.android.camera.util.Size;
import java.io.File;
+import javax.annotation.Nonnull;
+
/**
* OneCamera is a camera API tailored around our Google Camera application
* needs. It's not a general purpose API but instead offers an API with exactly
}
/**
- * A class implementing this interface can be passed to a picture saver
- * in order to receive image processing events.
+ * A class implementing this interface can be passed to a picture saver in
+ * order to receive image processing events.
*/
public static interface PictureSaverCallback {
/**
* Called when a thumbnail image is available.
*/
public void onThumbnailAvailable(Bitmap thumbnailBitmap, int rotation);
+
+ /**
+ * Called when compressed data for Thumbnail on a remote device (such as
+ * Android wear) is available.
+ */
+ public void onRemoteThumbnailAvailable(byte[] jpegImage);
}
/**
/**
* Flash modes.
* <p>
- * Has to be in sync with R.arrays.pref_camera_flashmode_entryvalues.
*/
public static enum Flash {
- AUTO, OFF, ON
+ AUTO("auto"), OFF("off"), ON("on");
+
+ /**
+ * The machine-readable (via {@link #encodeSettingsString} and
+ * {@link #decodeSettingsString} string used to represent this flash
+ * mode in {@link SettingsManager}.
+ * <p>
+ * This must be in sync with R.arrays.pref_camera_flashmode_entryvalues.
+ */
+ private final String mSettingsString;
+
+ Flash(@Nonnull String settingsString) {
+ mSettingsString = settingsString;
+ }
+
+ @Nonnull
+ public String encodeSettingsString() {
+ return mSettingsString;
+ }
+
+ @Nonnull
+ public static Flash decodeSettingsString(@Nonnull String setting) {
+ if (AUTO.encodeSettingsString().equals(setting)) {
+ return AUTO;
+ } else if (OFF.encodeSettingsString().equals(setting)) {
+ return OFF;
+ } else if (ON.encodeSettingsString().equals(setting)) {
+ return ON;
+ }
+ throw new IllegalArgumentException("Not a valid setting");
+ }
}
/** Called when the capture is completed or failed. */
public final PictureSaverCallback saverCallback;
/** The heading of the device at time of capture. In degrees. */
public final int heading;
- /** Flash mode for this capture. */
- public final Flash flashMode;
/** Zoom value. */
public final float zoom;
/** Timer duration in seconds or 0 for no timer. */
public PhotoCaptureParameters(String title, int orientation, Location location, File
debugDataFolder, PictureCallback callback, PictureSaverCallback saverCallback,
- int heading, Flash flashMode, float zoom, float timerSeconds) {
+ int heading, float zoom, float timerSeconds) {
super(title, orientation, location, debugDataFolder);
this.callback = callback;
this.saverCallback = saverCallback;
this.heading = heading;
- this.flashMode = flashMode;
this.zoom = zoom;
this.timerSeconds = timerSeconds;
}
/**
* Meters and triggers auto focus scan with ROI around tap point.
* <p/>
- * Normalized coordinates are referenced to portrait preview window with
- * (0, 0) top left and (1, 1) bottom right. Rotation has no effect.
+ * Normalized coordinates are referenced to portrait preview window with (0,
+ * 0) top left and (1, 1) bottom right. Rotation has no effect.
*
* @param nx normalized x coordinate.
* @param ny normalized y coordinate.
/**
* Call this to stop taking burst.
- *
*/
public void stopBurst();
/**
* Starts a preview stream and renders it to the given surface.
+ *
* @param Surface the surface on which to render preview frames
- * @param listener
+ * @param listener
*/
public void startPreview(Surface surface, CaptureReadyCallback listener);
package com.android.camera.one.v2;
-import com.android.camera.async.MainThreadExecutor;
+import com.android.camera.async.MainThread;
import com.android.camera.async.Observable;
import com.android.camera.one.OneCamera;
import com.android.camera.one.OneCameraCharacteristics;
public interface OneCameraFactory {
OneCamera createOneCamera(CameraDeviceProxy cameraDevice,
OneCameraCharacteristics characteristics,
- MainThreadExecutor mainThreadExecutor,
+ MainThread mainThread,
Size pictureSize,
ImageSaver.Builder imageSaverBuilder,
Observable<OneCamera.PhotoCaptureParameters.Flash> flashSetting);
* TODO: Determine what the maximum number of full YUV capture frames is.
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+@Deprecated
public class OneCameraZslImpl extends AbstractOneCamera {
private static final Tag TAG = new Tag("OneCameraZslImpl2");
|| aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
return false;
}
- switch (params.flashMode) {
- case OFF:
- break;
- case ON:
- if (flashState != CaptureResult.FLASH_STATE_FIRED
- || flashMode != CaptureResult.FLASH_MODE_SINGLE) {
- return false;
- }
- break;
- case AUTO:
- if (aeState == CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED
- && flashState != CaptureResult.FLASH_STATE_FIRED) {
- return false;
- }
- break;
- }
if (afState == CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN
|| afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN) {
// already, capture the next good image.
// TODO Disable the shutter button until this image is captured.
- if (params.flashMode == Flash.ON || params.flashMode == Flash.AUTO) {
+ Flash flashMode = Flash.OFF;
+
+ if (flashMode == Flash.ON || flashMode == Flash.AUTO) {
// We must issue a request for a single capture using the
// flash, including an AE precapture trigger.
}
});
- sendAutoExposureTriggerRequest(params.flashMode);
+ sendAutoExposureTriggerRequest(flashMode);
} else {
// We may get here if, for example, the auto focus is in the
// middle of a scan.
builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
- addFlashToCaptureRequestBuilder(builder, params.flashMode);
+ Flash flashMode = Flash.OFF;
+ addFlashToCaptureRequestBuilder(builder, flashMode);
addRegionsToCaptureRequestBuilder(builder);
builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
import com.android.camera.async.HandlerFactory;
import com.android.camera.async.Lifetime;
-import com.android.camera.async.MainThreadExecutor;
+import com.android.camera.async.MainThread;
import com.android.camera.async.Observable;
import com.android.camera.async.Updatable;
import com.android.camera.one.OneCamera;
@Override
public OneCamera createOneCamera(final CameraDeviceProxy device,
- final OneCameraCharacteristics characteristics, final MainThreadExecutor mainExecutor,
+ final OneCameraCharacteristics characteristics, final MainThread mainExecutor,
Size pictureSize, final ImageSaver.Builder imageSaverBuilder,
final Observable<OneCamera.PhotoCaptureParameters.Flash> flashSetting) {
import com.android.camera.async.HandlerFactory;
import com.android.camera.async.Lifetime;
-import com.android.camera.async.MainThreadExecutor;
+import com.android.camera.async.MainThread;
import com.android.camera.async.Observable;
import com.android.camera.async.Updatable;
import com.android.camera.one.OneCamera;
@Override
public OneCamera createOneCamera(final CameraDeviceProxy device,
final OneCameraCharacteristics characteristics,
- final MainThreadExecutor mainThreadExecutor,
+ final MainThread mainThread,
Size pictureSize, final ImageSaver.Builder imageSaverBuilder,
final Observable<OneCamera.PhotoCaptureParameters.Flash> flashSetting) {
miscThreadPool);
ZslPictureTakerFactory pictureTakerFactory = new ZslPictureTakerFactory(
- mainThreadExecutor,
+ mainThread,
cameraCommandExecutor,
imageSaverBuilder,
frameServer,
List<Size> supportedPreviewSizes = characteristics.getSupportedPreviewSizes();
OneCamera.Facing direction = characteristics.getCameraDirection();
return new InitializedOneCameraFactory(cameraStarter, device,
- outputSurfaces, mainThreadExecutor, new HandlerFactory(), maxZoom,
+ outputSurfaces, mainThread, new HandlerFactory(), maxZoom,
supportedPreviewSizes, direction).provideOneCamera();
}
}
import android.hardware.camera2.CameraAccessException;
import com.android.camera.async.SafeCloseable;
+import com.android.camera.debug.Log;
import com.android.camera.one.v2.camera2proxy.CameraCaptureSessionClosedException;
import com.android.camera.one.v2.core.ResourceAcquisitionFailedException;
@Override
public void run() {
try {
+ Log.d(TAG, "Executing command: " + mCommand + " START");
mCommand.run();
+ Log.d(TAG, "Executing command: " + mCommand + " END");
} catch (ResourceAcquisitionFailedException e) {
// This may indicate that the command would have otherwise
// deadlocked waiting for resources which can never be acquired,
} catch (InterruptedException e) {
// If interrupted, just return because the system is shutting
// down.
+ Log.d(TAG, "Interrupted while executing command: " + mCommand);
} catch (CameraAccessException e) {
// If the camera was closed and the command failed, just return.
+ Log.d(TAG, "Unable to connect to camera while executing command: " + mCommand);
} catch (CameraCaptureSessionClosedException e) {
// If the session was closed and the command failed, just
// return.
+ Log.d(TAG, "Unable to connect to capture session while executing command: " +
+ mCommand);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception when executing command: " + mCommand, e);
}
}
}
+ private static final Log.Tag TAG = new Log.Tag("CameraCommandExecutor");
+
private final ExecutorService mExecutor;
public CameraCommandExecutor(ExecutorService threadPoolExecutor) {
public void execute(CameraCommand command) {
try {
- mExecutor.submit(new CommandRunnable(command));
+ mExecutor.execute(new CommandRunnable(command));
} catch (RejectedExecutionException e) {
// If the executor is shut down, the command will not be executed.
// So, we can ignore this exception.
* <li>Auto exposure, based on the current flash-setting</li>
* <li>Metering regions</li>
* <li>Zoom</li>
- * <li>Logging of OS/driver-level errors</li>
+ * <li>TODO Logging of OS/driver-level errors</li>
* </ul>
* <p>
* Note that this does not include functionality for taking pictures, since this
Observable<Float> zoom, int templateType) {
RequestTemplate previewBuilder = new RequestTemplate(rootBuilder);
previewBuilder.setParam(
+ CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
+ previewBuilder.setParam(
CaptureRequest.CONTROL_AE_MODE, new FlashBasedAEMode(flash));
Supplier<Rect> cropRegion = new ZoomedCropRegion(
// changes to apply the new setting.
// Also, de-register these callbacks when the camera is closed (to
// not leak memory).
- SafeCloseable zoomCallback = zoom.addCallback(new CallbackRunnable(mPreviewStarter),
- threadPool);
+ SafeCloseable zoomCallback = zoom.addCallback(
+ new CallbackRunnable<Float>(mPreviewStarter), threadPool);
lifetime.add(zoomCallback);
- SafeCloseable flashCallback = flash.addCallback(new CallbackRunnable(mPreviewStarter),
+ SafeCloseable flashCallback = flash.addCallback(
+ new CallbackRunnable<OneCamera.PhotoCaptureParameters.Flash>(mPreviewStarter),
threadPool);
lifetime.add(flashCallback);
import android.net.Uri;
import com.android.camera.app.OrientationManager;
-import com.android.camera.async.MainThreadExecutor;
+import com.android.camera.async.MainThread;
import com.android.camera.one.OneCamera;
import com.android.camera.one.v2.camera2proxy.ImageProxy;
import com.android.camera.one.v2.photo.ImageRotationCalculator;
import com.android.camera.processing.imagebackend.ImageProcessorProxyListener;
import com.android.camera.processing.imagebackend.ImageToProcess;
import com.android.camera.processing.imagebackend.TaskImageContainer;
+import com.android.camera.remote.WearRemoteShutterListener;
import com.android.camera.session.CaptureSession;
import com.google.common.base.Optional;
public class YuvImageBackendImageSaver implements ImageSaver.Builder {
@ParametersAreNonnullByDefault
private static class ImageSaverImpl implements SingleImageSaver {
- private final MainThreadExecutor mExecutor;
+ private final MainThread mExecutor;
private final CaptureSession mSession;
private final OrientationManager.DeviceOrientation mImageRotation;
private final ImageBackend mImageBackend;
private final ImageProcessorListener mPreviewListener;
- public ImageSaverImpl(MainThreadExecutor executor,
+ public ImageSaverImpl(MainThread executor,
CaptureSession session, OrientationManager.DeviceOrientation imageRotation,
ImageBackend imageBackend, ImageProcessorListener previewListener) {
mExecutor = executor;
}
private static class PreviewListener implements ImageProcessorListener {
- private final MainThreadExecutor mExecutor;
+ private final MainThread mExecutor;
private final ImageProcessorProxyListener mListenerProxy;
private final CaptureSession mSession;
private final OrientationManager.DeviceOrientation mImageRotation;
private final OneCamera.PictureSaverCallback mPictureSaverCallback;
- private PreviewListener(MainThreadExecutor executor,
+ private PreviewListener(MainThread executor,
ImageProcessorProxyListener listenerProxy, CaptureSession session,
OrientationManager.DeviceOrientation imageRotation,
OneCamera.PictureSaverCallback pictureSaverCallback) {
@Override
public void onResultCompressed(TaskImageContainer.TaskInfo task,
TaskImageContainer.CompressedPayload payload) {
+ if(task.destination == TaskImageContainer.TaskInfo.Destination.FINAL_IMAGE) {
+ mPictureSaverCallback.onRemoteThumbnailAvailable(payload.data);
+ }
}
@Override
}
}
- private final MainThreadExecutor mExecutor;
+ private final MainThread mExecutor;
private final ImageRotationCalculator mImageRotationCalculator;
private final ImageBackend mImageBackend;
* @param executor Executor to run listener events on the ImageBackend
* @param imageRotationCalculator the image rotation calculator to determine
*/
- public YuvImageBackendImageSaver(MainThreadExecutor executor,
+ public YuvImageBackendImageSaver(MainThread executor,
ImageRotationCalculator imageRotationCalculator,
ImageBackend imageBackend) {
mExecutor = executor;
package com.android.camera.one.v2.photo;
-import com.android.camera.async.MainThreadExecutor;
+import com.android.camera.async.MainThread;
import com.android.camera.one.v2.commands.CameraCommandExecutor;
import com.android.camera.one.v2.core.FrameServer;
import com.android.camera.one.v2.core.RequestBuilder;
public class PictureTakerFactory {
private final PictureTakerImpl mPictureTaker;
- public PictureTakerFactory(MainThreadExecutor mainExecutor,
+ public PictureTakerFactory(MainThread mainExecutor,
CameraCommandExecutor commandExecutor,
ImageSaver.Builder imageSaverBuilder,
FrameServer frameServer,
ImageStreamFactory sharedImageReader) {
ImageCaptureCommand flashOffCommand = new SimpleImageCaptureCommand(frameServer,
rootRequestBuilder, sharedImageReader);
- // TODO FIXME Implement flash
- ImageCaptureCommand flashOnCommand = flashOffCommand;
- ImageCaptureCommand flashAutoCommand = flashOffCommand;
mPictureTaker = new PictureTakerImpl(mainExecutor, commandExecutor, imageSaverBuilder,
- flashOffCommand, flashOnCommand, flashAutoCommand);
+ flashOffCommand);
}
public PictureTaker providePictureTaker() {
import android.hardware.camera2.CameraAccessException;
import com.android.camera.app.OrientationManager;
-import com.android.camera.async.MainThreadExecutor;
+import com.android.camera.async.MainThread;
import com.android.camera.async.Updatable;
import com.android.camera.one.OneCamera;
import com.android.camera.one.v2.camera2proxy.CameraCaptureSessionClosedException;
import com.android.camera.session.CaptureSession;
class PictureTakerImpl implements PictureTaker {
- private final MainThreadExecutor mMainExecutor;
+ private final MainThread mMainExecutor;
private final CameraCommandExecutor mCameraCommandExecutor;
private final ImageSaver.Builder mImageSaverBuilder;
- private final ImageCaptureCommand mFlashOffCommand;
- private final ImageCaptureCommand mFlashOnCommand;
- private final ImageCaptureCommand mFlashAutoCommand;
+ private final ImageCaptureCommand mCommand;
- public PictureTakerImpl(MainThreadExecutor mainExecutor,
- CameraCommandExecutor cameraCommandExecutor,
- ImageSaver.Builder imageSaverBuilder,
- ImageCaptureCommand flashOffCommand,
- ImageCaptureCommand flashOnCommand,
- ImageCaptureCommand flashAutoCommand) {
+ public PictureTakerImpl(MainThread mainExecutor, CameraCommandExecutor cameraCommandExecutor,
+ ImageSaver.Builder imageSaverBuilder, ImageCaptureCommand command) {
mMainExecutor = mainExecutor;
mCameraCommandExecutor = cameraCommandExecutor;
mImageSaverBuilder = imageSaverBuilder;
- mFlashOffCommand = flashOffCommand;
- mFlashOnCommand = flashOnCommand;
- mFlashAutoCommand = flashAutoCommand;
+ mCommand = command;
}
@Override
public void takePicture(OneCamera.PhotoCaptureParameters params, CaptureSession session) {
- OneCamera.PhotoCaptureParameters.Flash flashMode = params.flashMode;
OneCamera.PictureCallback pictureCallback = params.callback;
// Wrap the pictureCallback with a thread-safe adapter which guarantees
OrientationManager.DeviceOrientation.from(params.orientation),
session);
- ImageCaptureCommand imageCommand;
- if (flashMode == OneCamera.PhotoCaptureParameters.Flash.ON) {
- imageCommand = mFlashOnCommand;
- } else if (flashMode == OneCamera.PhotoCaptureParameters.Flash.OFF) {
- imageCommand = mFlashOffCommand;
- } else {
- imageCommand = mFlashAutoCommand;
- }
-
- final ImageCaptureCommand finalImageCommand = imageCommand;
-
mCameraCommandExecutor.execute(new LoggingCameraCommand(new CameraCommand() {
@Override
public void run() throws InterruptedException, CameraAccessException,
CameraCaptureSessionClosedException, ResourceAcquisitionFailedException {
boolean failed = true;
try {
- finalImageCommand.run(imageExposureCallback, imageSaver);
+ mCommand.run(imageExposureCallback, imageSaver);
failed = false;
} catch (Exception e) {
failureCallback.update(null);
package com.android.camera.one.v2.photo;
import com.android.camera.async.BufferQueue;
-import com.android.camera.async.MainThreadExecutor;
+import com.android.camera.async.MainThread;
import com.android.camera.one.v2.camera2proxy.ImageProxy;
import com.android.camera.one.v2.commands.CameraCommandExecutor;
import com.android.camera.one.v2.core.FrameServer;
public class ZslPictureTakerFactory {
private final PictureTakerImpl mPictureTaker;
- public ZslPictureTakerFactory(MainThreadExecutor mainExecutor,
+ public ZslPictureTakerFactory(MainThread mainExecutor,
CameraCommandExecutor commandExecutor,
ImageSaver.Builder imageSaverBuilder,
FrameServer frameServer,
ImageStreamFactory sharedImageReader,
BufferQueue<ImageProxy> ringBuffer,
MetadataPool metadataPool) {
- ImageCaptureCommand fallbackFlashOffCommand = new SimpleImageCaptureCommand(frameServer,
+ ImageCaptureCommand fallbackCommand = new SimpleImageCaptureCommand(frameServer,
rootRequestBuilder, sharedImageReader);
- ImageCaptureCommand flashOffCommand = new ZslImageCaptureCommandFactory(ringBuffer,
- metadataPool, fallbackFlashOffCommand).provideCaptureCommand();
- // TODO FIXME Implement flash
- ImageCaptureCommand flashOnCommand = flashOffCommand;
- ImageCaptureCommand flashAutoCommand = flashOffCommand;
+ ImageCaptureCommand zslCommand = new ZslImageCaptureCommandFactory(ringBuffer,
+ metadataPool, fallbackCommand).provideCaptureCommand();
mPictureTaker = new PictureTakerImpl(mainExecutor, commandExecutor, imageSaverBuilder,
- flashOffCommand, flashOnCommand, flashAutoCommand);
+ zslCommand);
}
public PictureTaker providePictureTaker() {
+++ /dev/null
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.camera.settings;
-
-import com.android.camera.async.ConcurrentState;
-import com.android.camera.async.FilteredUpdatable;
-import com.android.camera.async.Observable;
-import com.android.camera.async.SafeCloseable;
-import com.android.camera.async.Updatable;
-import com.android.camera.util.Callback;
-
-import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import javax.annotation.Nonnull;
-
-/**
- * Wraps a {@link SettingsManager} setting with thread-safe interfaces for
- * updating the value and observing changes.
- */
-public class Setting<T> implements Updatable<T>, Observable<T>, SafeCloseable {
- /**
- * The SettingsManager instance to wrap.
- * <p>
- * Note that because many SettingsManager operations are not thread-safe at
- * all, access to it must is synchronized on the object, itself.
- */
- private final SettingsManager mSettingsManager;
- private final ConcurrentState<T> mState;
- private final Updatable<T> mFilteredState;
- private final SettingsManager.OnSettingChangedListener mOnSettingChangedListener;
- private final String mScope;
- private final String mKey;
- private final Class<T> mTClass;
- private final AtomicBoolean mClosed;
-
- private Setting(SettingsManager manager, String scope, String key, Class<T> tClass, T
- defaultValue) {
- mSettingsManager = manager;
- mScope = scope;
- mKey = key;
- mTClass = tClass;
- mState = new ConcurrentState<>(defaultValue);
- mClosed = new AtomicBoolean(false);
-
- // Wrap mState to only dispatch to listeners when the value actually
- // changes.
- mFilteredState = new FilteredUpdatable<>(mState);
-
- mOnSettingChangedListener = new SettingsManager.OnSettingChangedListener() {
- @Override
- public void onSettingChanged(SettingsManager settingsManager, String key) {
- updateFromSettings();
- }
- };
-
- synchronized (mSettingsManager) {
- mSettingsManager.addListener(mOnSettingChangedListener);
- }
- }
-
- public static Setting<Integer> createForInteger(SettingsManager manager,
- String scope, String key) {
- Integer defaultValue = manager.getIntegerDefault(key);
- return new Setting<Integer>(manager, scope, key, Integer.class, defaultValue);
- }
-
- public static Setting<String> createForString(SettingsManager manager,
- String scope, String key) {
- String defaultValue = manager.getStringDefault(key);
- return new Setting<String>(manager, scope, key, String.class, defaultValue);
- }
-
- public static Setting<Boolean> createForBoolean(SettingsManager manager,
- String scope, String key) {
- Boolean defaultValue = manager.getBooleanDefault(key);
- return new Setting<Boolean>(manager, scope, key, Boolean.class, defaultValue);
- }
-
- @Override
- public SafeCloseable addCallback(Callback callback, Executor executor) {
- return mState.addCallback(callback, executor);
- }
-
- private void updateFromSettings() {
- mFilteredState.update(getFromSettings());
- }
-
- private T getFromSettings() {
- synchronized (mSettingsManager) {
- if (mTClass.equals(Integer.class)) {
- return (T) mSettingsManager.getInteger(mScope, mKey);
- } else if (mTClass.equals(String.class)) {
- return (T) mSettingsManager.getString(mScope, mKey);
- } else if (mTClass.equals(Boolean.class)) {
- return (T) new Boolean(mSettingsManager.getBoolean(mScope, mKey));
- }
- }
- return null;
- }
-
- @Override
- public T get() {
- return getFromSettings();
- }
-
- @Override
- public void update(@Nonnull T t) {
- synchronized (mSettingsManager) {
- if (mTClass.equals(Integer.class)) {
- mSettingsManager.set(mScope, mKey, (Integer) t);
- } else if (mTClass.equals(String.class)) {
- mSettingsManager.set(mScope, mKey, (String) t);
- } else if (mTClass.equals(Boolean.class)) {
- mSettingsManager.set(mScope, mKey, (Boolean) t);
- }
- }
- }
-
- @Override
- public void close() {
- if (mClosed.getAndSet(true)) {
- return;
- }
- synchronized (mSettingsManager) {
- mSettingsManager.removeListener(mOnSettingChangedListener);
- }
- }
-}
--- /dev/null
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera.settings;
+
+import com.android.camera.async.FilteredUpdatable;
+import com.android.camera.async.Observable;
+import com.android.camera.async.ExecutorCallback;
+import com.android.camera.async.SafeCloseable;
+import com.android.camera.async.Updatable;
+import com.android.camera.util.Callback;
+
+import java.util.concurrent.Executor;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
+
+/**
+ * Wraps a {@link SettingsManager} setting with thread-safe interfaces for
+ * observing changes.
+ */
+@ThreadSafe
+public final class SettingObserver<T> implements Observable<T> {
+ private class Listener implements SettingsManager.OnSettingChangedListener, SafeCloseable {
+ private final Updatable<T> mCallback;
+
+ private Listener(Updatable<T> callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void onSettingChanged(SettingsManager settingsManager, String key) {
+ T t = get();
+ if (t != null) {
+ mCallback.update(t);
+ }
+ }
+
+ @Override
+ public void close() {
+ mSettingsManager.removeListener(this);
+ }
+ }
+
+ private final SettingsManager mSettingsManager;
+ private final String mScope;
+ private final String mKey;
+ private final Class<T> mTClass;
+
+ private SettingObserver(SettingsManager manager, String scope, String key, Class<T> tClass) {
+ mSettingsManager = manager;
+ mScope = scope;
+ mKey = key;
+ mTClass = tClass;
+ }
+
+ public static SettingObserver<Integer> ofInteger(SettingsManager manager,
+ String scope, String key) {
+ return new SettingObserver<>(manager, scope, key,
+ Integer.class);
+ }
+
+ public static SettingObserver<String> ofString(SettingsManager manager,
+ String scope, String key) {
+ return new SettingObserver<>(manager, scope, key,
+ String.class);
+ }
+
+ public static SettingObserver<Boolean> ofBoolean(SettingsManager manager,
+ String scope, String key) {
+ return new SettingObserver<>(manager, scope, key,
+ Boolean.class);
+ }
+
+ @Override
+ public SafeCloseable addCallback(Callback<T> callback, Executor executor) {
+ final Listener listener =
+ new Listener(new FilteredUpdatable<>(new ExecutorCallback<>(callback, executor)));
+ mSettingsManager.addListener(listener);
+ return listener;
+ }
+
+ @Nullable
+ @Override
+ @SuppressWarnings("unchecked")
+ public T get() {
+ if (mTClass.equals(Integer.class)) {
+ return (T) Integer.valueOf(mSettingsManager.getInteger(mScope, mKey));
+ } else if (mTClass.equals(String.class)) {
+ Object string = mSettingsManager.getString(mScope, mKey);
+ if (string == null) {
+ return null;
+ } else {
+ return (T) string;
+ }
+ } else if (mTClass.equals(Boolean.class)) {
+ return (T) Boolean.valueOf(mSettingsManager.getBoolean(mScope, mKey));
+ } else {
+ // Impossible branch
+ throw new IllegalStateException("T must be one of {Integer, Boolean, String}");
+ }
+ }
+}
import java.util.ArrayList;
import java.util.List;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
+
+
/**
* SettingsManager class provides an api for getting and setting SharedPreferences
* values.
* methods, which rely on an index into the set of possible values.
*
*/
+@ThreadSafe
public class SettingsManager {
private static final Log.Tag TAG = new Log.Tag("SettingsManager");
* Retrieve a setting's value as a String, using the default value
* stored in the DefaultsStore.
*/
+ @Nullable
public String getString(String scope, String key) {
synchronized (mLock) {
return getString(scope, key, getStringDefault(key));
* Retrieve a setting's value as an Integer, manually specifying
* a default value.
*/
- public Integer getInteger(String scope, String key, Integer defaultValue) {
+ public int getInteger(String scope, String key, Integer defaultValue) {
synchronized (mLock) {
String defaultValueString = Integer.toString(defaultValue);
String value = getString(scope, key, defaultValueString);
* Retrieve a setting's value as an Integer, converting the default value
* stored in the DefaultsStore.
*/
- public Integer getInteger(String scope, String key) {
+ public int getInteger(String scope, String key) {
synchronized (mLock) {
return getInteger(scope, key, getIntegerDefault(key));
}