diff --git a/src/com/fsck/k9/activity/K9Activity.java b/src/com/fsck/k9/activity/K9Activity.java index afd9c5bf8..c1b35ce79 100644 --- a/src/com/fsck/k9/activity/K9Activity.java +++ b/src/com/fsck/k9/activity/K9Activity.java @@ -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 true 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); + } } diff --git a/src/com/fsck/k9/activity/K9ActivityCommon.java b/src/com/fsck/k9/activity/K9ActivityCommon.java new file mode 100644 index 000000000..2dd65e9b7 --- /dev/null +++ b/src/com/fsck/k9/activity/K9ActivityCommon.java @@ -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. + * + *

The implementing class simply has to call through to the implementation of these methods + * in {@link K9ActivityCommon}.

+ */ + 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)); + } +} diff --git a/src/com/fsck/k9/activity/K9FragmentActivity.java b/src/com/fsck/k9/activity/K9FragmentActivity.java index b27db1ca6..289765b0c 100644 --- a/src/com/fsck/k9/activity/K9FragmentActivity.java +++ b/src/com/fsck/k9/activity/K9FragmentActivity.java @@ -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 true 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); + } } diff --git a/src/com/fsck/k9/activity/K9ListActivity.java b/src/com/fsck/k9/activity/K9ListActivity.java index 91427e505..9c37a58e6 100644 --- a/src/com/fsck/k9/activity/K9ListActivity.java +++ b/src/com/fsck/k9/activity/K9ListActivity.java @@ -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); - } } diff --git a/src/com/fsck/k9/activity/K9PreferenceActivity.java b/src/com/fsck/k9/activity/K9PreferenceActivity.java index 1b83b68f4..d30cf9d63 100644 --- a/src/com/fsck/k9/activity/K9PreferenceActivity.java +++ b/src/com/fsck/k9/activity/K9PreferenceActivity.java @@ -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; } } - } diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java index ca5d3f261..dee923870 100644 --- a/src/com/fsck/k9/activity/MessageList.java +++ b/src/com/fsck/k9/activity/MessageList.java @@ -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(); diff --git a/src/com/fsck/k9/activity/MessageView.java b/src/com/fsck/k9/activity/MessageView.java index 7be0ddc50..760e37fac 100644 --- a/src/com/fsck/k9/activity/MessageView.java +++ b/src/com/fsck/k9/activity/MessageView.java @@ -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. - * - *

* Used to detect right-to-left bezel swipes. - *

* * @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(); } } diff --git a/src/com/fsck/k9/activity/misc/SwipeGestureDetector.java b/src/com/fsck/k9/activity/misc/SwipeGestureDetector.java index f020e41fc..db77ee5d9 100644 --- a/src/com/fsck/k9/activity/misc/SwipeGestureDetector.java +++ b/src/com/fsck/k9/activity/misc/SwipeGestureDetector.java @@ -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}. + * + *

See {@link OnGestureListener#onFling(MotionEvent, 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. + */ void onSwipeRightToLeft(final MotionEvent e1, final MotionEvent e2); + + /** + * Called when a swipe from left to right is handled by {@link MyGestureDetector}. + * + *

See {@link OnGestureListener#onFling(MotionEvent, 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. + */ void onSwipeLeftToRight(final MotionEvent e1, final MotionEvent e2); } } diff --git a/src/com/fsck/k9/view/SingleMessageView.java b/src/com/fsck/k9/view/SingleMessageView.java index c7ccdff8e..2344782cf 100644 --- a/src/com/fsck/k9/view/SingleMessageView.java +++ b/src/com/fsck/k9/view/SingleMessageView.java @@ -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);