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 17package com.android.camera.captureintent; 18 19import android.content.Intent; 20import android.graphics.Point; 21import android.graphics.SurfaceTexture; 22import android.view.GestureDetector; 23import android.view.KeyEvent; 24import android.view.MotionEvent; 25import android.view.View; 26 27import com.android.camera.CameraActivity; 28import com.android.camera.CameraModule; 29import com.android.camera.app.AppController; 30import com.android.camera.app.CameraAppUI; 31import com.android.camera.async.MainThread; 32import com.android.camera.async.RefCountBase; 33import com.android.camera.burst.BurstFacadeFactory; 34import com.android.camera.captureintent.event.EventClickOnCameraKey; 35import com.android.camera.captureintent.event.EventOnSurfaceTextureAvailable; 36import com.android.camera.captureintent.event.EventOnSurfaceTextureDestroyed; 37import com.android.camera.captureintent.event.EventOnSurfaceTextureUpdated; 38import com.android.camera.captureintent.event.EventOnTextureViewLayoutChanged; 39import com.android.camera.captureintent.event.EventPause; 40import com.android.camera.captureintent.event.EventResume; 41import com.android.camera.captureintent.event.EventTapOnCancelShutterButton; 42import com.android.camera.captureintent.event.EventTapOnPreview; 43import com.android.camera.captureintent.event.EventTapOnShutterButton; 44import com.android.camera.captureintent.event.EventZoomRatioChanged; 45import com.android.camera.captureintent.resource.ResourceConstructed; 46import com.android.camera.captureintent.resource.ResourceConstructedImpl; 47import com.android.camera.captureintent.state.StateBackground; 48import com.android.camera.captureintent.stateful.State; 49import com.android.camera.captureintent.stateful.StateMachine; 50import com.android.camera.captureintent.stateful.StateMachineImpl; 51import com.android.camera.debug.Log; 52import com.android.camera.hardware.HardwareSpec; 53import com.android.camera.one.OneCameraException; 54import com.android.camera.one.OneCameraModule; 55import com.android.camera.settings.SettingsManager; 56import com.android.camera.ui.PreviewStatusListener; 57import com.android.camera.ui.TouchCoordinate; 58import com.android.camera.util.Size; 59import com.android.camera2.R; 60import com.android.ex.camera2.portability.CameraAgent; 61 62/** 63 * The camera module that handles image capture intent. 64 */ 65public 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 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 107 public void onCameraAvailable(CameraAgent.CameraProxy cameraProxy) { 108 // Do nothing for capture intent. 109 } 110 111 @Override 112 public void onShutterButtonFocus(boolean pressed) { 113 // Do nothing for capture intent. 114 } 115 116 @Override 117 public void onShutterCoordinate(TouchCoordinate touchCoordinate) { 118 mTouchPointInsideShutterButton = touchCoordinate; 119 } 120 121 @Override 122 public void onShutterButtonClick() { 123 mStateMachine.processEvent(new EventTapOnShutterButton(mTouchPointInsideShutterButton)); 124 } 125 126 @Override 127 public void onShutterButtonLongPressed() { 128 // Do nothing for capture intent. 129 } 130 131 @Override 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 150 public void resume() { 151 mModuleUI.onModuleResumed(); 152 mStateMachine.processEvent(new EventResume()); 153 } 154 155 @Override 156 public void pause() { 157 mModuleUI.setCountdownFinishedListener(null); 158 mModuleUI.onModulePaused(); 159 mStateMachine.processEvent(new EventPause()); 160 } 161 162 @Override 163 public void destroy() { 164 // Never called. Do nothing here. 165 } 166 167 @Override 168 public void onPreviewVisibilityChanged(int visibility) { 169 // Do nothing. 170 } 171 172 @Override 173 public void onLayoutOrientationChanged(boolean isLandscape) { 174 // Do nothing. 175 } 176 177 @Override 178 public void hardResetSettings(SettingsManager settingsManager) { 179 // Do nothing. 180 } 181 182 @Override 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 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 203 public boolean isUsingBottomBar() { 204 return true; 205 } 206 207 @Override 208 public String getPeekAccessibilityString() { 209 return mResourceConstructed.get().getContext().getResources() 210 .getString(R.string.photo_accessibility_peek); 211 } 212 213 @Override 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 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