/* * 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.captureintent; import android.content.Intent; import android.graphics.Point; import android.graphics.SurfaceTexture; import android.view.GestureDetector; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import com.android.camera.CameraActivity; import com.android.camera.CameraModule; import com.android.camera.app.AppController; import com.android.camera.app.CameraAppUI; import com.android.camera.async.MainThread; import com.android.camera.async.RefCountBase; import com.android.camera.burst.BurstFacadeFactory; import com.android.camera.captureintent.event.EventClickOnCameraKey; import com.android.camera.captureintent.event.EventOnSurfaceTextureAvailable; import com.android.camera.captureintent.event.EventOnSurfaceTextureDestroyed; import com.android.camera.captureintent.event.EventOnSurfaceTextureUpdated; import com.android.camera.captureintent.event.EventOnTextureViewLayoutChanged; import com.android.camera.captureintent.event.EventPause; import com.android.camera.captureintent.event.EventResume; import com.android.camera.captureintent.event.EventTapOnCancelShutterButton; import com.android.camera.captureintent.event.EventTapOnPreview; import com.android.camera.captureintent.event.EventTapOnShutterButton; import com.android.camera.captureintent.event.EventZoomRatioChanged; import com.android.camera.captureintent.resource.ResourceConstructed; import com.android.camera.captureintent.resource.ResourceConstructedImpl; import com.android.camera.captureintent.state.StateBackground; import com.android.camera.captureintent.stateful.State; import com.android.camera.captureintent.stateful.StateMachine; import com.android.camera.captureintent.stateful.StateMachineImpl; import com.android.camera.debug.Log; import com.android.camera.hardware.HardwareSpec; import com.android.camera.one.OneCameraException; import com.android.camera.one.OneCameraModule; import com.android.camera.settings.SettingsManager; import com.android.camera.ui.PreviewStatusListener; import com.android.camera.ui.TouchCoordinate; import com.android.camera.util.Size; import com.android.camera2.R; import com.android.ex.camera2.portability.CameraAgent; /** * The camera module that handles image capture intent. */ public class CaptureIntentModule extends CameraModule { private static final Log.Tag TAG = new Log.Tag("CapIntModule"); /** The module UI. */ private final CaptureIntentModuleUI mModuleUI; /** The available resources after construction. */ private final RefCountBase mResourceConstructed; /** The module state machine. */ private final StateMachine mStateMachine; private TouchCoordinate mTouchPointInsideShutterButton; public CaptureIntentModule(AppController appController, Intent intent, String settingScopeNamespace) throws OneCameraException { super(appController); mModuleUI = new CaptureIntentModuleUI( appController.getCameraAppUI(), appController.getModuleLayoutRoot(), mUIListener); mStateMachine = new StateMachineImpl(); mResourceConstructed = ResourceConstructedImpl.create( intent, mModuleUI, settingScopeNamespace, MainThread.create(), appController.getAndroidContext(), appController.getCameraOpener(), OneCameraModule.provideOneCameraManager(), appController.getLocationManager(), appController.getOrientationManager(), appController.getSettingsManager(), new BurstFacadeFactory.BurstFacadeStub(), appController, appController.getFatalErrorHandler()); final State initialState = StateBackground.create(mStateMachine, mResourceConstructed); // Set the initial state. mStateMachine.setInitialState(initialState); } @Override public void onCameraAvailable(CameraAgent.CameraProxy cameraProxy) { // Do nothing for capture intent. } @Override public void onShutterButtonFocus(boolean pressed) { // Do nothing for capture intent. } @Override public void onShutterCoordinate(TouchCoordinate touchCoordinate) { mTouchPointInsideShutterButton = touchCoordinate; } @Override public void onShutterButtonClick() { mStateMachine.processEvent(new EventTapOnShutterButton(mTouchPointInsideShutterButton)); } @Override public void onShutterButtonLongPressed() { // Do nothing for capture intent. } @Override public void init( final CameraActivity activity, boolean isSecureCamera, boolean isCaptureIntent) { mResourceConstructed.get().getAppController() .setPreviewStatusListener(mPreviewStatusListener); // Issue cancel countdown event when the button is pressed. // TODO: Make this part of the official API the way shutter button events are. mResourceConstructed.get().getAppController().getCameraAppUI() .setCancelShutterButtonListener(new View.OnClickListener() { @Override public void onClick(View v) { mStateMachine.processEvent(new EventTapOnCancelShutterButton()); } }); } @Override public void resume() { mModuleUI.onModuleResumed(); mStateMachine.processEvent(new EventResume()); } @Override public void pause() { mModuleUI.setCountdownFinishedListener(null); mModuleUI.onModulePaused(); mStateMachine.processEvent(new EventPause()); } @Override public void destroy() { // Never called. Do nothing here. } @Override public void onPreviewVisibilityChanged(int visibility) { // Do nothing. } @Override public void onLayoutOrientationChanged(boolean isLandscape) { // Do nothing. } @Override public void hardResetSettings(SettingsManager settingsManager) { // Do nothing. } @Override public HardwareSpec getHardwareSpec() { /** * Instead of passively providing CameraAppUI the hardware spec here, * {@link com.android.camera.captureintent.state.StateOpeningCamera} * will actively specify hardware spec. */ return null; } @Override public CameraAppUI.BottomBarUISpec getBottomBarSpec() { /** * Instead of passively providing CameraAppUI the bottom bar spec here, * {@link com.android.camera.captureintent.state.StateOpeningCamera} * will actively specify bottom bar spec. */ return null; } @Override public boolean isUsingBottomBar() { return true; } @Override public String getPeekAccessibilityString() { return mResourceConstructed.get().getContext().getResources() .getString(R.string.photo_accessibility_peek); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_CAMERA: case KeyEvent.KEYCODE_DPAD_CENTER: mStateMachine.processEvent(new EventClickOnCameraKey()); return true; case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: // Prevent default. return true; } return false; } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: mStateMachine.processEvent(new EventClickOnCameraKey()); return true; } return false; } /** The listener to listen events from the UI. */ private final CaptureIntentModuleUI.Listener mUIListener = new CaptureIntentModuleUI.Listener() { @Override public void onZoomRatioChanged(final float zoomRatio) { mStateMachine.processEvent(new EventZoomRatioChanged(zoomRatio)); } }; /** The listener to listen events from the preview. */ private final PreviewStatusListener mPreviewStatusListener = new PreviewStatusListener() { @Override public void onPreviewLayoutChanged(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { final Size previewLayoutSize = new Size(right - left, bottom - top); mStateMachine.processEvent(new EventOnTextureViewLayoutChanged(previewLayoutSize)); } @Override public boolean shouldAutoAdjustTransformMatrixOnLayout() { return CaptureIntentConfig.WORKAROUND_PREVIEW_STRETCH_BUG_NEXUS4; } @Override public void onPreviewFlipped() { // Do nothing because when preview is flipped, TextureView will lay // itself out again, which will then trigger a transform matrix // update. } @Override public GestureDetector.OnGestureListener getGestureListener() { return new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapUp(MotionEvent ev) { final Point tapPoint = new Point((int) ev.getX(), (int) ev.getY()); mStateMachine.processEvent(new EventTapOnPreview(tapPoint)); return true; } }; } @Override public View.OnTouchListener getTouchListener() { return null; } @Override public void onSurfaceTextureAvailable( final SurfaceTexture surfaceTexture, int width, int height) { mStateMachine.processEvent(new EventOnSurfaceTextureAvailable(surfaceTexture)); } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { mStateMachine.processEvent(new EventOnSurfaceTextureDestroyed()); return true; } @Override public void onSurfaceTextureSizeChanged( SurfaceTexture surfaceTexture, int width, int height) { } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { mStateMachine.processEvent(new EventOnSurfaceTextureUpdated()); } }; }