11c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu/*
21c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * Copyright (C) 2013 The Android Open Source Project
31c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu *
41c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * Licensed under the Apache License, Version 2.0 (the "License");
51c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * you may not use this file except in compliance with the License.
61c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * You may obtain a copy of the License at
71c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu *
81c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu *      http://www.apache.org/licenses/LICENSE-2.0
91c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu *
101c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * Unless required by applicable law or agreed to in writing, software
111c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * distributed under the License is distributed on an "AS IS" BASIS,
121c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * See the License for the specific language governing permissions and
141c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu * limitations under the License.
151c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu */
161c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu
171c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liupackage com.android.camera.ui;
181c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu
199eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liuimport android.app.Activity;
201c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liuimport android.content.Context;
219eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liuimport android.content.Intent;
229eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liuimport android.provider.MediaStore;
231c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liuimport android.util.AttributeSet;
241c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liuimport android.view.MotionEvent;
25f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liuimport android.view.View;
269eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liuimport android.view.ViewConfiguration;
271c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liuimport android.widget.FrameLayout;
281c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu
2928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liuimport com.android.camera.app.CameraAppUI;
305596b4c902dcb685928b43678f428746ca5ffd08Angus Kongimport com.android.camera.debug.Log;
31344320c90639f823451ddac42e8f39b74727787cDoris Liuimport com.android.camera.util.CameraUtil;
329eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liuimport com.android.camera.widget.FilmstripLayout;
339eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liuimport com.android.camera2.R;
34772951602f9cfccd097283e3b78d188838c82138Erin Dahlgren
35f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liupublic class MainActivityLayout extends FrameLayout {
361c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu
375596b4c902dcb685928b43678f428746ca5ffd08Angus Kong    private final Log.Tag TAG = new Log.Tag("MainActivityLayout");
389eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu    // Only check for intercepting touch events within first 500ms
399eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu    private static final int SWIPE_TIME_OUT = 500;
409eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu
419eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu    private ModeListView mModeList;
429eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu    private FilmstripLayout mFilmstripLayout;
439eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu    private boolean mCheckToIntercept;
449eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu    private MotionEvent mDown;
459eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu    private final int mSlop;
46f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    private boolean mRequestToInterceptTouchEvents = false;
47f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    private View mTouchReceiver = null;
489eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu    private final boolean mIsCaptureIntent;
4928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu    private CameraAppUI.NonDecorWindowSizeChangedListener mNonDecorWindowSizeChangedListener = null;
509eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu
519eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu    // TODO: This can be removed once we come up with a new design for b/13751653.
529eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu    @Deprecated
539eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu    private boolean mSwipeEnabled = true;
541c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu
551c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu    public MainActivityLayout(Context context, AttributeSet attrs) {
561c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu        super(context, attrs);
579eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu        mSlop = ViewConfiguration.get(context).getScaledTouchSlop();
589eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu
599eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu        Activity activity = (Activity) context;
609eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu        Intent intent = activity.getIntent();
619eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu        String action = intent.getAction();
629eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu        mIsCaptureIntent = (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
639eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu                || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(action)
649eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu                || MediaStore.ACTION_VIDEO_CAPTURE.equals(action));
659eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu    }
669eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu
679eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu    /**
689eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu     * Enables or disables the swipe for modules not supporting the new swipe
699eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu     * logic yet.
709eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu     */
719eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu    @Deprecated
729eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu    public void setSwipeEnabled(boolean enabled) {
739eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu        mSwipeEnabled = enabled;
748793eff1b85bda89047316fed36cdc1161a8b811Sascha Haeberling    }
758793eff1b85bda89047316fed36cdc1161a8b811Sascha Haeberling
761c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu    @Override
771c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu    public boolean onInterceptTouchEvent(MotionEvent ev) {
781c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
799eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu            mCheckToIntercept = true;
801c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu            mDown = MotionEvent.obtain(ev);
81f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            mTouchReceiver = null;
82f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            mRequestToInterceptTouchEvents = false;
831c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu            return false;
84f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        } else if (mRequestToInterceptTouchEvents) {
85f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            mRequestToInterceptTouchEvents = false;
86f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            onTouchEvent(mDown);
87f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            return true;
881c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu        } else if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
891c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu            // Do not intercept touch once child is in zoom mode
909eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu            mCheckToIntercept = false;
911c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu            return false;
929eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu        } else {
939eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu            // TODO: This can be removed once we come up with a new design for b/13751653.
949eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu            if (!mCheckToIntercept) {
959eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu                return false;
969eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu            }
979eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu            if (ev.getEventTime() - ev.getDownTime() > SWIPE_TIME_OUT) {
989eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu                return false;
999eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu            }
1009eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu            if (mIsCaptureIntent || !mSwipeEnabled) {
1019eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu                return false;
1029eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu            }
1039eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu            int deltaX = (int) (ev.getX() - mDown.getX());
1049eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu            int deltaY = (int) (ev.getY() - mDown.getY());
1059eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu            if (ev.getActionMasked() == MotionEvent.ACTION_MOVE
1069eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu                    && Math.abs(deltaX) > mSlop) {
1079eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu                // Intercept right swipe
1089eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu                if (deltaX >= Math.abs(deltaY) * 2) {
1099eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu                    mTouchReceiver = mModeList;
1109eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu                    onTouchEvent(mDown);
1119eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu                    return true;
1129eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu                }
1139eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu                // Intercept left swipe
1149eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu                else if (deltaX < -Math.abs(deltaY) * 2) {
1159eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu                    mTouchReceiver = mFilmstripLayout;
1169eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu                    onTouchEvent(mDown);
1179eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu                    return true;
1189eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu                }
1199eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu            }
1201c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu        }
1211c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu        return false;
1221c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu    }
1231c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu
1241c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu    @Override
1251c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu    public boolean onTouchEvent(MotionEvent ev) {
126f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        if (mTouchReceiver != null) {
127f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            mTouchReceiver.setVisibility(VISIBLE);
128166e36fb6e04d40a1bef0459ee6b96c9c736039bAngus Kong            return mTouchReceiver.dispatchTouchEvent(ev);
129f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        }
130f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        return false;
1311c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu    }
1321c94b7d0fa0143230d04b9f14c2ff93c6886d6ccDoris Liu
1339eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu    @Override
1349eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu    public void onFinishInflate() {
1359eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu        mModeList = (ModeListView) findViewById(R.id.mode_list_layout);
1369eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu        mFilmstripLayout = (FilmstripLayout) findViewById(R.id.filmstrip_layout);
1379eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu    }
1389eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu
139f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    public void redirectTouchEventsTo(View touchReceiver) {
140f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        if (touchReceiver == null) {
141f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            Log.e(TAG, "Cannot redirect touch to a null receiver.");
142f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            return;
143f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        }
144f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        mTouchReceiver = touchReceiver;
145f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        mRequestToInterceptTouchEvents = true;
146f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu    }
14728a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu
14828a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu    @Override
14928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
15028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu        if (mNonDecorWindowSizeChangedListener != null) {
15128a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu            mNonDecorWindowSizeChangedListener.onNonDecorWindowSizeChanged(
152344320c90639f823451ddac42e8f39b74727787cDoris Liu                    MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec),
1538be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohde                    CameraUtil.getDisplayRotation());
15428a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu        }
15528a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
15628a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu    }
15728a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu
15828a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu    /**
15928a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu     * Sets a listener that gets notified when the layout size is changed. This
16028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu     * size is the size of main activity layout. It is also the size of the window
16128a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu     * excluding the system decor such as status bar and nav bar.
16228a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu     */
16328a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu    public void setNonDecorWindowSizeChangedListener(
16428a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu            CameraAppUI.NonDecorWindowSizeChangedListener listener) {
16528a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu        mNonDecorWindowSizeChangedListener = listener;
16628a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu        if (mNonDecorWindowSizeChangedListener != null) {
16728a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu            mNonDecorWindowSizeChangedListener.onNonDecorWindowSizeChanged(
168344320c90639f823451ddac42e8f39b74727787cDoris Liu                    getMeasuredWidth(), getMeasuredHeight(),
1698be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohde                    CameraUtil.getDisplayRotation());
17028a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu        }
17128a2950939614a0c1c83787960ce1a218fb69a5eDoris Liu    }
1729eb517f4c4bcf00fbe435a56f89d3abcaaa4d881Doris Liu}