1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.camera.captureintent; 18 19 import android.content.Intent; 20 import android.graphics.Point; 21 import android.graphics.SurfaceTexture; 22 import android.view.GestureDetector; 23 import android.view.KeyEvent; 24 import android.view.MotionEvent; 25 import android.view.View; 26 27 import com.android.camera.CameraActivity; 28 import com.android.camera.CameraModule; 29 import com.android.camera.app.AppController; 30 import com.android.camera.app.CameraAppUI; 31 import com.android.camera.async.MainThread; 32 import com.android.camera.async.RefCountBase; 33 import com.android.camera.burst.BurstFacadeFactory; 34 import com.android.camera.captureintent.event.EventClickOnCameraKey; 35 import com.android.camera.captureintent.event.EventOnSurfaceTextureAvailable; 36 import com.android.camera.captureintent.event.EventOnSurfaceTextureDestroyed; 37 import com.android.camera.captureintent.event.EventOnSurfaceTextureUpdated; 38 import com.android.camera.captureintent.event.EventOnTextureViewLayoutChanged; 39 import com.android.camera.captureintent.event.EventPause; 40 import com.android.camera.captureintent.event.EventResume; 41 import com.android.camera.captureintent.event.EventTapOnCancelShutterButton; 42 import com.android.camera.captureintent.event.EventTapOnPreview; 43 import com.android.camera.captureintent.event.EventTapOnShutterButton; 44 import com.android.camera.captureintent.event.EventZoomRatioChanged; 45 import com.android.camera.captureintent.resource.ResourceConstructed; 46 import com.android.camera.captureintent.resource.ResourceConstructedImpl; 47 import com.android.camera.captureintent.state.StateBackground; 48 import com.android.camera.captureintent.stateful.State; 49 import com.android.camera.captureintent.stateful.StateMachine; 50 import com.android.camera.captureintent.stateful.StateMachineImpl; 51 import com.android.camera.debug.Log; 52 import com.android.camera.hardware.HardwareSpec; 53 import com.android.camera.one.OneCameraException; 54 import com.android.camera.one.OneCameraModule; 55 import com.android.camera.settings.SettingsManager; 56 import com.android.camera.ui.PreviewStatusListener; 57 import com.android.camera.ui.TouchCoordinate; 58 import com.android.camera.util.Size; 59 import com.android.camera2.R; 60 import com.android.ex.camera2.portability.CameraAgent; 61 62 /** 63 * The camera module that handles image capture intent. 64 */ 65 public class CaptureIntentModule extends CameraModule { 66 private static final Log.Tag TAG = new Log.Tag("CapIntModule"); 67 68 /** The module UI. */ 69 private final CaptureIntentModuleUI mModuleUI; 70 71 /** The available resources after construction. */ 72 private final RefCountBase<ResourceConstructed> mResourceConstructed; 73 74 /** The module state machine. */ 75 private final StateMachine mStateMachine; 76 77 private TouchCoordinate mTouchPointInsideShutterButton; 78 CaptureIntentModule(AppController appController, Intent intent, String settingScopeNamespace)79 public CaptureIntentModule(AppController appController, Intent intent, 80 String settingScopeNamespace) throws OneCameraException { 81 super(appController); 82 mModuleUI = new CaptureIntentModuleUI( 83 appController.getCameraAppUI(), 84 appController.getModuleLayoutRoot(), 85 mUIListener); 86 mStateMachine = new StateMachineImpl(); 87 mResourceConstructed = ResourceConstructedImpl.create( 88 intent, 89 mModuleUI, 90 settingScopeNamespace, 91 MainThread.create(), 92 appController.getAndroidContext(), 93 appController.getCameraOpener(), 94 OneCameraModule.provideOneCameraManager(), 95 appController.getLocationManager(), 96 appController.getOrientationManager(), 97 appController.getSettingsManager(), 98 new BurstFacadeFactory.BurstFacadeStub(), 99 appController, 100 appController.getFatalErrorHandler()); 101 final State initialState = StateBackground.create(mStateMachine, mResourceConstructed); 102 // Set the initial state. 103 mStateMachine.setInitialState(initialState); 104 } 105 106 @Override onCameraAvailable(CameraAgent.CameraProxy cameraProxy)107 public void onCameraAvailable(CameraAgent.CameraProxy cameraProxy) { 108 // Do nothing for capture intent. 109 } 110 111 @Override onShutterButtonFocus(boolean pressed)112 public void onShutterButtonFocus(boolean pressed) { 113 // Do nothing for capture intent. 114 } 115 116 @Override onShutterCoordinate(TouchCoordinate touchCoordinate)117 public void onShutterCoordinate(TouchCoordinate touchCoordinate) { 118 mTouchPointInsideShutterButton = touchCoordinate; 119 } 120 121 @Override onShutterButtonClick()122 public void onShutterButtonClick() { 123 mStateMachine.processEvent(new EventTapOnShutterButton(mTouchPointInsideShutterButton)); 124 } 125 126 @Override onShutterButtonLongPressed()127 public void onShutterButtonLongPressed() { 128 // Do nothing for capture intent. 129 } 130 131 @Override init( final CameraActivity activity, boolean isSecureCamera, boolean isCaptureIntent)132 public void init( 133 final CameraActivity activity, boolean isSecureCamera, boolean isCaptureIntent) { 134 mResourceConstructed.get().getAppController() 135 .setPreviewStatusListener(mPreviewStatusListener); 136 137 // Issue cancel countdown event when the button is pressed. 138 // TODO: Make this part of the official API the way shutter button events are. 139 mResourceConstructed.get().getAppController().getCameraAppUI() 140 .setCancelShutterButtonListener(new View.OnClickListener() { 141 @Override 142 public void onClick(View v) { 143 mStateMachine.processEvent(new EventTapOnCancelShutterButton()); 144 } 145 }); 146 147 } 148 149 @Override resume()150 public void resume() { 151 mModuleUI.onModuleResumed(); 152 mStateMachine.processEvent(new EventResume()); 153 } 154 155 @Override pause()156 public void pause() { 157 mModuleUI.setCountdownFinishedListener(null); 158 mModuleUI.onModulePaused(); 159 mStateMachine.processEvent(new EventPause()); 160 } 161 162 @Override destroy()163 public void destroy() { 164 // Never called. Do nothing here. 165 } 166 167 @Override onPreviewVisibilityChanged(int visibility)168 public void onPreviewVisibilityChanged(int visibility) { 169 // Do nothing. 170 } 171 172 @Override onLayoutOrientationChanged(boolean isLandscape)173 public void onLayoutOrientationChanged(boolean isLandscape) { 174 // Do nothing. 175 } 176 177 @Override hardResetSettings(SettingsManager settingsManager)178 public void hardResetSettings(SettingsManager settingsManager) { 179 // Do nothing. 180 } 181 182 @Override getHardwareSpec()183 public HardwareSpec getHardwareSpec() { 184 /** 185 * Instead of passively providing CameraAppUI the hardware spec here, 186 * {@link com.android.camera.captureintent.state.StateOpeningCamera} 187 * will actively specify hardware spec. 188 */ 189 return null; 190 } 191 192 @Override getBottomBarSpec()193 public CameraAppUI.BottomBarUISpec getBottomBarSpec() { 194 /** 195 * Instead of passively providing CameraAppUI the bottom bar spec here, 196 * {@link com.android.camera.captureintent.state.StateOpeningCamera} 197 * will actively specify bottom bar spec. 198 */ 199 return null; 200 } 201 202 @Override isUsingBottomBar()203 public boolean isUsingBottomBar() { 204 return true; 205 } 206 207 @Override getPeekAccessibilityString()208 public String getPeekAccessibilityString() { 209 return mResourceConstructed.get().getContext().getResources() 210 .getString(R.string.photo_accessibility_peek); 211 } 212 213 @Override onKeyDown(int keyCode, KeyEvent event)214 public boolean onKeyDown(int keyCode, KeyEvent event) { 215 switch (keyCode) { 216 case KeyEvent.KEYCODE_CAMERA: 217 case KeyEvent.KEYCODE_DPAD_CENTER: 218 mStateMachine.processEvent(new EventClickOnCameraKey()); 219 return true; 220 case KeyEvent.KEYCODE_VOLUME_UP: 221 case KeyEvent.KEYCODE_VOLUME_DOWN: 222 // Prevent default. 223 return true; 224 } 225 return false; 226 } 227 228 @Override onKeyUp(int keyCode, KeyEvent event)229 public boolean onKeyUp(int keyCode, KeyEvent event) { 230 switch (keyCode) { 231 case KeyEvent.KEYCODE_VOLUME_UP: 232 case KeyEvent.KEYCODE_VOLUME_DOWN: 233 mStateMachine.processEvent(new EventClickOnCameraKey()); 234 return true; 235 } 236 return false; 237 } 238 239 /** The listener to listen events from the UI. */ 240 private final CaptureIntentModuleUI.Listener mUIListener = 241 new CaptureIntentModuleUI.Listener() { 242 @Override 243 public void onZoomRatioChanged(final float zoomRatio) { 244 mStateMachine.processEvent(new EventZoomRatioChanged(zoomRatio)); 245 } 246 }; 247 248 /** The listener to listen events from the preview. */ 249 private final PreviewStatusListener mPreviewStatusListener = new PreviewStatusListener() { 250 @Override 251 public void onPreviewLayoutChanged(View v, int left, int top, int right, 252 int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { 253 final Size previewLayoutSize = new Size(right - left, bottom - top); 254 mStateMachine.processEvent(new EventOnTextureViewLayoutChanged(previewLayoutSize)); 255 } 256 257 @Override 258 public boolean shouldAutoAdjustTransformMatrixOnLayout() { 259 return CaptureIntentConfig.WORKAROUND_PREVIEW_STRETCH_BUG_NEXUS4; 260 } 261 262 @Override 263 public void onPreviewFlipped() { 264 // Do nothing because when preview is flipped, TextureView will lay 265 // itself out again, which will then trigger a transform matrix 266 // update. 267 } 268 269 @Override 270 public GestureDetector.OnGestureListener getGestureListener() { 271 return new GestureDetector.SimpleOnGestureListener() { 272 @Override 273 public boolean onSingleTapUp(MotionEvent ev) { 274 final Point tapPoint = new Point((int) ev.getX(), (int) ev.getY()); 275 mStateMachine.processEvent(new EventTapOnPreview(tapPoint)); 276 return true; 277 } 278 }; 279 } 280 281 @Override 282 public View.OnTouchListener getTouchListener() { 283 return null; 284 } 285 286 @Override 287 public void onSurfaceTextureAvailable( 288 final SurfaceTexture surfaceTexture, int width, int height) { 289 mStateMachine.processEvent(new EventOnSurfaceTextureAvailable(surfaceTexture)); 290 } 291 292 @Override 293 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 294 mStateMachine.processEvent(new EventOnSurfaceTextureDestroyed()); 295 return true; 296 } 297 298 @Override 299 public void onSurfaceTextureSizeChanged( 300 SurfaceTexture surfaceTexture, int width, int height) { 301 } 302 303 @Override 304 public void onSurfaceTextureUpdated(SurfaceTexture surface) { 305 mStateMachine.processEvent(new EventOnSurfaceTextureUpdated()); 306 } 307 }; 308 } 309