mirror of
https://github.com/moparisthebest/k-9
synced 2024-12-25 09:08:49 -05:00
Extracted functionality common to most activities to K9ActivityCommon
This commit is contained in:
parent
bbcc4988ba
commit
8a226972a5
@ -1,230 +1,37 @@
|
||||
package com.fsck.k9.activity;
|
||||
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.GestureDetector.SimpleOnGestureListener;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.TranslateAnimation;
|
||||
|
||||
import com.actionbarsherlock.app.SherlockActivity;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.activity.K9ActivityCommon.K9ActivityMagic;
|
||||
import com.fsck.k9.activity.misc.SwipeGestureDetector.OnSwipeGestureListener;
|
||||
|
||||
|
||||
public class K9Activity extends SherlockActivity {
|
||||
protected static final int BEZEL_SWIPE_THRESHOLD = 20;
|
||||
public class K9Activity extends SherlockActivity implements K9ActivityMagic {
|
||||
|
||||
private K9ActivityCommon mBase;
|
||||
|
||||
protected GestureDetector mGestureDetector;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
setLanguage(this, K9.getK9Language());
|
||||
setTheme(K9.getK9ThemeResourceId());
|
||||
super.onCreate(icicle);
|
||||
setupFormats();
|
||||
}
|
||||
|
||||
public static void setLanguage(Context context, String language) {
|
||||
Locale locale;
|
||||
if (language == null || language.equals("")) {
|
||||
locale = Locale.getDefault();
|
||||
} else if (language.length() == 5 && language.charAt(2) == '_') {
|
||||
// language is in the form: en_US
|
||||
locale = new Locale(language.substring(0, 2), language.substring(3));
|
||||
} else {
|
||||
locale = new Locale(language);
|
||||
}
|
||||
Configuration config = new Configuration();
|
||||
config.locale = locale;
|
||||
context.getResources().updateConfiguration(config,
|
||||
context.getResources().getDisplayMetrics());
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
mBase = K9ActivityCommon.newInstance(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
if (mGestureDetector != null) {
|
||||
mGestureDetector.onTouchEvent(ev);
|
||||
}
|
||||
return super.dispatchTouchEvent(ev);
|
||||
public boolean dispatchTouchEvent(MotionEvent event) {
|
||||
mBase.preDispatchTouchEvent(event);
|
||||
return super.dispatchTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
setupFormats();
|
||||
}
|
||||
|
||||
private java.text.DateFormat mTimeFormat;
|
||||
|
||||
private void setupFormats() {
|
||||
mTimeFormat = android.text.format.DateFormat.getTimeFormat(this); // 12/24 date format
|
||||
}
|
||||
|
||||
public java.text.DateFormat getTimeFormat() {
|
||||
return mTimeFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a swipe from right to left is handled by {@link MyGestureDetector}. See
|
||||
* {@link android.view.GestureDetector.OnGestureListener#onFling(android.view.MotionEvent, android.view.MotionEvent, float, float)}
|
||||
* for more information on the {@link MotionEvent}s being passed.
|
||||
* @param e1 First down motion event that started the fling.
|
||||
* @param e2 The move motion event that triggered the current onFling.
|
||||
*/
|
||||
protected void onSwipeRightToLeft(final MotionEvent e1, final MotionEvent e2) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a swipe from left to right is handled by {@link MyGestureDetector}. See
|
||||
* {@link android.view.GestureDetector.OnGestureListener#onFling(android.view.MotionEvent, android.view.MotionEvent, float, float)}
|
||||
* for more information on the {@link MotionEvent}s being passed.
|
||||
* @param e1 First down motion event that started the fling.
|
||||
* @param e2 The move motion event that triggered the current onFling.
|
||||
*/
|
||||
protected void onSwipeLeftToRight(final MotionEvent e1, final MotionEvent e2) {
|
||||
}
|
||||
|
||||
protected Animation inFromRightAnimation() {
|
||||
return slideAnimation(0.0f, +1.0f);
|
||||
}
|
||||
|
||||
protected Animation outToLeftAnimation() {
|
||||
return slideAnimation(0.0f, -1.0f);
|
||||
}
|
||||
|
||||
private Animation slideAnimation(float right, float left) {
|
||||
|
||||
Animation slide = new TranslateAnimation(
|
||||
Animation.RELATIVE_TO_PARENT, right, Animation.RELATIVE_TO_PARENT, left,
|
||||
Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f
|
||||
);
|
||||
slide.setDuration(125);
|
||||
slide.setFillBefore(true);
|
||||
slide.setInterpolator(new AccelerateInterpolator());
|
||||
return slide;
|
||||
}
|
||||
|
||||
class MyGestureDetector extends SimpleOnGestureListener {
|
||||
private boolean gesturesEnabled = false;
|
||||
|
||||
/**
|
||||
* Creates a new {@link android.view.GestureDetector.OnGestureListener}. Enabled/disabled based upon
|
||||
* {@link com.fsck.k9.K9#gesturesEnabled()}}.
|
||||
*/
|
||||
public MyGestureDetector() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link android.view.GestureDetector.OnGestureListener}.
|
||||
* @param gesturesEnabled Setting to <code>true</code> will enable gesture detection,
|
||||
* regardless of the system-wide gesture setting.
|
||||
*/
|
||||
public MyGestureDetector(final boolean gesturesEnabled) {
|
||||
super();
|
||||
this.gesturesEnabled = gesturesEnabled;
|
||||
}
|
||||
|
||||
private static final float SWIPE_MAX_OFF_PATH_DIP = 250f;
|
||||
private static final float SWIPE_THRESHOLD_VELOCITY_DIP = 325f;
|
||||
|
||||
|
||||
protected MotionEvent mLastOnDownEvent = null;
|
||||
|
||||
@Override
|
||||
public boolean onDown(MotionEvent e) {
|
||||
mLastOnDownEvent = e;
|
||||
return super.onDown(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||
// Do fling-detection if gestures are force-enabled or we have system-wide gestures enabled.
|
||||
if (gesturesEnabled || K9.gesturesEnabled()) {
|
||||
|
||||
// Apparently sometimes e1 is null
|
||||
// Found a workaround here: http://stackoverflow.com/questions/4151385/
|
||||
if (e1 == null) {
|
||||
e1 = mLastOnDownEvent;
|
||||
}
|
||||
|
||||
// Make sure we avoid NullPointerExceptions
|
||||
if (e1 == null || e2 == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate the minimum distance required for this to count as a swipe.
|
||||
// Convert the constant dips to pixels.
|
||||
final float mGestureScale = getResources().getDisplayMetrics().density;
|
||||
final int minVelocity = (int)(SWIPE_THRESHOLD_VELOCITY_DIP * mGestureScale + 0.5f);
|
||||
final int maxOffPath = (int)(SWIPE_MAX_OFF_PATH_DIP * mGestureScale + 0.5f);
|
||||
|
||||
// Calculate how much was actually swiped.
|
||||
final float deltaX = e2.getX() - e1.getX();
|
||||
final float deltaY = e2.getY() - e1.getY();
|
||||
|
||||
// Calculate the minimum distance required for this to be considered a swipe.
|
||||
final int minDistance = (int)Math.abs(deltaY * 4);
|
||||
|
||||
if(K9.DEBUG) {
|
||||
final boolean movedAcross = (Math.abs(deltaX) > Math.abs(deltaY * 4));
|
||||
final boolean steadyHand = (Math.abs(deltaX / deltaY) > 2);
|
||||
Log.d(K9.LOG_TAG, String.format("Old swipe algorithm: movedAcross=%s steadyHand=%s result=%s", movedAcross, steadyHand, movedAcross && steadyHand));
|
||||
Log.d(K9.LOG_TAG, String.format("New swipe algorithm: deltaX=%.2f deltaY=%.2f minDistance=%d velocity=%.2f (min=%d)", deltaX, deltaY, minDistance, velocityX, minVelocity));
|
||||
}
|
||||
|
||||
try {
|
||||
if (Math.abs(deltaY) > maxOffPath) {
|
||||
if(K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "New swipe algorithm: Swipe too far off horizontal path.");
|
||||
return false;
|
||||
}
|
||||
if(Math.abs(velocityX) < minVelocity) {
|
||||
if(K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "New swipe algorithm: Swipe too slow.");
|
||||
return false;
|
||||
}
|
||||
// right to left swipe
|
||||
if (deltaX < (minDistance * -1)) {
|
||||
onSwipeRightToLeft(e1, e2);
|
||||
if(K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "New swipe algorithm: Right to Left swipe OK.");
|
||||
} else if (deltaX > minDistance) {
|
||||
onSwipeLeftToRight(e1, e2);
|
||||
if(K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "New swipe algorithm: Left to Right swipe OK.");
|
||||
} else {
|
||||
if(K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "New swipe algorithm: Swipe did not meet minimum distance requirements.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// successful fling, cancel the 2nd event to prevent any other action from happening
|
||||
// see http://code.google.com/p/android/issues/detail?id=8497
|
||||
e2.setAction(MotionEvent.ACTION_CANCEL);
|
||||
} catch (Exception e) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int getThemeBackgroundColor() {
|
||||
TypedArray array = getTheme().obtainStyledAttributes(new int[] {
|
||||
android.R.attr.colorBackground,
|
||||
});
|
||||
int backgroundColor = array.getColor(0, 0xFF00FF);
|
||||
array.recycle();
|
||||
return backgroundColor;
|
||||
return mBase.getThemeBackgroundColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupGestureDetector(OnSwipeGestureListener listener) {
|
||||
mBase.setupGestureDetector(listener);
|
||||
}
|
||||
}
|
||||
|
115
src/com/fsck/k9/activity/K9ActivityCommon.java
Normal file
115
src/com/fsck/k9/activity/K9ActivityCommon.java
Normal file
@ -0,0 +1,115 @@
|
||||
package com.fsck.k9.activity;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.activity.misc.SwipeGestureDetector;
|
||||
import com.fsck.k9.activity.misc.SwipeGestureDetector.OnSwipeGestureListener;
|
||||
import com.fsck.k9.helper.StringUtils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
|
||||
/**
|
||||
* This class implements functionality common to most activities used in K-9 Mail.
|
||||
*
|
||||
* @see K9Activity
|
||||
* @see K9ListActivity
|
||||
* @see K9FragmentActivity
|
||||
*/
|
||||
public class K9ActivityCommon {
|
||||
/**
|
||||
* Creates a new instance of {@link K9ActivityCommon} bound to the specified activity.
|
||||
*
|
||||
* @param activity
|
||||
* The {@link Activity} the returned {@code K9ActivityCommon} instance will be bound to.
|
||||
*
|
||||
* @return The {@link K9ActivityCommon} instance that will provide the base functionality of the
|
||||
* "K9" activities.
|
||||
*/
|
||||
public static K9ActivityCommon newInstance(Activity activity) {
|
||||
return new K9ActivityCommon(activity);
|
||||
}
|
||||
|
||||
public static void setLanguage(Activity activity, String language) {
|
||||
Locale locale;
|
||||
if (StringUtils.isNullOrEmpty(language)) {
|
||||
locale = Locale.getDefault();
|
||||
} else if (language.length() == 5 && language.charAt(2) == '_') {
|
||||
// language is in the form: en_US
|
||||
locale = new Locale(language.substring(0, 2), language.substring(3));
|
||||
} else {
|
||||
locale = new Locale(language);
|
||||
}
|
||||
|
||||
Configuration config = new Configuration();
|
||||
config.locale = locale;
|
||||
Resources resources = activity.getResources();
|
||||
resources.updateConfiguration(config, resources.getDisplayMetrics());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base activities need to implement this interface.
|
||||
*
|
||||
* <p>The implementing class simply has to call through to the implementation of these methods
|
||||
* in {@link K9ActivityCommon}.</p>
|
||||
*/
|
||||
public interface K9ActivityMagic {
|
||||
int getThemeBackgroundColor();
|
||||
void setupGestureDetector(OnSwipeGestureListener listener);
|
||||
}
|
||||
|
||||
|
||||
private Activity mActivity;
|
||||
private GestureDetector mGestureDetector;
|
||||
|
||||
|
||||
private K9ActivityCommon(Activity activity) {
|
||||
mActivity = activity;
|
||||
setLanguage(mActivity, K9.getK9Language());
|
||||
mActivity.setTheme(K9.getK9ThemeResourceId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this before calling {@code super.dispatchTouchEvent(MotionEvent)}.
|
||||
*/
|
||||
public void preDispatchTouchEvent(MotionEvent event) {
|
||||
if (mGestureDetector != null) {
|
||||
mGestureDetector.onTouchEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the background color of the theme used for this activity.
|
||||
*
|
||||
* @return The background color of the current theme.
|
||||
*/
|
||||
public int getThemeBackgroundColor() {
|
||||
TypedArray array = mActivity.getTheme().obtainStyledAttributes(
|
||||
new int[] { android.R.attr.colorBackground });
|
||||
|
||||
int backgroundColor = array.getColor(0, 0xFF00FF);
|
||||
|
||||
array.recycle();
|
||||
|
||||
return backgroundColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this if you wish to use the swipe gesture detector.
|
||||
*
|
||||
* @param listener
|
||||
* A listener that will be notified if a left to right or right to left swipe has been
|
||||
* detected.
|
||||
*/
|
||||
public void setupGestureDetector(OnSwipeGestureListener listener) {
|
||||
mGestureDetector = new GestureDetector(mActivity,
|
||||
new SwipeGestureDetector(mActivity, listener));
|
||||
}
|
||||
}
|
@ -1,230 +1,37 @@
|
||||
package com.fsck.k9.activity;
|
||||
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.GestureDetector.SimpleOnGestureListener;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.TranslateAnimation;
|
||||
|
||||
import com.actionbarsherlock.app.SherlockFragmentActivity;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.activity.K9ActivityCommon.K9ActivityMagic;
|
||||
import com.fsck.k9.activity.misc.SwipeGestureDetector.OnSwipeGestureListener;
|
||||
|
||||
|
||||
public class K9FragmentActivity extends SherlockFragmentActivity {
|
||||
protected static final int BEZEL_SWIPE_THRESHOLD = 20;
|
||||
public class K9FragmentActivity extends SherlockFragmentActivity implements K9ActivityMagic {
|
||||
|
||||
private K9ActivityCommon mBase;
|
||||
|
||||
protected GestureDetector mGestureDetector;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
setLanguage(this, K9.getK9Language());
|
||||
setTheme(K9.getK9ThemeResourceId());
|
||||
super.onCreate(icicle);
|
||||
setupFormats();
|
||||
}
|
||||
|
||||
public static void setLanguage(Context context, String language) {
|
||||
Locale locale;
|
||||
if (language == null || language.equals("")) {
|
||||
locale = Locale.getDefault();
|
||||
} else if (language.length() == 5 && language.charAt(2) == '_') {
|
||||
// language is in the form: en_US
|
||||
locale = new Locale(language.substring(0, 2), language.substring(3));
|
||||
} else {
|
||||
locale = new Locale(language);
|
||||
}
|
||||
Configuration config = new Configuration();
|
||||
config.locale = locale;
|
||||
context.getResources().updateConfiguration(config,
|
||||
context.getResources().getDisplayMetrics());
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
mBase = K9ActivityCommon.newInstance(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
if (mGestureDetector != null) {
|
||||
mGestureDetector.onTouchEvent(ev);
|
||||
}
|
||||
return super.dispatchTouchEvent(ev);
|
||||
public boolean dispatchTouchEvent(MotionEvent event) {
|
||||
mBase.preDispatchTouchEvent(event);
|
||||
return super.dispatchTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
setupFormats();
|
||||
}
|
||||
|
||||
private java.text.DateFormat mTimeFormat;
|
||||
|
||||
private void setupFormats() {
|
||||
mTimeFormat = android.text.format.DateFormat.getTimeFormat(this); // 12/24 date format
|
||||
}
|
||||
|
||||
public java.text.DateFormat getTimeFormat() {
|
||||
return mTimeFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a swipe from right to left is handled by {@link MyGestureDetector}. See
|
||||
* {@link android.view.GestureDetector.OnGestureListener#onFling(android.view.MotionEvent, android.view.MotionEvent, float, float)}
|
||||
* for more information on the {@link MotionEvent}s being passed.
|
||||
* @param e1 First down motion event that started the fling.
|
||||
* @param e2 The move motion event that triggered the current onFling.
|
||||
*/
|
||||
protected void onSwipeRightToLeft(final MotionEvent e1, final MotionEvent e2) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a swipe from left to right is handled by {@link MyGestureDetector}. See
|
||||
* {@link android.view.GestureDetector.OnGestureListener#onFling(android.view.MotionEvent, android.view.MotionEvent, float, float)}
|
||||
* for more information on the {@link MotionEvent}s being passed.
|
||||
* @param e1 First down motion event that started the fling.
|
||||
* @param e2 The move motion event that triggered the current onFling.
|
||||
*/
|
||||
protected void onSwipeLeftToRight(final MotionEvent e1, final MotionEvent e2) {
|
||||
}
|
||||
|
||||
protected Animation inFromRightAnimation() {
|
||||
return slideAnimation(0.0f, +1.0f);
|
||||
}
|
||||
|
||||
protected Animation outToLeftAnimation() {
|
||||
return slideAnimation(0.0f, -1.0f);
|
||||
}
|
||||
|
||||
private Animation slideAnimation(float right, float left) {
|
||||
|
||||
Animation slide = new TranslateAnimation(
|
||||
Animation.RELATIVE_TO_PARENT, right, Animation.RELATIVE_TO_PARENT, left,
|
||||
Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f
|
||||
);
|
||||
slide.setDuration(125);
|
||||
slide.setFillBefore(true);
|
||||
slide.setInterpolator(new AccelerateInterpolator());
|
||||
return slide;
|
||||
}
|
||||
|
||||
class MyGestureDetector extends SimpleOnGestureListener {
|
||||
private boolean gesturesEnabled = false;
|
||||
|
||||
/**
|
||||
* Creates a new {@link android.view.GestureDetector.OnGestureListener}. Enabled/disabled based upon
|
||||
* {@link com.fsck.k9.K9#gesturesEnabled()}}.
|
||||
*/
|
||||
public MyGestureDetector() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link android.view.GestureDetector.OnGestureListener}.
|
||||
* @param gesturesEnabled Setting to <code>true</code> will enable gesture detection,
|
||||
* regardless of the system-wide gesture setting.
|
||||
*/
|
||||
public MyGestureDetector(final boolean gesturesEnabled) {
|
||||
super();
|
||||
this.gesturesEnabled = gesturesEnabled;
|
||||
}
|
||||
|
||||
private static final float SWIPE_MAX_OFF_PATH_DIP = 250f;
|
||||
private static final float SWIPE_THRESHOLD_VELOCITY_DIP = 325f;
|
||||
|
||||
|
||||
protected MotionEvent mLastOnDownEvent = null;
|
||||
|
||||
@Override
|
||||
public boolean onDown(MotionEvent e) {
|
||||
mLastOnDownEvent = e;
|
||||
return super.onDown(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||
// Do fling-detection if gestures are force-enabled or we have system-wide gestures enabled.
|
||||
if (gesturesEnabled || K9.gesturesEnabled()) {
|
||||
|
||||
// Apparently sometimes e1 is null
|
||||
// Found a workaround here: http://stackoverflow.com/questions/4151385/
|
||||
if (e1 == null) {
|
||||
e1 = mLastOnDownEvent;
|
||||
}
|
||||
|
||||
// Make sure we avoid NullPointerExceptions
|
||||
if (e1 == null || e2 == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate the minimum distance required for this to count as a swipe.
|
||||
// Convert the constant dips to pixels.
|
||||
final float mGestureScale = getResources().getDisplayMetrics().density;
|
||||
final int minVelocity = (int)(SWIPE_THRESHOLD_VELOCITY_DIP * mGestureScale + 0.5f);
|
||||
final int maxOffPath = (int)(SWIPE_MAX_OFF_PATH_DIP * mGestureScale + 0.5f);
|
||||
|
||||
// Calculate how much was actually swiped.
|
||||
final float deltaX = e2.getX() - e1.getX();
|
||||
final float deltaY = e2.getY() - e1.getY();
|
||||
|
||||
// Calculate the minimum distance required for this to be considered a swipe.
|
||||
final int minDistance = (int)Math.abs(deltaY * 4);
|
||||
|
||||
if(K9.DEBUG) {
|
||||
final boolean movedAcross = (Math.abs(deltaX) > Math.abs(deltaY * 4));
|
||||
final boolean steadyHand = (Math.abs(deltaX / deltaY) > 2);
|
||||
Log.d(K9.LOG_TAG, String.format("Old swipe algorithm: movedAcross=%s steadyHand=%s result=%s", movedAcross, steadyHand, movedAcross && steadyHand));
|
||||
Log.d(K9.LOG_TAG, String.format("New swipe algorithm: deltaX=%.2f deltaY=%.2f minDistance=%d velocity=%.2f (min=%d)", deltaX, deltaY, minDistance, velocityX, minVelocity));
|
||||
}
|
||||
|
||||
try {
|
||||
if (Math.abs(deltaY) > maxOffPath) {
|
||||
if(K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "New swipe algorithm: Swipe too far off horizontal path.");
|
||||
return false;
|
||||
}
|
||||
if(Math.abs(velocityX) < minVelocity) {
|
||||
if(K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "New swipe algorithm: Swipe too slow.");
|
||||
return false;
|
||||
}
|
||||
// right to left swipe
|
||||
if (deltaX < (minDistance * -1)) {
|
||||
onSwipeRightToLeft(e1, e2);
|
||||
if(K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "New swipe algorithm: Right to Left swipe OK.");
|
||||
} else if (deltaX > minDistance) {
|
||||
onSwipeLeftToRight(e1, e2);
|
||||
if(K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "New swipe algorithm: Left to Right swipe OK.");
|
||||
} else {
|
||||
if(K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "New swipe algorithm: Swipe did not meet minimum distance requirements.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// successful fling, cancel the 2nd event to prevent any other action from happening
|
||||
// see http://code.google.com/p/android/issues/detail?id=8497
|
||||
e2.setAction(MotionEvent.ACTION_CANCEL);
|
||||
} catch (Exception e) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int getThemeBackgroundColor() {
|
||||
TypedArray array = getTheme().obtainStyledAttributes(new int[] {
|
||||
android.R.attr.colorBackground,
|
||||
});
|
||||
int backgroundColor = array.getColor(0, 0xFF00FF);
|
||||
array.recycle();
|
||||
return backgroundColor;
|
||||
return mBase.getThemeBackgroundColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupGestureDetector(OnSwipeGestureListener listener) {
|
||||
mBase.setupGestureDetector(listener);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.fsck.k9.activity;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.GestureDetector;
|
||||
import java.text.DateFormat;
|
||||
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.AdapterView;
|
||||
@ -10,94 +10,96 @@ import android.os.Bundle;
|
||||
|
||||
import com.actionbarsherlock.app.SherlockListActivity;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.activity.K9ActivityCommon.K9ActivityMagic;
|
||||
import com.fsck.k9.activity.misc.SwipeGestureDetector.OnSwipeGestureListener;
|
||||
import com.fsck.k9.helper.DateFormatter;
|
||||
|
||||
public class K9ListActivity extends SherlockListActivity {
|
||||
protected GestureDetector mGestureDetector;
|
||||
|
||||
public class K9ListActivity extends SherlockListActivity implements K9ActivityMagic {
|
||||
|
||||
private K9ActivityCommon mBase;
|
||||
private DateFormat mDateFormat;
|
||||
private DateFormat mTimeFormat;
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
K9Activity.setLanguage(this, K9.getK9Language());
|
||||
setTheme(K9.getK9ThemeResourceId());
|
||||
super.onCreate(icicle);
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
mBase = K9ActivityCommon.newInstance(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
setupFormats();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent event) {
|
||||
mBase.preDispatchTouchEvent(event);
|
||||
return super.dispatchTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
setupFormats();
|
||||
}
|
||||
|
||||
private java.text.DateFormat mDateFormat;
|
||||
private java.text.DateFormat mTimeFormat;
|
||||
|
||||
private void setupFormats() {
|
||||
mDateFormat = DateFormatter.getDateFormat(this);
|
||||
mTimeFormat = android.text.format.DateFormat.getTimeFormat(this); // 12/24 date format
|
||||
public DateFormat getDateFormat() {
|
||||
return mDateFormat;
|
||||
}
|
||||
|
||||
public java.text.DateFormat getTimeFormat() {
|
||||
public DateFormat getTimeFormat() {
|
||||
return mTimeFormat;
|
||||
}
|
||||
|
||||
public java.text.DateFormat getDateFormat() {
|
||||
return mDateFormat;
|
||||
private void setupFormats() {
|
||||
mTimeFormat = android.text.format.DateFormat.getTimeFormat(this);
|
||||
mDateFormat = DateFormatter.getDateFormat(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getThemeBackgroundColor() {
|
||||
return mBase.getThemeBackgroundColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupGestureDetector(OnSwipeGestureListener listener) {
|
||||
mBase.setupGestureDetector(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
// Shortcuts that work no matter what is selected
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_VOLUME_UP: {
|
||||
final ListView listView = getListView();
|
||||
if (K9.useVolumeKeysForListNavigationEnabled()) {
|
||||
int currentPosition = listView.getSelectedItemPosition();
|
||||
if (currentPosition == AdapterView.INVALID_POSITION || listView.isInTouchMode()) {
|
||||
currentPosition = listView.getFirstVisiblePosition();
|
||||
}
|
||||
if (currentPosition > 0) {
|
||||
listView.setSelection(currentPosition - 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
case KeyEvent.KEYCODE_VOLUME_DOWN: {
|
||||
final ListView listView = getListView();
|
||||
if (K9.useVolumeKeysForListNavigationEnabled()) {
|
||||
int currentPosition = listView.getSelectedItemPosition();
|
||||
if (currentPosition == AdapterView.INVALID_POSITION || listView.isInTouchMode()) {
|
||||
currentPosition = listView.getFirstVisiblePosition();
|
||||
}
|
||||
if (K9.useVolumeKeysForListNavigationEnabled() &&
|
||||
(keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
|
||||
keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
|
||||
|
||||
if (currentPosition < listView.getCount()) {
|
||||
listView.setSelection(currentPosition + 1);
|
||||
}
|
||||
return true;
|
||||
final ListView listView = getListView();
|
||||
|
||||
int currentPosition = listView.getSelectedItemPosition();
|
||||
if (currentPosition == AdapterView.INVALID_POSITION || listView.isInTouchMode()) {
|
||||
currentPosition = listView.getFirstVisiblePosition();
|
||||
}
|
||||
|
||||
if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && currentPosition > 0) {
|
||||
listView.setSelection(currentPosition - 1);
|
||||
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN &&
|
||||
currentPosition < listView.getCount()) {
|
||||
listView.setSelection(currentPosition + 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||
// Swallow these events too to avoid the audible notification of a volume change
|
||||
if (K9.useVolumeKeysForListNavigationEnabled()) {
|
||||
if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
|
||||
if (K9.DEBUG)
|
||||
Log.v(K9.LOG_TAG, "Swallowed key up.");
|
||||
return true;
|
||||
}
|
||||
if (K9.useVolumeKeysForListNavigationEnabled() &&
|
||||
(keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
|
||||
keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
if (mGestureDetector != null) {
|
||||
mGestureDetector.onTouchEvent(ev);
|
||||
}
|
||||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import android.preference.Preference;
|
||||
public class K9PreferenceActivity extends SherlockPreferenceActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
K9Activity.setLanguage(this, K9.getK9Language());
|
||||
K9ActivityCommon.setLanguage(this, K9.getK9Language());
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 6 && Build.VERSION.SDK_INT < 14) {
|
||||
// There's a display bug in all supported Android versions before 4.0 (SDK 14) which
|
||||
@ -88,5 +88,4 @@ public class K9PreferenceActivity extends SherlockPreferenceActivity {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,22 +30,23 @@ import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.*;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.AdapterView.OnItemLongClickListener;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ListView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.actionbarsherlock.app.ActionBar;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuBuilder;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
@ -59,14 +60,12 @@ import com.fsck.k9.K9;
|
||||
import com.fsck.k9.Preferences;
|
||||
import com.fsck.k9.R;
|
||||
import com.fsck.k9.SearchSpecification;
|
||||
import com.fsck.k9.activity.misc.SwipeGestureDetector;
|
||||
import com.fsck.k9.activity.misc.SwipeGestureDetector.OnSwipeGestureListener;
|
||||
import com.fsck.k9.activity.setup.AccountSettings;
|
||||
import com.fsck.k9.activity.setup.FolderSettings;
|
||||
import com.fsck.k9.activity.setup.Prefs;
|
||||
import com.fsck.k9.controller.MessagingController;
|
||||
import com.fsck.k9.controller.MessagingListener;
|
||||
import com.fsck.k9.helper.MenuPopup;
|
||||
import com.fsck.k9.helper.MessageHelper;
|
||||
import com.fsck.k9.helper.Utility;
|
||||
import com.fsck.k9.mail.Flag;
|
||||
@ -724,7 +723,7 @@ public class MessageList extends K9ListActivity implements OnItemClickListener,
|
||||
mListView.setVerticalFadingEdgeEnabled(false);
|
||||
|
||||
// Enable gesture detection for MessageLists
|
||||
mGestureDetector = new GestureDetector(new SwipeGestureDetector(this, this));
|
||||
setupGestureDetector(this);
|
||||
|
||||
// Correcting for screen rotation when in ActionMode
|
||||
mSelectedCount = getSelectionFromCheckboxes().size();
|
||||
|
@ -12,6 +12,8 @@ import com.fsck.k9.Account;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.Preferences;
|
||||
import com.fsck.k9.R;
|
||||
import com.fsck.k9.activity.misc.SwipeGestureDetector;
|
||||
import com.fsck.k9.activity.misc.SwipeGestureDetector.OnSwipeGestureListener;
|
||||
import com.fsck.k9.crypto.PgpData;
|
||||
import com.fsck.k9.fragment.MessageViewFragment;
|
||||
import com.fsck.k9.fragment.MessageViewFragment.MessageViewFragmentListener;
|
||||
@ -28,14 +30,14 @@ import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.util.Log;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
||||
public class MessageView extends K9FragmentActivity implements MessageViewFragmentListener {
|
||||
public class MessageView extends K9FragmentActivity implements MessageViewFragmentListener,
|
||||
OnSwipeGestureListener {
|
||||
|
||||
private static final String EXTRA_MESSAGE_REFERENCE = "com.fsck.k9.MessageView_messageReference";
|
||||
private static final String EXTRA_MESSAGE_REFERENCES = "com.fsck.k9.MessageView_messageReferences";
|
||||
@ -71,15 +73,11 @@ public class MessageView extends K9FragmentActivity implements MessageViewFragme
|
||||
private Menu mMenu;
|
||||
|
||||
/**
|
||||
* Screen width in pixels.
|
||||
*
|
||||
* <p>
|
||||
* Used to detect right-to-left bezel swipes.
|
||||
* </p>
|
||||
*
|
||||
* @see #onSwipeRightToLeft(MotionEvent, MotionEvent)
|
||||
*/
|
||||
private int mScreenWidthInPixels;
|
||||
private int mRightBezelThreshold;
|
||||
|
||||
|
||||
@Override
|
||||
@ -92,10 +90,13 @@ public class MessageView extends K9FragmentActivity implements MessageViewFragme
|
||||
initializeActionBar();
|
||||
setTitle("");
|
||||
|
||||
mScreenWidthInPixels = getResources().getDisplayMetrics().widthPixels;
|
||||
int screenWidth = getResources().getDisplayMetrics().widthPixels;
|
||||
mRightBezelThreshold = screenWidth - SwipeGestureDetector.BEZEL_SWIPE_THRESHOLD;
|
||||
|
||||
// Enable gesture detection for MessageViews
|
||||
mGestureDetector = new GestureDetector(new MyGestureDetector(false));
|
||||
if (K9.gesturesEnabled()) {
|
||||
setupGestureDetector(this);
|
||||
}
|
||||
|
||||
final Intent intent = getIntent();
|
||||
|
||||
@ -409,8 +410,8 @@ public class MessageView extends K9FragmentActivity implements MessageViewFragme
|
||||
* Handle a right-to-left swipe starting at the edge of the screen as "move to next message."
|
||||
*/
|
||||
@Override
|
||||
protected void onSwipeRightToLeft(MotionEvent e1, MotionEvent e2) {
|
||||
if ((int) e1.getRawX() > mScreenWidthInPixels - BEZEL_SWIPE_THRESHOLD) {
|
||||
public void onSwipeRightToLeft(MotionEvent e1, MotionEvent e2) {
|
||||
if ((int) e1.getRawX() > mRightBezelThreshold) {
|
||||
onNext();
|
||||
}
|
||||
}
|
||||
@ -420,8 +421,8 @@ public class MessageView extends K9FragmentActivity implements MessageViewFragme
|
||||
* "move to previous message."
|
||||
*/
|
||||
@Override
|
||||
protected void onSwipeLeftToRight(MotionEvent e1, MotionEvent e2) {
|
||||
if ((int) e1.getRawX() < BEZEL_SWIPE_THRESHOLD) {
|
||||
public void onSwipeLeftToRight(MotionEvent e1, MotionEvent e2) {
|
||||
if ((int) e1.getRawX() < SwipeGestureDetector.BEZEL_SWIPE_THRESHOLD) {
|
||||
onPrevious();
|
||||
}
|
||||
}
|
||||
|
@ -2,18 +2,23 @@ package com.fsck.k9.activity.misc;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.GestureDetector.OnGestureListener;
|
||||
import android.view.GestureDetector.SimpleOnGestureListener;
|
||||
|
||||
|
||||
public class SwipeGestureDetector extends SimpleOnGestureListener {
|
||||
public static final int BEZEL_SWIPE_THRESHOLD = 20;
|
||||
|
||||
private static final float SWIPE_MAX_OFF_PATH_DIP = 250f;
|
||||
private static final float SWIPE_THRESHOLD_VELOCITY_DIP = 325f;
|
||||
|
||||
|
||||
private final OnSwipeGestureListener mListener;
|
||||
private int mMinVelocity;
|
||||
private int mMaxOffPath;
|
||||
private MotionEvent mLastOnDownEvent = null;
|
||||
|
||||
|
||||
public SwipeGestureDetector(Context context, OnSwipeGestureListener listener) {
|
||||
super();
|
||||
|
||||
@ -80,8 +85,35 @@ public class SwipeGestureDetector extends SimpleOnGestureListener {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A listener that will be notified when a right to left or left to right swipe has been
|
||||
* detected.
|
||||
*/
|
||||
public interface OnSwipeGestureListener {
|
||||
/**
|
||||
* Called when a swipe from right to left is handled by {@link MyGestureDetector}.
|
||||
*
|
||||
* <p>See {@link OnGestureListener#onFling(MotionEvent, MotionEvent, float, float)}
|
||||
* for more information on the {@link MotionEvent}s being passed.</p>
|
||||
*
|
||||
* @param e1
|
||||
* First down motion event that started the fling.
|
||||
* @param e2
|
||||
* The move motion event that triggered the current onFling.
|
||||
*/
|
||||
void onSwipeRightToLeft(final MotionEvent e1, final MotionEvent e2);
|
||||
|
||||
/**
|
||||
* Called when a swipe from left to right is handled by {@link MyGestureDetector}.
|
||||
*
|
||||
* <p>See {@link OnGestureListener#onFling(MotionEvent, MotionEvent, float, float)}
|
||||
* for more information on the {@link MotionEvent}s being passed.</p>
|
||||
*
|
||||
* @param e1
|
||||
* First down motion event that started the fling.
|
||||
* @param e2
|
||||
* The move motion event that triggered the current onFling.
|
||||
*/
|
||||
void onSwipeLeftToRight(final MotionEvent e1, final MotionEvent e2);
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ import android.widget.Toast;
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.R;
|
||||
import com.fsck.k9.activity.K9Activity;
|
||||
import com.fsck.k9.activity.K9ActivityCommon.K9ActivityMagic;
|
||||
import com.fsck.k9.controller.MessagingController;
|
||||
import com.fsck.k9.controller.MessagingListener;
|
||||
import com.fsck.k9.crypto.CryptoProvider;
|
||||
@ -159,7 +159,7 @@ public class SingleMessageView extends LinearLayout implements OnClickListener,
|
||||
mHeaderPlaceHolder.removeView(mHeaderContainer);
|
||||
// the HTC version of WebView tries to force the background of the
|
||||
// titlebar, which is really unfair.
|
||||
// mHeaderContainer.setBackgroundColor(((K9Activity)activity).getThemeBackgroundColor());
|
||||
mHeaderContainer.setBackgroundColor(((K9ActivityMagic)activity).getThemeBackgroundColor());
|
||||
|
||||
mTitleBarHeaderContainer = new LinearLayout(activity);
|
||||
mMessageContentView.setEmbeddedTitleBarCompat(mTitleBarHeaderContainer);
|
||||
|
Loading…
Reference in New Issue
Block a user