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
17package com.android.camera.widget;
18
19import android.content.Context;
20import android.content.res.Configuration;
21import android.graphics.RectF;
22import android.util.AttributeSet;
23import android.view.Gravity;
24import android.view.MotionEvent;
25import android.view.View;
26import android.view.ViewGroup;
27import android.widget.FrameLayout;
28import android.widget.ImageView;
29import android.widget.LinearLayout;
30
31import com.android.camera.CaptureLayoutHelper;
32import com.android.camera.ShutterButton;
33import com.android.camera.debug.Log;
34import com.android.camera.ui.PreviewOverlay;
35import com.android.camera.ui.TouchCoordinate;
36import 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 */
42public 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 static final int BOTTOM_RIGHT = Gravity.BOTTOM | Gravity.RIGHT;
50    private static final 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
59    public ModeOptionsOverlay(Context context, AttributeSet attrs) {
60        super(context, attrs);
61    }
62
63    /**
64     * Whether the mode options are hidden.
65     */
66    public boolean isModeOptionsHidden() {
67        return mModeOptions.isHiddenOrHiding();
68    }
69
70    /**
71     * Gets the current width of the mode options toggle including the three dots and various mode
72     * option indicators.
73     */
74    public float getModeOptionsToggleWidth() {
75        return mModeOptionsToggle.getWidth();
76    }
77
78    /**
79     * Sets a capture layout helper to query layout rect from.
80     */
81    public void setCaptureLayoutHelper(CaptureLayoutHelper helper) {
82        mCaptureLayoutHelper = helper;
83    }
84
85    public void setToggleClickable(boolean clickable) {
86        mModeOptionsToggle.setClickable(clickable);
87    }
88
89    public void showExposureOptions() {
90        mModeOptions.showExposureOptions();
91    }
92
93    /**
94     * Sets the mode options listener.
95     *
96     * @param listener The listener to be set.
97     */
98    public void setModeOptionsListener(ModeOptions.Listener listener) {
99        mModeOptions.setListener(listener);
100    }
101
102    @Override
103    public void onFinishInflate() {
104        mModeOptions = (ModeOptions) findViewById(R.id.mode_options);
105        mModeOptions.setClickable(true);
106        mModeOptions.setOnClickListener(new View.OnClickListener() {
107            @Override
108            public void onClick(View v) {
109                closeModeOptions();
110            }
111        });
112
113        mModeOptionsToggle = (LinearLayout) findViewById(R.id.mode_options_toggle);
114        mModeOptionsToggle.setOnClickListener(new View.OnClickListener() {
115            @Override
116            public void onClick(View v) {
117                mModeOptions.animateVisible();
118            }
119        });
120        mModeOptions.setViewToShowHide(mModeOptionsToggle);
121
122        mThreeDots = (ImageView) findViewById(R.id.three_dots);
123    }
124
125    @Override
126    public void onPreviewTouched(MotionEvent ev) {
127        closeModeOptions();
128    }
129
130    @Override
131    public void onShutterButtonClick() {
132        closeModeOptions();
133    }
134
135    @Override
136    public void onShutterCoordinate(TouchCoordinate coord) {
137        // Do nothing.
138    }
139
140    @Override
141    public void onShutterButtonFocus(boolean pressed) {
142        // noop
143    }
144
145    @Override
146    public void onShutterButtonLongPressed() {
147        // noop
148    }
149
150    /**
151     * Schedule (or re-schedule) the options menu to be closed after a number
152     * of milliseconds.  If the options menu is already closed, nothing is
153     * scheduled.
154     */
155    public void closeModeOptions() {
156        mModeOptions.animateHidden();
157    }
158
159    @Override
160    public void onConfigurationChanged(Configuration configuration) {
161        super.onConfigurationChanged(configuration);
162        checkOrientation(configuration.orientation);
163    }
164
165    @Override
166    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
167        if (mCaptureLayoutHelper == null) {
168            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
169            Log.e(TAG, "Capture layout helper needs to be set first.");
170        } else {
171            RectF uncoveredPreviewRect = mCaptureLayoutHelper.getUncoveredPreviewRect();
172            super.onMeasure(MeasureSpec.makeMeasureSpec(
173                            (int) uncoveredPreviewRect.width(), MeasureSpec.EXACTLY),
174                    MeasureSpec.makeMeasureSpec((int) uncoveredPreviewRect.height(),
175                            MeasureSpec.EXACTLY)
176            );
177        }
178    }
179
180    /**
181     * Set the layout gravity of the child layout to be bottom or top right
182     * depending on orientation.
183     */
184    private void checkOrientation(int orientation) {
185        final boolean isPortrait = (Configuration.ORIENTATION_PORTRAIT == orientation);
186
187        final int modeOptionsDimension = (int) getResources()
188            .getDimension(R.dimen.mode_options_height);
189
190        FrameLayout.LayoutParams modeOptionsParams
191            = (FrameLayout.LayoutParams) mModeOptions.getLayoutParams();
192        FrameLayout.LayoutParams modeOptionsToggleParams
193            = (FrameLayout.LayoutParams) mModeOptionsToggle.getLayoutParams();
194
195        if (isPortrait) {
196            modeOptionsParams.height = modeOptionsDimension;
197            modeOptionsParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
198            modeOptionsParams.gravity = Gravity.BOTTOM;
199
200            modeOptionsToggleParams.gravity = BOTTOM_RIGHT;
201
202            mThreeDots.setImageResource(R.drawable.ic_options_port);
203        } else {
204            modeOptionsParams.width = modeOptionsDimension;
205            modeOptionsParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
206            modeOptionsParams.gravity = Gravity.RIGHT;
207
208            modeOptionsToggleParams.gravity = TOP_RIGHT;
209
210            mThreeDots.setImageResource(R.drawable.ic_options_land);
211        }
212
213        requestLayout();
214    }
215}
216