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.resource;
18
19import com.google.common.logging.eventprotos;
20
21import com.android.camera.SoundPlayer;
22import com.android.camera.async.MainThread;
23import com.android.camera.async.RefCountBase;
24import com.android.camera.captureintent.CaptureIntentModuleUI;
25import com.android.camera.captureintent.CaptureIntentSessionFactory;
26import com.android.camera.debug.Log;
27import com.android.camera.hardware.HeadingSensor;
28import com.android.camera.one.OneCamera;
29import com.android.camera.session.CaptureSession;
30import com.android.camera.session.CaptureSessionManager;
31import com.android.camera.session.CaptureSessionManagerImpl;
32import com.android.camera.session.SessionStorageManagerImpl;
33import com.android.camera.settings.Keys;
34import com.android.camera.settings.SettingsManager;
35import com.android.camera.ui.focus.FocusController;
36import com.android.camera.ui.focus.FocusSound;
37import com.android.camera.util.AndroidServices;
38import com.android.camera.util.CameraUtil;
39import com.android.camera2.R;
40
41import android.media.MediaActionSound;
42
43public final class ResourceCaptureToolsImpl implements ResourceCaptureTools {
44    private static final Log.Tag TAG = new Log.Tag("ResCapTools");
45
46    private final RefCountBase<ResourceConstructed> mResourceConstructed;
47    private final RefCountBase<ResourceSurfaceTexture> mResourceSurfaceTexture;
48    private final RefCountBase<ResourceOpenedCamera> mResourceOpenedCamera;
49
50    private final CaptureSessionManager mCaptureSessionManager;
51    private final FocusController mFocusController;
52    private final HeadingSensor mHeadingSensor;
53    private final SoundPlayer mSoundPlayer;
54    private final MediaActionSound mMediaActionSound;
55
56    /**
57     * Creates a reference counted {@link ResourceCaptureToolsImpl} object.
58     */
59    public static RefCountBase<ResourceCaptureTools> create(
60            RefCountBase<ResourceConstructed> resourceConstructed,
61            RefCountBase<ResourceSurfaceTexture> resourceSurfaceTexture,
62            RefCountBase<ResourceOpenedCamera> resourceOpenedCamera) {
63        CaptureSessionManager captureSessionManager = new CaptureSessionManagerImpl(
64                new CaptureIntentSessionFactory(),
65                SessionStorageManagerImpl.create(resourceConstructed.get().getContext()),
66                resourceConstructed.get().getMainThread());
67        HeadingSensor headingSensor =
68                new HeadingSensor(AndroidServices.instance().provideSensorManager());
69        SoundPlayer soundPlayer = new SoundPlayer(resourceConstructed.get().getContext());
70        FocusSound focusSound = new FocusSound(soundPlayer, R.raw.material_camera_focus);
71        FocusController focusController = new FocusController(
72                resourceConstructed.get().getModuleUI().getFocusRing(),
73                focusSound,
74                resourceConstructed.get().getMainThread());
75        MediaActionSound mediaActionSound = new MediaActionSound();
76        ResourceCaptureTools resourceCaptureTools = new ResourceCaptureToolsImpl(
77                resourceConstructed, resourceSurfaceTexture, resourceOpenedCamera,
78                captureSessionManager, focusController, headingSensor, soundPlayer,
79                mediaActionSound);
80        return new RefCountBase<>(resourceCaptureTools);
81    }
82
83    private ResourceCaptureToolsImpl(
84            RefCountBase<ResourceConstructed> resourceConstructed,
85            RefCountBase<ResourceSurfaceTexture> resourceSurfaceTexture,
86            RefCountBase<ResourceOpenedCamera> resourceOpenedCamera,
87            CaptureSessionManager captureSessionManager,
88            FocusController focusController,
89            HeadingSensor headingSensor,
90            SoundPlayer soundPlayer,
91            MediaActionSound mediaActionSound) {
92        mResourceConstructed = resourceConstructed;
93        mResourceConstructed.addRef();     // Will be balanced in close().
94        mResourceSurfaceTexture = resourceSurfaceTexture;
95        mResourceSurfaceTexture.addRef();  // Will be balanced in close().
96        mResourceOpenedCamera = resourceOpenedCamera;
97        mResourceOpenedCamera.addRef();    // Will be balanced in close().
98        mCaptureSessionManager = captureSessionManager;
99        mHeadingSensor = headingSensor;
100        mHeadingSensor.activate();  // Will be balanced in close().
101        mSoundPlayer = soundPlayer;
102        mSoundPlayer.loadSound(R.raw.timer_final_second);  // Will be balanced in close().
103        mSoundPlayer.loadSound(R.raw.timer_increment);     // Will be balanced in close().
104        mMediaActionSound = mediaActionSound;
105        mFocusController = focusController;
106    }
107
108    @Override
109    public void close() {
110        Log.d(TAG, "close");
111        mResourceConstructed.close();
112        mResourceSurfaceTexture.close();
113        mResourceOpenedCamera.close();
114        mHeadingSensor.deactivate();
115        mSoundPlayer.unloadSound(R.raw.timer_increment);
116        mSoundPlayer.unloadSound(R.raw.timer_final_second);
117    }
118
119    @Override
120    public RefCountBase<ResourceConstructed> getResourceConstructed() {
121        return mResourceConstructed;
122    }
123
124    @Override
125    public RefCountBase<ResourceSurfaceTexture> getResourceSurfaceTexture() {
126        return mResourceSurfaceTexture;
127    }
128
129    @Override
130    public RefCountBase<ResourceOpenedCamera> getResourceOpenedCamera() {
131        return mResourceOpenedCamera;
132    }
133
134    @Override
135    public CaptureSessionManager getCaptureSessionManager() {
136        return mCaptureSessionManager;
137    }
138
139    @Override
140    public FocusController getFocusController() {
141        return mFocusController;
142    }
143
144    @Override
145    public MediaActionSound getMediaActionSound() {
146        return mMediaActionSound;
147    }
148
149    @Override
150    public void takePictureNow(
151            OneCamera.PictureCallback pictureCallback,
152            CaptureLoggingInfo captureLoggingInfo) {
153        final ResourceConstructed resource = mResourceConstructed.get();
154        final ResourceOpenedCamera openedCamera = mResourceOpenedCamera.get();
155
156        /**
157         * Disable the shutter button immediately. The button will be
158         * re-enabled when users press re-take button.
159         */
160        resource.getMainThread().execute(new Runnable() {
161            @Override
162            public void run() {
163                resource.getModuleUI().setShutterButtonEnabled(false);
164            }
165        });
166
167        /** Create a new capture session. */
168        final long timestamp = System.currentTimeMillis();
169        final String fileName = CameraUtil.instance().createJpegName(timestamp);
170        final android.location.Location location =
171                resource.getLocationManager().getCurrentLocation();
172        final CaptureSession session =
173                mCaptureSessionManager.createNewSession(fileName, timestamp, location);
174        session.startEmpty(null, openedCamera.getPictureSize());
175
176        /** Logging */
177        final SettingsManager settingsManager = resource.getSettingsManager();
178        boolean isGridLinesOn = Keys.areGridLinesOn(settingsManager);
179        session.getCollector().decorateAtTimeCaptureRequest(
180                eventprotos.NavigationChange.Mode.PHOTO_CAPTURE,
181                session.getTitle() + ".jpg",
182                (openedCamera.getCameraFacing() == OneCamera.Facing.FRONT),
183                false, /** hdrPlusEnabled */
184                openedCamera.getZoomRatio(),
185                openedCamera.getCaptureSetting().getFlashSetting().get().encodeSettingsString(),
186                isGridLinesOn,
187                (float) captureLoggingInfo.getCountDownDuration(),
188                captureLoggingInfo.getTouchPointInsideShutterButton(),
189                null /* TODO: Implement Volume Button Shutter Click Instrumentation */,
190                openedCamera.getCameraCharacteristics().getSensorInfoActiveArraySize()
191        );
192
193        OneCamera.PhotoCaptureParameters params = new OneCamera.PhotoCaptureParameters(
194                session.getTitle(),
195                resource.getOrientationManager().getDeviceOrientation().getDegrees(),
196                session.getLocation(),
197                resource.getContext().getExternalCacheDir(),
198                pictureCallback,
199                mPictureSaverCallback,
200                mHeadingSensor.getCurrentHeading(),
201                openedCamera.getZoomRatio(),
202                0);
203        openedCamera.getCamera().takePicture(params, session);
204    }
205
206    @Override
207    public void playCountDownSound(int remainingSeconds) {
208        if (remainingSeconds == 1) {
209            mSoundPlayer.play(R.raw.timer_final_second, 0.6f);
210        } else if (remainingSeconds == 2 || remainingSeconds == 3) {
211            mSoundPlayer.play(R.raw.timer_increment, 0.6f);
212        }
213    }
214
215    @Override
216    public MainThread getMainThread() {
217        return mResourceConstructed.get().getMainThread();
218    }
219
220    @Override
221    public CaptureIntentModuleUI getModuleUI() {
222        return mResourceConstructed.get().getModuleUI();
223    }
224
225    @Override
226    public OneCamera getCamera() {
227        return mResourceOpenedCamera.get().getCamera();
228    }
229
230    private final OneCamera.PictureSaverCallback mPictureSaverCallback =
231            new OneCamera.PictureSaverCallback() {
232                @Override
233                public void onRemoteThumbnailAvailable(byte[] jpegImage) {
234                }
235            };
236}
237