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