1
0
mirror of https://github.com/moparisthebest/k-9 synced 2024-12-26 01:28:50 -05:00

Extracted functionality common to most activities to K9ActivityCommon

This commit is contained in:
cketti 2012-09-27 06:12:01 +02:00
parent bbcc4988ba
commit 8a226972a5
9 changed files with 261 additions and 499 deletions

View File

@ -1,230 +1,37 @@
package com.fsck.k9.activity; 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.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent; 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.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 { public class K9Activity extends SherlockActivity implements K9ActivityMagic {
protected static final int BEZEL_SWIPE_THRESHOLD = 20;
private K9ActivityCommon mBase;
protected GestureDetector mGestureDetector;
@Override @Override
public void onCreate(Bundle icicle) { public void onCreate(Bundle savedInstanceState) {
setLanguage(this, K9.getK9Language()); mBase = K9ActivityCommon.newInstance(this);
setTheme(K9.getK9ThemeResourceId()); super.onCreate(savedInstanceState);
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());
} }
@Override @Override
public boolean dispatchTouchEvent(MotionEvent ev) { public boolean dispatchTouchEvent(MotionEvent event) {
if (mGestureDetector != null) { mBase.preDispatchTouchEvent(event);
mGestureDetector.onTouchEvent(ev); return super.dispatchTouchEvent(event);
}
return super.dispatchTouchEvent(ev);
} }
@Override @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() { public int getThemeBackgroundColor() {
TypedArray array = getTheme().obtainStyledAttributes(new int[] { return mBase.getThemeBackgroundColor();
android.R.attr.colorBackground,
});
int backgroundColor = array.getColor(0, 0xFF00FF);
array.recycle();
return backgroundColor;
} }
@Override
public void setupGestureDetector(OnSwipeGestureListener listener) {
mBase.setupGestureDetector(listener);
}
} }

View 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));
}
}

View File

@ -1,230 +1,37 @@
package com.fsck.k9.activity; 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.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent; 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.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 { public class K9FragmentActivity extends SherlockFragmentActivity implements K9ActivityMagic {
protected static final int BEZEL_SWIPE_THRESHOLD = 20;
private K9ActivityCommon mBase;
protected GestureDetector mGestureDetector;
@Override @Override
public void onCreate(Bundle icicle) { public void onCreate(Bundle savedInstanceState) {
setLanguage(this, K9.getK9Language()); mBase = K9ActivityCommon.newInstance(this);
setTheme(K9.getK9ThemeResourceId()); super.onCreate(savedInstanceState);
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());
} }
@Override @Override
public boolean dispatchTouchEvent(MotionEvent ev) { public boolean dispatchTouchEvent(MotionEvent event) {
if (mGestureDetector != null) { mBase.preDispatchTouchEvent(event);
mGestureDetector.onTouchEvent(ev); return super.dispatchTouchEvent(event);
}
return super.dispatchTouchEvent(ev);
} }
@Override @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() { public int getThemeBackgroundColor() {
TypedArray array = getTheme().obtainStyledAttributes(new int[] { return mBase.getThemeBackgroundColor();
android.R.attr.colorBackground,
});
int backgroundColor = array.getColor(0, 0xFF00FF);
array.recycle();
return backgroundColor;
} }
@Override
public void setupGestureDetector(OnSwipeGestureListener listener) {
mBase.setupGestureDetector(listener);
}
} }

View File

@ -1,7 +1,7 @@
package com.fsck.k9.activity; package com.fsck.k9.activity;
import android.util.Log; import java.text.DateFormat;
import android.view.GestureDetector;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.widget.AdapterView; import android.widget.AdapterView;
@ -10,94 +10,96 @@ import android.os.Bundle;
import com.actionbarsherlock.app.SherlockListActivity; import com.actionbarsherlock.app.SherlockListActivity;
import com.fsck.k9.K9; 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; 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 @Override
public void onCreate(Bundle icicle) { public void onCreate(Bundle savedInstanceState) {
K9Activity.setLanguage(this, K9.getK9Language()); mBase = K9ActivityCommon.newInstance(this);
setTheme(K9.getK9ThemeResourceId()); super.onCreate(savedInstanceState);
super.onCreate(icicle);
setupFormats(); setupFormats();
} }
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
mBase.preDispatchTouchEvent(event);
return super.dispatchTouchEvent(event);
}
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
setupFormats(); setupFormats();
} }
private java.text.DateFormat mDateFormat; public DateFormat getDateFormat() {
private java.text.DateFormat mTimeFormat; return mDateFormat;
private void setupFormats() {
mDateFormat = DateFormatter.getDateFormat(this);
mTimeFormat = android.text.format.DateFormat.getTimeFormat(this); // 12/24 date format
} }
public java.text.DateFormat getTimeFormat() { public DateFormat getTimeFormat() {
return mTimeFormat; return mTimeFormat;
} }
public java.text.DateFormat getDateFormat() { private void setupFormats() {
return mDateFormat; 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 @Override
public boolean onKeyDown(int keyCode, KeyEvent event) { public boolean onKeyDown(int keyCode, KeyEvent event) {
// Shortcuts that work no matter what is selected // Shortcuts that work no matter what is selected
switch (keyCode) { if (K9.useVolumeKeysForListNavigationEnabled() &&
case KeyEvent.KEYCODE_VOLUME_UP: { (keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
final ListView listView = getListView(); keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
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 (currentPosition < listView.getCount()) { final ListView listView = getListView();
listView.setSelection(currentPosition + 1);
} int currentPosition = listView.getSelectedItemPosition();
return true; 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); return super.onKeyDown(keyCode, event);
} }
@Override @Override
public boolean onKeyUp(int keyCode, KeyEvent event) { public boolean onKeyUp(int keyCode, KeyEvent event) {
// Swallow these events too to avoid the audible notification of a volume change // Swallow these events too to avoid the audible notification of a volume change
if (K9.useVolumeKeysForListNavigationEnabled()) { if (K9.useVolumeKeysForListNavigationEnabled() &&
if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) { (keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
if (K9.DEBUG) keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
Log.v(K9.LOG_TAG, "Swallowed key up."); return true;
return true;
}
} }
return super.onKeyUp(keyCode, event); return super.onKeyUp(keyCode, event);
} }
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (mGestureDetector != null) {
mGestureDetector.onTouchEvent(ev);
}
return super.dispatchTouchEvent(ev);
}
} }

View File

@ -12,7 +12,7 @@ import android.preference.Preference;
public class K9PreferenceActivity extends SherlockPreferenceActivity { public class K9PreferenceActivity extends SherlockPreferenceActivity {
@Override @Override
public void onCreate(Bundle icicle) { 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) { 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 // 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; return false;
} }
} }
} }

View File

@ -30,22 +30,23 @@ import android.util.Log;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.*; import android.view.*;
import android.view.ContextMenu.ContextMenuInfo; 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;
import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.CompoundButton; import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageButton;
import android.widget.ListView; import android.widget.ListView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.internal.view.menu.MenuBuilder;
import com.actionbarsherlock.view.ActionMode; import com.actionbarsherlock.view.ActionMode;
import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuInflater;
@ -59,14 +60,12 @@ import com.fsck.k9.K9;
import com.fsck.k9.Preferences; import com.fsck.k9.Preferences;
import com.fsck.k9.R; import com.fsck.k9.R;
import com.fsck.k9.SearchSpecification; 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.misc.SwipeGestureDetector.OnSwipeGestureListener;
import com.fsck.k9.activity.setup.AccountSettings; import com.fsck.k9.activity.setup.AccountSettings;
import com.fsck.k9.activity.setup.FolderSettings; import com.fsck.k9.activity.setup.FolderSettings;
import com.fsck.k9.activity.setup.Prefs; import com.fsck.k9.activity.setup.Prefs;
import com.fsck.k9.controller.MessagingController; import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.controller.MessagingListener; import com.fsck.k9.controller.MessagingListener;
import com.fsck.k9.helper.MenuPopup;
import com.fsck.k9.helper.MessageHelper; import com.fsck.k9.helper.MessageHelper;
import com.fsck.k9.helper.Utility; import com.fsck.k9.helper.Utility;
import com.fsck.k9.mail.Flag; import com.fsck.k9.mail.Flag;
@ -724,7 +723,7 @@ public class MessageList extends K9ListActivity implements OnItemClickListener,
mListView.setVerticalFadingEdgeEnabled(false); mListView.setVerticalFadingEdgeEnabled(false);
// Enable gesture detection for MessageLists // Enable gesture detection for MessageLists
mGestureDetector = new GestureDetector(new SwipeGestureDetector(this, this)); setupGestureDetector(this);
// Correcting for screen rotation when in ActionMode // Correcting for screen rotation when in ActionMode
mSelectedCount = getSelectionFromCheckboxes().size(); mSelectedCount = getSelectionFromCheckboxes().size();

View File

@ -12,6 +12,8 @@ import com.fsck.k9.Account;
import com.fsck.k9.K9; import com.fsck.k9.K9;
import com.fsck.k9.Preferences; import com.fsck.k9.Preferences;
import com.fsck.k9.R; 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.crypto.PgpData;
import com.fsck.k9.fragment.MessageViewFragment; import com.fsck.k9.fragment.MessageViewFragment;
import com.fsck.k9.fragment.MessageViewFragment.MessageViewFragmentListener; 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.FragmentManager;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
import android.util.Log; import android.util.Log;
import android.view.GestureDetector;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.widget.Toast; 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_REFERENCE = "com.fsck.k9.MessageView_messageReference";
private static final String EXTRA_MESSAGE_REFERENCES = "com.fsck.k9.MessageView_messageReferences"; 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; private Menu mMenu;
/** /**
* Screen width in pixels.
*
* <p>
* Used to detect right-to-left bezel swipes. * Used to detect right-to-left bezel swipes.
* </p>
* *
* @see #onSwipeRightToLeft(MotionEvent, MotionEvent) * @see #onSwipeRightToLeft(MotionEvent, MotionEvent)
*/ */
private int mScreenWidthInPixels; private int mRightBezelThreshold;
@Override @Override
@ -92,10 +90,13 @@ public class MessageView extends K9FragmentActivity implements MessageViewFragme
initializeActionBar(); initializeActionBar();
setTitle(""); setTitle("");
mScreenWidthInPixels = getResources().getDisplayMetrics().widthPixels; int screenWidth = getResources().getDisplayMetrics().widthPixels;
mRightBezelThreshold = screenWidth - SwipeGestureDetector.BEZEL_SWIPE_THRESHOLD;
// Enable gesture detection for MessageViews // Enable gesture detection for MessageViews
mGestureDetector = new GestureDetector(new MyGestureDetector(false)); if (K9.gesturesEnabled()) {
setupGestureDetector(this);
}
final Intent intent = getIntent(); 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." * Handle a right-to-left swipe starting at the edge of the screen as "move to next message."
*/ */
@Override @Override
protected void onSwipeRightToLeft(MotionEvent e1, MotionEvent e2) { public void onSwipeRightToLeft(MotionEvent e1, MotionEvent e2) {
if ((int) e1.getRawX() > mScreenWidthInPixels - BEZEL_SWIPE_THRESHOLD) { if ((int) e1.getRawX() > mRightBezelThreshold) {
onNext(); onNext();
} }
} }
@ -420,8 +421,8 @@ public class MessageView extends K9FragmentActivity implements MessageViewFragme
* "move to previous message." * "move to previous message."
*/ */
@Override @Override
protected void onSwipeLeftToRight(MotionEvent e1, MotionEvent e2) { public void onSwipeLeftToRight(MotionEvent e1, MotionEvent e2) {
if ((int) e1.getRawX() < BEZEL_SWIPE_THRESHOLD) { if ((int) e1.getRawX() < SwipeGestureDetector.BEZEL_SWIPE_THRESHOLD) {
onPrevious(); onPrevious();
} }
} }

View File

@ -2,18 +2,23 @@ package com.fsck.k9.activity.misc;
import android.content.Context; import android.content.Context;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.GestureDetector.OnGestureListener;
import android.view.GestureDetector.SimpleOnGestureListener; import android.view.GestureDetector.SimpleOnGestureListener;
public class SwipeGestureDetector extends 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_MAX_OFF_PATH_DIP = 250f;
private static final float SWIPE_THRESHOLD_VELOCITY_DIP = 325f; private static final float SWIPE_THRESHOLD_VELOCITY_DIP = 325f;
private final OnSwipeGestureListener mListener; private final OnSwipeGestureListener mListener;
private int mMinVelocity; private int mMinVelocity;
private int mMaxOffPath; private int mMaxOffPath;
private MotionEvent mLastOnDownEvent = null; private MotionEvent mLastOnDownEvent = null;
public SwipeGestureDetector(Context context, OnSwipeGestureListener listener) { public SwipeGestureDetector(Context context, OnSwipeGestureListener listener) {
super(); 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 { 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); 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); void onSwipeLeftToRight(final MotionEvent e1, final MotionEvent e2);
} }
} }

View File

@ -32,7 +32,7 @@ import android.widget.Toast;
import com.fsck.k9.Account; import com.fsck.k9.Account;
import com.fsck.k9.K9; import com.fsck.k9.K9;
import com.fsck.k9.R; 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.MessagingController;
import com.fsck.k9.controller.MessagingListener; import com.fsck.k9.controller.MessagingListener;
import com.fsck.k9.crypto.CryptoProvider; import com.fsck.k9.crypto.CryptoProvider;
@ -159,7 +159,7 @@ public class SingleMessageView extends LinearLayout implements OnClickListener,
mHeaderPlaceHolder.removeView(mHeaderContainer); mHeaderPlaceHolder.removeView(mHeaderContainer);
// the HTC version of WebView tries to force the background of the // the HTC version of WebView tries to force the background of the
// titlebar, which is really unfair. // titlebar, which is really unfair.
// mHeaderContainer.setBackgroundColor(((K9Activity)activity).getThemeBackgroundColor()); mHeaderContainer.setBackgroundColor(((K9ActivityMagic)activity).getThemeBackgroundColor());
mTitleBarHeaderContainer = new LinearLayout(activity); mTitleBarHeaderContainer = new LinearLayout(activity);
mMessageContentView.setEmbeddedTitleBarCompat(mTitleBarHeaderContainer); mMessageContentView.setEmbeddedTitleBarCompat(mTitleBarHeaderContainer);