1 /*
2  * Copyright (C) 2014 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.widget;
18 
19 import android.content.Context;
20 import android.content.res.Configuration;
21 import android.graphics.RectF;
22 import android.util.AttributeSet;
23 import android.view.Gravity;
24 import android.view.MotionEvent;
25 import android.view.View;
26 import android.view.ViewGroup;
27 import android.widget.FrameLayout;
28 import android.widget.ImageView;
29 import android.widget.LinearLayout;
30 
31 import com.android.camera.CaptureLayoutHelper;
32 import com.android.camera.ShutterButton;
33 import com.android.camera.debug.Log;
34 import com.android.camera.ui.PreviewOverlay;
35 import com.android.camera.ui.TouchCoordinate;
36 import com.android.camera2.R;
37 
38 /**
39  * ModeOptionsOverlay is a FrameLayout which positions mode options in
40  * in the bottom of the preview that is visible above the bottom bar.
41  */
42 public class ModeOptionsOverlay extends FrameLayout
43     implements PreviewOverlay.OnPreviewTouchedListener,
44                ShutterButton.OnShutterButtonListener {
45 
46     private final static Log.Tag TAG = new Log.Tag("ModeOptionsOverlay");
47 
48     private static final int BOTTOMBAR_OPTIONS_TIMEOUT_MS = 2000;
49     private final static int BOTTOM_RIGHT = Gravity.BOTTOM | Gravity.RIGHT;
50     private final static int TOP_RIGHT = Gravity.TOP | Gravity.RIGHT;
51 
52     private ModeOptions mModeOptions;
53     // need a reference to set the onClickListener and fix the layout gravity on orientation change
54     private LinearLayout mModeOptionsToggle;
55     // need a reference to fix the rotation on orientation change
56     private ImageView mThreeDots;
57     private CaptureLayoutHelper mCaptureLayoutHelper = null;
58 
ModeOptionsOverlay(Context context, AttributeSet attrs)59     public ModeOptionsOverlay(Context context, AttributeSet attrs) {
60         super(context, attrs);
61     }
62 
63     /**
64      * Sets a capture layout helper to query layout rect from.
65      */
setCaptureLayoutHelper(CaptureLayoutHelper helper)66     public void setCaptureLayoutHelper(CaptureLayoutHelper helper) {
67         mCaptureLayoutHelper = helper;
68     }
69 
setToggleClickable(boolean clickable)70     public void setToggleClickable(boolean clickable) {
71         mModeOptionsToggle.setClickable(clickable);
72     }
73 
74     @Override
onFinishInflate()75     public void onFinishInflate() {
76         mModeOptions = (ModeOptions) findViewById(R.id.mode_options);
77         mModeOptions.setClickable(true);
78         mModeOptions.setOnClickListener(new View.OnClickListener() {
79             @Override
80             public void onClick(View v) {
81                 closeModeOptions();
82             }
83         });
84 
85         mModeOptionsToggle = (LinearLayout) findViewById(R.id.mode_options_toggle);
86         mModeOptionsToggle.setOnClickListener(new View.OnClickListener() {
87             @Override
88             public void onClick(View v) {
89                 mModeOptions.animateVisible();
90             }
91         });
92         mModeOptions.setViewToShowHide(mModeOptionsToggle);
93 
94         mThreeDots = (ImageView) findViewById(R.id.three_dots);
95     }
96 
97     @Override
onPreviewTouched(MotionEvent ev)98     public void onPreviewTouched(MotionEvent ev) {
99         closeModeOptions();
100     }
101 
102     @Override
onShutterButtonClick()103     public void onShutterButtonClick() {
104         closeModeOptions();
105     }
106 
107     @Override
onShutterCoordinate(TouchCoordinate coord)108     public void onShutterCoordinate(TouchCoordinate coord) {
109         // Do nothing.
110     }
111 
112     @Override
onShutterButtonFocus(boolean pressed)113     public void onShutterButtonFocus(boolean pressed) {
114         // noop
115     }
116 
117     /**
118      * Schedule (or re-schedule) the options menu to be closed after a number
119      * of milliseconds.  If the options menu is already closed, nothing is
120      * scheduled.
121      */
closeModeOptions()122     public void closeModeOptions() {
123         mModeOptions.animateHidden();
124     }
125 
126     @Override
onConfigurationChanged(Configuration configuration)127     public void onConfigurationChanged(Configuration configuration) {
128         super.onConfigurationChanged(configuration);
129         checkOrientation(configuration.orientation);
130     }
131 
132     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)133     public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
134         if (mCaptureLayoutHelper == null) {
135             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
136             Log.e(TAG, "Capture layout helper needs to be set first.");
137         } else {
138             RectF uncoveredPreviewRect = mCaptureLayoutHelper.getUncoveredPreviewRect();
139             super.onMeasure(MeasureSpec.makeMeasureSpec(
140                             (int) uncoveredPreviewRect.width(), MeasureSpec.EXACTLY),
141                     MeasureSpec.makeMeasureSpec((int) uncoveredPreviewRect.height(),
142                             MeasureSpec.EXACTLY)
143             );
144         }
145     }
146 
147     /**
148      * Set the layout gravity of the child layout to be bottom or top right
149      * depending on orientation.
150      */
checkOrientation(int orientation)151     private void checkOrientation(int orientation) {
152         final boolean isPortrait = (Configuration.ORIENTATION_PORTRAIT == orientation);
153 
154         final int modeOptionsDimension = (int) getResources()
155             .getDimension(R.dimen.mode_options_height);
156 
157         FrameLayout.LayoutParams modeOptionsParams
158             = (FrameLayout.LayoutParams) mModeOptions.getLayoutParams();
159         FrameLayout.LayoutParams modeOptionsToggleParams
160             = (FrameLayout.LayoutParams) mModeOptionsToggle.getLayoutParams();
161 
162         if (isPortrait) {
163             modeOptionsParams.height = modeOptionsDimension;
164             modeOptionsParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
165             modeOptionsParams.gravity = Gravity.BOTTOM;
166 
167             modeOptionsToggleParams.gravity = BOTTOM_RIGHT;
168 
169             mThreeDots.setImageResource(R.drawable.ic_options_port);
170         } else {
171             modeOptionsParams.width = modeOptionsDimension;
172             modeOptionsParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
173             modeOptionsParams.gravity = Gravity.RIGHT;
174 
175             modeOptionsToggleParams.gravity = TOP_RIGHT;
176 
177             mThreeDots.setImageResource(R.drawable.ic_options_land);
178         }
179 
180         requestLayout();
181     }
182 }
183