• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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;
18 
19 import android.app.AlertDialog;
20 import android.app.ProgressDialog;
21 import android.content.Context;
22 import android.content.DialogInterface;
23 import android.content.res.Configuration;
24 import android.content.res.Resources;
25 import android.graphics.Bitmap;
26 import android.graphics.Canvas;
27 import android.graphics.Matrix;
28 import android.graphics.Point;
29 import android.graphics.Rect;
30 import android.graphics.SurfaceTexture;
31 import android.graphics.drawable.BitmapDrawable;
32 import android.graphics.drawable.Drawable;
33 import android.util.Log;
34 import android.view.LayoutInflater;
35 import android.view.TextureView;
36 import android.view.View;
37 import android.view.ViewGroup;
38 import android.widget.FrameLayout;
39 import android.widget.ImageView;
40 import android.widget.LinearLayout;
41 import android.widget.TextView;
42 
43 import com.android.camera.ui.CameraControls;
44 import com.android.camera.ui.CameraRootView;
45 import com.android.camera.ui.ModuleSwitcher;
46 import com.android.camera.util.CameraUtil;
47 import com.android.camera2.R;
48 
49 /**
50  * The UI of {@link WideAnglePanoramaModule}.
51  */
52 public class WideAnglePanoramaUI implements
53         TextureView.SurfaceTextureListener,
54         ShutterButton.OnShutterButtonListener,
55         CameraRootView.MyDisplayListener,
56         View.OnLayoutChangeListener {
57 
58     @SuppressWarnings("unused")
59     private static final String TAG = "CAM_WidePanoramaUI";
60 
61     private CameraActivity mActivity;
62     private WideAnglePanoramaController mController;
63 
64     private ViewGroup mRootView;
65     private ModuleSwitcher mSwitcher;
66     private FrameLayout mCaptureLayout;
67     private View mReviewLayout;
68     private ImageView mReview;
69     private View mPreviewBorder;
70     private View mLeftIndicator;
71     private View mRightIndicator;
72     private View mCaptureIndicator;
73     private PanoProgressBar mCaptureProgressBar;
74     private PanoProgressBar mSavingProgressBar;
75     private TextView mTooFastPrompt;
76     private View mPreviewLayout;
77     private ViewGroup mReviewControl;
78     private TextureView mTextureView;
79     private ShutterButton mShutterButton;
80     private CameraControls mCameraControls;
81 
82     private Matrix mProgressDirectionMatrix = new Matrix();
83     private float[] mProgressAngle = new float[2];
84 
85     private DialogHelper mDialogHelper;
86 
87     // Color definitions.
88     private int mIndicatorColor;
89     private int mIndicatorColorFast;
90     private int mReviewBackground;
91     private SurfaceTexture mSurfaceTexture;
92     private View mPreviewCover;
93 
94     /** Constructor. */
WideAnglePanoramaUI( CameraActivity activity, WideAnglePanoramaController controller, ViewGroup root)95     public WideAnglePanoramaUI(
96             CameraActivity activity,
97             WideAnglePanoramaController controller,
98             ViewGroup root) {
99         mActivity = activity;
100         mController = controller;
101         mRootView = root;
102 
103         createContentView();
104         mSwitcher = (ModuleSwitcher) mRootView.findViewById(R.id.camera_switcher);
105         mSwitcher.setCurrentIndex(ModuleSwitcher.WIDE_ANGLE_PANO_MODULE_INDEX);
106         mSwitcher.setSwitchListener(mActivity);
107     }
108 
onStartCapture()109     public void onStartCapture() {
110         hideSwitcher();
111         mShutterButton.setImageResource(R.drawable.btn_shutter_recording);
112         mCaptureIndicator.setVisibility(View.VISIBLE);
113         showDirectionIndicators(PanoProgressBar.DIRECTION_NONE);
114     }
115 
showPreviewUI()116     public void showPreviewUI() {
117         mCaptureLayout.setVisibility(View.VISIBLE);
118         showUI();
119     }
120 
onStopCapture()121     public void onStopCapture() {
122         mCaptureIndicator.setVisibility(View.INVISIBLE);
123         hideTooFastIndication();
124         hideDirectionIndicators();
125     }
126 
hideSwitcher()127     public void hideSwitcher() {
128         mSwitcher.closePopup();
129         mSwitcher.setVisibility(View.INVISIBLE);
130     }
131 
hideUI()132     public void hideUI() {
133         hideSwitcher();
134         mCameraControls.setVisibility(View.INVISIBLE);
135     }
136 
showUI()137     public void showUI() {
138         showSwitcher();
139         mCameraControls.setVisibility(View.VISIBLE);
140     }
141 
onPreviewFocusChanged(boolean previewFocused)142     public void onPreviewFocusChanged(boolean previewFocused) {
143         if (previewFocused) {
144             showUI();
145         } else {
146             hideUI();
147         }
148     }
149 
arePreviewControlsVisible()150     public boolean arePreviewControlsVisible() {
151         return (mCameraControls.getVisibility() == View.VISIBLE);
152     }
153 
showSwitcher()154     public void showSwitcher() {
155         mSwitcher.setVisibility(View.VISIBLE);
156     }
157 
setCaptureProgressOnDirectionChangeListener( PanoProgressBar.OnDirectionChangeListener listener)158     public void setCaptureProgressOnDirectionChangeListener(
159             PanoProgressBar.OnDirectionChangeListener listener) {
160         mCaptureProgressBar.setOnDirectionChangeListener(listener);
161     }
162 
resetCaptureProgress()163     public void resetCaptureProgress() {
164         mCaptureProgressBar.reset();
165     }
166 
setMaxCaptureProgress(int max)167     public void setMaxCaptureProgress(int max) {
168         mCaptureProgressBar.setMaxProgress(max);
169     }
170 
showCaptureProgress()171     public void showCaptureProgress() {
172         mCaptureProgressBar.setVisibility(View.VISIBLE);
173     }
174 
updateCaptureProgress( float panningRateXInDegree, float panningRateYInDegree, float progressHorizontalAngle, float progressVerticalAngle, float maxPanningSpeed)175     public void updateCaptureProgress(
176             float panningRateXInDegree, float panningRateYInDegree,
177             float progressHorizontalAngle, float progressVerticalAngle,
178             float maxPanningSpeed) {
179 
180         if ((Math.abs(panningRateXInDegree) > maxPanningSpeed)
181                 || (Math.abs(panningRateYInDegree) > maxPanningSpeed)) {
182             showTooFastIndication();
183         } else {
184             hideTooFastIndication();
185         }
186 
187         // progressHorizontalAngle and progressVerticalAngle are relative to the
188         // camera. Convert them to UI direction.
189         mProgressAngle[0] = progressHorizontalAngle;
190         mProgressAngle[1] = progressVerticalAngle;
191         mProgressDirectionMatrix.mapPoints(mProgressAngle);
192 
193         int angleInMajorDirection =
194                 (Math.abs(mProgressAngle[0]) > Math.abs(mProgressAngle[1]))
195                         ? (int) mProgressAngle[0]
196                         : (int) mProgressAngle[1];
197         mCaptureProgressBar.setProgress((angleInMajorDirection));
198     }
199 
setProgressOrientation(int orientation)200     public void setProgressOrientation(int orientation) {
201         mProgressDirectionMatrix.reset();
202         mProgressDirectionMatrix.postRotate(orientation);
203     }
204 
showDirectionIndicators(int direction)205     public void showDirectionIndicators(int direction) {
206         switch (direction) {
207             case PanoProgressBar.DIRECTION_NONE:
208                 mLeftIndicator.setVisibility(View.VISIBLE);
209                 mRightIndicator.setVisibility(View.VISIBLE);
210                 break;
211             case PanoProgressBar.DIRECTION_LEFT:
212                 mLeftIndicator.setVisibility(View.VISIBLE);
213                 mRightIndicator.setVisibility(View.INVISIBLE);
214                 break;
215             case PanoProgressBar.DIRECTION_RIGHT:
216                 mLeftIndicator.setVisibility(View.INVISIBLE);
217                 mRightIndicator.setVisibility(View.VISIBLE);
218                 break;
219         }
220     }
221 
getSurfaceTexture()222     public SurfaceTexture getSurfaceTexture() {
223         return mSurfaceTexture;
224     }
225 
226     @Override
onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i2)227     public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i2) {
228         mSurfaceTexture = surfaceTexture;
229         mController.onPreviewUIReady();
230     }
231 
232     @Override
onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i2)233     public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i2) {
234 
235     }
236 
237     @Override
onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture)238     public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
239         mController.onPreviewUIDestroyed();
240         mSurfaceTexture = null;
241         Log.d(TAG, "surfaceTexture is destroyed");
242         return true;
243     }
244 
245     @Override
onSurfaceTextureUpdated(SurfaceTexture surfaceTexture)246     public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
247         // Make sure preview cover is hidden if preview data is available.
248         if (mPreviewCover.getVisibility() != View.GONE) {
249             mPreviewCover.setVisibility(View.GONE);
250         }
251     }
252 
hideDirectionIndicators()253     private void hideDirectionIndicators() {
254         mLeftIndicator.setVisibility(View.INVISIBLE);
255         mRightIndicator.setVisibility(View.INVISIBLE);
256     }
257 
getPreviewAreaSize()258     public Point getPreviewAreaSize() {
259         return new Point(
260                 mTextureView.getWidth(), mTextureView.getHeight());
261     }
262 
reset()263     public void reset() {
264         mShutterButton.setImageResource(R.drawable.btn_new_shutter);
265         mReviewLayout.setVisibility(View.GONE);
266         mCaptureProgressBar.setVisibility(View.INVISIBLE);
267     }
268 
showFinalMosaic(Bitmap bitmap, int orientation)269     public void showFinalMosaic(Bitmap bitmap, int orientation) {
270         if (bitmap != null && orientation != 0) {
271             Matrix rotateMatrix = new Matrix();
272             rotateMatrix.setRotate(orientation);
273             bitmap = Bitmap.createBitmap(
274                     bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
275                     rotateMatrix, false);
276         }
277 
278         mReview.setImageBitmap(bitmap);
279         mCaptureLayout.setVisibility(View.GONE);
280         mReviewLayout.setVisibility(View.VISIBLE);
281     }
282 
onConfigurationChanged( Configuration newConfig, boolean threadRunning)283     public void onConfigurationChanged(
284             Configuration newConfig, boolean threadRunning) {
285         Drawable lowResReview = null;
286         if (threadRunning) lowResReview = mReview.getDrawable();
287 
288         // Change layout in response to configuration change
289         LayoutInflater inflater = (LayoutInflater)
290                 mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
291 
292         mReviewControl.removeAllViews();
293         inflater.inflate(R.layout.pano_review_control, mReviewControl, true);
294 
295         mRootView.bringChildToFront(mCameraControls);
296         setViews(mActivity.getResources());
297         if (threadRunning) {
298             mReview.setImageDrawable(lowResReview);
299             mCaptureLayout.setVisibility(View.GONE);
300             mReviewLayout.setVisibility(View.VISIBLE);
301         }
302     }
303 
resetSavingProgress()304     public void resetSavingProgress() {
305         mSavingProgressBar.reset();
306         mSavingProgressBar.setRightIncreasing(true);
307     }
308 
updateSavingProgress(int progress)309     public void updateSavingProgress(int progress) {
310         mSavingProgressBar.setProgress(progress);
311     }
312 
313     @Override
onShutterButtonFocus(boolean pressed)314     public void onShutterButtonFocus(boolean pressed) {
315         // Do nothing.
316     }
317 
318     @Override
onShutterButtonClick()319     public void onShutterButtonClick() {
320         mController.onShutterButtonClick();
321     }
322 
323     @Override
onLayoutChange( View v, int l, int t, int r, int b, int oldl, int oldt, int oldr, int oldb)324     public void onLayoutChange(
325             View v, int l, int t, int r, int b,
326             int oldl, int oldt, int oldr, int oldb) {
327         mController.onPreviewUILayoutChange(l, t, r, b);
328     }
329 
showAlertDialog( String title, String failedString, String OKString, Runnable runnable)330     public void showAlertDialog(
331             String title, String failedString,
332             String OKString, Runnable runnable) {
333         mDialogHelper.showAlertDialog(title, failedString, OKString, runnable);
334     }
335 
showWaitingDialog(String title)336     public void showWaitingDialog(String title) {
337         mDialogHelper.showWaitingDialog(title);
338     }
339 
dismissAllDialogs()340     public void dismissAllDialogs() {
341         mDialogHelper.dismissAll();
342     }
343 
createContentView()344     private void createContentView() {
345         LayoutInflater inflator = (LayoutInflater) mActivity
346                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
347         inflator.inflate(R.layout.panorama_module, mRootView, true);
348 
349         Resources appRes = mActivity.getResources();
350         mIndicatorColor = appRes.getColor(R.color.pano_progress_indication);
351         mReviewBackground = appRes.getColor(R.color.review_background);
352         mIndicatorColorFast = appRes.getColor(R.color.pano_progress_indication_fast);
353 
354         mPreviewCover = mRootView.findViewById(R.id.preview_cover);
355         mPreviewLayout = mRootView.findViewById(R.id.pano_preview_layout);
356         mReviewControl = (ViewGroup) mRootView.findViewById(R.id.pano_review_control);
357         mReviewLayout = mRootView.findViewById(R.id.pano_review_layout);
358         mReview = (ImageView) mRootView.findViewById(R.id.pano_reviewarea);
359         mCaptureLayout = (FrameLayout) mRootView.findViewById(R.id.panorama_capture_layout);
360         mCaptureProgressBar = (PanoProgressBar) mRootView.findViewById(R.id.pano_pan_progress_bar);
361         mCaptureProgressBar.setBackgroundColor(appRes.getColor(R.color.pano_progress_empty));
362         mCaptureProgressBar.setDoneColor(appRes.getColor(R.color.pano_progress_done));
363         mCaptureProgressBar.setIndicatorColor(mIndicatorColor);
364         mCaptureProgressBar.setIndicatorWidth(20);
365 
366         mPreviewBorder = mCaptureLayout.findViewById(R.id.pano_preview_area_border);
367 
368         mLeftIndicator = mRootView.findViewById(R.id.pano_pan_left_indicator);
369         mRightIndicator = mRootView.findViewById(R.id.pano_pan_right_indicator);
370         mLeftIndicator.setEnabled(false);
371         mRightIndicator.setEnabled(false);
372         mTooFastPrompt = (TextView) mRootView.findViewById(R.id.pano_capture_too_fast_textview);
373         mCaptureIndicator = mRootView.findViewById(R.id.pano_capture_indicator);
374 
375         mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button);
376         mShutterButton.setImageResource(R.drawable.btn_new_shutter);
377         mShutterButton.setOnShutterButtonListener(this);
378         // Hide menu and indicators.
379         mRootView.findViewById(R.id.menu).setVisibility(View.GONE);
380         mRootView.findViewById(R.id.on_screen_indicators).setVisibility(View.GONE);
381         mReview.setBackgroundColor(mReviewBackground);
382 
383         // TODO: set display change listener properly.
384         ((CameraRootView) mRootView).setDisplayChangeListener(null);
385         mTextureView = (TextureView) mRootView.findViewById(R.id.pano_preview_textureview);
386         mTextureView.setSurfaceTextureListener(this);
387         mTextureView.addOnLayoutChangeListener(this);
388         mCameraControls = (CameraControls) mRootView.findViewById(R.id.camera_controls);
389 
390         mDialogHelper = new DialogHelper();
391         setViews(appRes);
392     }
393 
setViews(Resources appRes)394     private void setViews(Resources appRes) {
395         int weight = appRes.getInteger(R.integer.SRI_pano_layout_weight);
396 
397         LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mPreviewLayout.getLayoutParams();
398         lp.weight = weight;
399         mPreviewLayout.setLayoutParams(lp);
400 
401         lp = (LinearLayout.LayoutParams) mReview.getLayoutParams();
402         lp.weight = weight;
403         mPreviewLayout.setLayoutParams(lp);
404 
405         mSavingProgressBar = (PanoProgressBar) mRootView.findViewById(R.id.pano_saving_progress_bar);
406         mSavingProgressBar.setIndicatorWidth(0);
407         mSavingProgressBar.setMaxProgress(100);
408         mSavingProgressBar.setBackgroundColor(appRes.getColor(R.color.pano_progress_empty));
409         mSavingProgressBar.setDoneColor(appRes.getColor(R.color.pano_progress_indication));
410 
411         View cancelButton = mRootView.findViewById(R.id.pano_review_cancel_button);
412         cancelButton.setOnClickListener(new View.OnClickListener() {
413             @Override
414             public void onClick(View arg0) {
415                 mController.cancelHighResStitching();
416             }
417         });
418 
419 
420     }
421 
showTooFastIndication()422     private void showTooFastIndication() {
423         mTooFastPrompt.setVisibility(View.VISIBLE);
424         // The PreviewArea also contains the border for "too fast" indication.
425         mPreviewBorder.setVisibility(View.VISIBLE);
426         mCaptureProgressBar.setIndicatorColor(mIndicatorColorFast);
427         mLeftIndicator.setEnabled(true);
428         mRightIndicator.setEnabled(true);
429     }
430 
hideTooFastIndication()431     private void hideTooFastIndication() {
432         mTooFastPrompt.setVisibility(View.GONE);
433         mPreviewBorder.setVisibility(View.INVISIBLE);
434         mCaptureProgressBar.setIndicatorColor(mIndicatorColor);
435         mLeftIndicator.setEnabled(false);
436         mRightIndicator.setEnabled(false);
437     }
438 
flipPreviewIfNeeded()439     public void flipPreviewIfNeeded() {
440         // Rotation needed to display image correctly clockwise
441         int cameraOrientation = mController.getCameraOrientation();
442         // Display rotated counter-clockwise
443         int displayRotation = CameraUtil.getDisplayRotation(mActivity);
444         // Rotation needed to display image correctly on current display
445         int rotation = (cameraOrientation - displayRotation + 360) % 360;
446         if (rotation >= 180) {
447             mTextureView.setRotation(180);
448         } else {
449             mTextureView.setRotation(0);
450         }
451     }
452 
453     @Override
onDisplayChanged()454     public void onDisplayChanged() {
455         mCameraControls.checkLayoutFlip();
456         flipPreviewIfNeeded();
457     }
458 
initDisplayChangeListener()459     public void initDisplayChangeListener() {
460         ((CameraRootView) mRootView).setDisplayChangeListener(this);
461     }
462 
removeDisplayChangeListener()463     public void removeDisplayChangeListener() {
464         ((CameraRootView) mRootView).removeDisplayChangeListener();
465     }
466 
showPreviewCover()467     public void showPreviewCover() {
468         mPreviewCover.setVisibility(View.VISIBLE);
469     }
470 
471     private class DialogHelper {
472         private ProgressDialog mProgressDialog;
473         private AlertDialog mAlertDialog;
474 
DialogHelper()475         DialogHelper() {
476             mProgressDialog = null;
477             mAlertDialog = null;
478         }
479 
dismissAll()480         public void dismissAll() {
481             if (mAlertDialog != null) {
482                 mAlertDialog.dismiss();
483                 mAlertDialog = null;
484             }
485             if (mProgressDialog != null) {
486                 mProgressDialog.dismiss();
487                 mProgressDialog = null;
488             }
489         }
490 
showAlertDialog( CharSequence title, CharSequence message, CharSequence buttonMessage, final Runnable buttonRunnable)491         public void showAlertDialog(
492                 CharSequence title, CharSequence message,
493                 CharSequence buttonMessage, final Runnable buttonRunnable) {
494             dismissAll();
495             mAlertDialog = (new AlertDialog.Builder(mActivity))
496                     .setTitle(title)
497                     .setMessage(message)
498                     .setNeutralButton(buttonMessage, new DialogInterface.OnClickListener() {
499                         @Override
500                         public void onClick(DialogInterface dialogInterface, int i) {
501                             buttonRunnable.run();
502                         }
503                     })
504                     .show();
505         }
506 
showWaitingDialog(CharSequence message)507         public void showWaitingDialog(CharSequence message) {
508             dismissAll();
509             mProgressDialog = ProgressDialog.show(mActivity, null, message, true, false);
510         }
511     }
512 
513     private static class FlipBitmapDrawable extends BitmapDrawable {
514 
FlipBitmapDrawable(Resources res, Bitmap bitmap)515         public FlipBitmapDrawable(Resources res, Bitmap bitmap) {
516             super(res, bitmap);
517         }
518 
519         @Override
draw(Canvas canvas)520         public void draw(Canvas canvas) {
521             Rect bounds = getBounds();
522             int cx = bounds.centerX();
523             int cy = bounds.centerY();
524             canvas.save(Canvas.MATRIX_SAVE_FLAG);
525             canvas.rotate(180, cx, cy);
526             super.draw(canvas);
527             canvas.restore();
528         }
529     }
530 }
531