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
17package com.android.camera.ui;
18
19import android.app.Activity;
20import android.content.Context;
21import android.content.Intent;
22import android.provider.MediaStore;
23import android.util.AttributeSet;
24import android.view.MotionEvent;
25import android.view.View;
26import android.view.ViewConfiguration;
27import android.widget.FrameLayout;
28
29import com.android.camera.app.CameraAppUI;
30import com.android.camera.debug.Log;
31import com.android.camera.util.CameraUtil;
32import com.android.camera.util.UsageStatistics;
33import com.android.camera.widget.FilmstripLayout;
34import com.android.camera2.R;
35import com.google.common.logging.eventprotos;
36
37public class MainActivityLayout extends FrameLayout {
38
39    private final Log.Tag TAG = new Log.Tag("MainActivityLayout");
40    // Only check for intercepting touch events within first 500ms
41    private static final int SWIPE_TIME_OUT = 500;
42
43    private ModeListView mModeList;
44    private FilmstripLayout mFilmstripLayout;
45    private boolean mCheckToIntercept;
46    private MotionEvent mDown;
47    private final int mSlop;
48    private boolean mRequestToInterceptTouchEvents = false;
49    private View mTouchReceiver = null;
50    private final boolean mIsCaptureIntent;
51    private CameraAppUI.NonDecorWindowSizeChangedListener mNonDecorWindowSizeChangedListener = null;
52
53    // TODO: This can be removed once we come up with a new design for b/13751653.
54    @Deprecated
55    private boolean mSwipeEnabled = true;
56
57    public MainActivityLayout(Context context, AttributeSet attrs) {
58        super(context, attrs);
59        mSlop = ViewConfiguration.get(context).getScaledTouchSlop();
60
61        Activity activity = (Activity) context;
62        Intent intent = activity.getIntent();
63        String action = intent.getAction();
64        mIsCaptureIntent = (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
65                || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(action)
66                || MediaStore.ACTION_VIDEO_CAPTURE.equals(action));
67    }
68
69    /**
70     * Enables or disables the swipe for modules not supporting the new swipe
71     * logic yet.
72     */
73    @Deprecated
74    public void setSwipeEnabled(boolean enabled) {
75        mSwipeEnabled = enabled;
76    }
77
78    @Override
79    public boolean onInterceptTouchEvent(MotionEvent ev) {
80        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
81            mCheckToIntercept = true;
82            mDown = MotionEvent.obtain(ev);
83            mTouchReceiver = null;
84            mRequestToInterceptTouchEvents = false;
85            return false;
86        } else if (mRequestToInterceptTouchEvents) {
87            mRequestToInterceptTouchEvents = false;
88            onTouchEvent(mDown);
89            return true;
90        } else if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
91            // Do not intercept touch once child is in zoom mode
92            mCheckToIntercept = false;
93            return false;
94        } else {
95            // TODO: This can be removed once we come up with a new design for b/13751653.
96            if (!mCheckToIntercept) {
97                return false;
98            }
99            if (ev.getEventTime() - ev.getDownTime() > SWIPE_TIME_OUT) {
100                return false;
101            }
102            if (mIsCaptureIntent || !mSwipeEnabled) {
103                return false;
104            }
105            int deltaX = (int) (ev.getX() - mDown.getX());
106            int deltaY = (int) (ev.getY() - mDown.getY());
107            if (ev.getActionMasked() == MotionEvent.ACTION_MOVE
108                    && Math.abs(deltaX) > mSlop) {
109                // Intercept right swipe
110                if (deltaX >= Math.abs(deltaY) * 2) {
111                    mTouchReceiver = mModeList;
112                    onTouchEvent(mDown);
113                    return true;
114                }
115                // Intercept left swipe
116                else if (deltaX < -Math.abs(deltaY) * 2) {
117                    mTouchReceiver = mFilmstripLayout;
118                    onTouchEvent(mDown);
119                    return true;
120                }
121            }
122        }
123        return false;
124    }
125
126    @Override
127    public boolean onTouchEvent(MotionEvent ev) {
128        if (mTouchReceiver != null) {
129            mTouchReceiver.setVisibility(VISIBLE);
130            return mTouchReceiver.dispatchTouchEvent(ev);
131        }
132        return false;
133    }
134
135    @Override
136    public void onFinishInflate() {
137        mModeList = (ModeListView) findViewById(R.id.mode_list_layout);
138        mFilmstripLayout = (FilmstripLayout) findViewById(R.id.filmstrip_layout);
139    }
140
141    public void redirectTouchEventsTo(View touchReceiver) {
142        if (touchReceiver == null) {
143            Log.e(TAG, "Cannot redirect touch to a null receiver.");
144            return;
145        }
146        mTouchReceiver = touchReceiver;
147        mRequestToInterceptTouchEvents = true;
148    }
149
150    @Override
151    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
152        if (mNonDecorWindowSizeChangedListener != null) {
153            mNonDecorWindowSizeChangedListener.onNonDecorWindowSizeChanged(
154                    MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec),
155                    CameraUtil.getDisplayRotation(getContext()));
156        }
157        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
158    }
159
160    /**
161     * Sets a listener that gets notified when the layout size is changed. This
162     * size is the size of main activity layout. It is also the size of the window
163     * excluding the system decor such as status bar and nav bar.
164     */
165    public void setNonDecorWindowSizeChangedListener(
166            CameraAppUI.NonDecorWindowSizeChangedListener listener) {
167        mNonDecorWindowSizeChangedListener = listener;
168        if (mNonDecorWindowSizeChangedListener != null) {
169            mNonDecorWindowSizeChangedListener.onNonDecorWindowSizeChanged(
170                    getMeasuredWidth(), getMeasuredHeight(),
171                    CameraUtil.getDisplayRotation(getContext()));
172        }
173    }
174}