1 /*
2  * Copyright (C) 2016 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.googlecode.android_scripting;
18 
19 import android.app.Activity;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.view.GestureDetector;
23 import android.view.MotionEvent;
24 import android.view.View;
25 import android.view.GestureDetector.SimpleOnGestureListener;
26 import android.view.View.OnTouchListener;
27 
28 import com.googlecode.android_scripting.activity.InterpreterManager;
29 import com.googlecode.android_scripting.activity.LogcatViewer;
30 import com.googlecode.android_scripting.activity.ScriptManager;
31 import com.googlecode.android_scripting.activity.TriggerManager;
32 
33 import java.util.ArrayList;
34 import java.util.HashMap;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Map;
38 
39 public class ActivityFlinger {
40 
41   private static final int SWIPE_MIN_DISTANCE = 120;
42   private static final int SWIPE_MAX_OFF_PATH = 100;
43   private static final int SWIPE_THRESHOLD_VELOCITY = 200;
44 
45   private static class ActivityTransition {
46     Class<? extends Activity> mLeft;
47     Class<? extends Activity> mRight;
48 
ActivityTransition(Class<? extends Activity> left, Class<? extends Activity> right)49     public ActivityTransition(Class<? extends Activity> left, Class<? extends Activity> right) {
50       mLeft = left;
51       mRight = right;
52     }
53   }
54 
55   private static Map<Class<?>, ActivityTransition> mActivityTransitions =
56       new HashMap<Class<?>, ActivityTransition>();
57 
ActivityFlinger()58   private ActivityFlinger() {
59     // Utility class.
60   }
61 
62   static {
63     List<Class<? extends Activity>> entries = new ArrayList<Class<? extends Activity>>();
64     entries.add(ScriptManager.class);
65     entries.add(InterpreterManager.class);
66     entries.add(TriggerManager.class);
67     entries.add(LogcatViewer.class);
68 
69     Class<? extends Activity> left = null;
70     Class<? extends Activity> current = null;
71     Class<? extends Activity> right = null;
72 
73     for (Iterator<Class<? extends Activity>> it = entries.iterator(); it.hasNext()
74         || current != null;) {
75       if (current == null) {
76         current = it.next();
77       }
78       if (it.hasNext()) {
79         right = it.next();
80       } else {
81         right = null;
82       }
mActivityTransitions.put(current, new ActivityTransition(left, right))83       mActivityTransitions.put(current, new ActivityTransition(left, right));
84       left = current;
85       current = right;
86     }
87   }
88 
attachView(View view, Context context)89   public static void attachView(View view, Context context) {
90     final LeftRightFlingListener mListener = new LeftRightFlingListener();
91     final GestureDetector mGestureDetector = new GestureDetector(mListener);
92     ActivityTransition transition = mActivityTransitions.get(context.getClass());
93     if (transition.mLeft != null) {
94       mListener.mLeftRunnable = new StartActivityRunnable(context, transition.mLeft);
95     }
96     if (transition.mRight != null) {
97       mListener.mRightRunnable = new StartActivityRunnable(context, transition.mRight);
98     }
99     view.setOnTouchListener(new OnTouchListener() {
100       @Override
101       public boolean onTouch(View v, MotionEvent event) {
102         return mGestureDetector.onTouchEvent(event);
103       }
104     });
105   }
106 
107   private static class StartActivityRunnable implements Runnable {
108 
109     private final Context mContext;
110     private final Class<?> mActivityClass;
111 
StartActivityRunnable(Context context, Class<?> activity)112     private StartActivityRunnable(Context context, Class<?> activity) {
113       mContext = context;
114       mActivityClass = activity;
115     }
116 
117     @Override
run()118     public void run() {
119       Intent intent = new Intent(mContext, mActivityClass);
120       mContext.startActivity(intent);
121     }
122   }
123 
124   private static class LeftRightFlingListener extends SimpleOnGestureListener {
125     Runnable mLeftRunnable;
126     Runnable mRightRunnable;
127 
128     @Override
onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY)129     public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {
130       if (Math.abs(event1.getY() - event2.getY()) > SWIPE_MAX_OFF_PATH) {
131         return false;
132       }
133       if (event1.getX() - event2.getX() > SWIPE_MIN_DISTANCE
134           && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
135         if (mRightRunnable != null) {
136           mRightRunnable.run();
137         }
138       } else if (event2.getX() - event1.getX() > SWIPE_MIN_DISTANCE
139           && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
140         if (mLeftRunnable != null) {
141           mLeftRunnable.run();
142         }
143       } else {
144         return super.onFling(event1, event2, velocityX, velocityY);
145       }
146       return true;
147     }
148   }
149 }
150